七大排序算法详解

这篇具有很好参考价值的文章主要介绍了七大排序算法详解。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

1.概念

1.排序的稳定性

常见的稳定的排序有三种:直接插入排序,冒泡排序,归并排序

对于一组数据元素排列,使用某种排序算法对它进行排序,若相同数据之间的前后位置排序后和未排序之前是相同的,我们就成这种排序算法具有稳定性

单看单个属性的稳定性并无意义,稳定性主要体现在对具有多个属性的对象进行排序时才有意义
假设一个订单对象有两个属性,分别是下单时间与下单金额:
此时我们有一个需求,就是按照订单金额从高到低排序,若金额相同,则按照下单的先后时间排序

  • 方法一:就是先按照订单金额大小排序,然后把金额相同的订单再次按照时间排序,但是这样就需要进行多次排序
  • 方法二:如果我们先把订单按照下单时间的先后排好序,然后再按照订单金额排序,此时如果我们使用的排序是稳定性的,那么它排序后同样是按照下单顺序先后排列的,此时我们就只需要两次排序

所以排序的稳定性也是非常重要

2.排序分类

1.外部排序(不牵扯元素大小比较)

外部排序主要有,桶排序,计数排序,基数排序,时间复杂度近乎O(n)
这三种排序的集合元素非常大,内存放不下,需要使用外部存储器来存储排序,并且对数据的要求非常严格

2.内部排序(基于比较的方式)

七大排序算法详解,Java EE,排序算法,算法,数据结构

1.插入排序

⭐直接插入排序(稳定)
1.核心思路

每次从无序区间中选择第一个元素,插入到有序区间的合适位置(相当于打扑克牌码牌的过程),有序区间+1,无序区间-1,直至整个数组有序
七大排序算法详解,Java EE,排序算法,算法,数据结构
⭐⭐⭐直接插入排序在近乎有序的集合性能上非常好(是因为近乎有序的集合,不需要频繁的去交换),常常作为其他高阶排序的优化手段

2.详细代码
    /**
     * 直接插入排序
     * @param nums
     */
    public static void insertSort(int[] nums) {
        // 有序区间[0,i)
        // 无序区间[i,n)
        for (int i = 1; i < nums.length; i++) {
            for (int j = i; j-1 >= 0; j--) {
                // 若当前值比前一个位置值还小,交换位置
                if (nums[j] < nums[j-1]) {
                    swap(nums, j , j-1);
                }
            }
        }
    }
⭐希尔排序

希尔排序是对插入排序的优化,因为插入排序在近乎有序的数组上性能很好,希尔排序正是利用了这一点

1.核心思路

希尔排序不断地将原数组分为若干个子数组,先将子数组内部调整为有序,不断变大分组的长度,当分组长度为1时(一个元素天然有序),此时进行一次插入排序即可

七大排序算法详解,Java EE,排序算法,算法,数据结构

2.详细代码
   // 希尔排序
    public static void shellSort(int[] arr) {
        int gap = arr.length >> 1;
        while (gap > 1) {
            // 先按照gap分组,组内使用插入排序
            insertionSortByGap(arr,gap);
            gap = gap >> 1;
        }
        // 当gap == 1时,整个数组接近于有序,此时来一个插入排序
        insertionSortByGap(arr,1);
    }

    // 按照gap分组,组内的插入排序
    private static void insertionSortByGap(int[] arr, int gap) {
    	// i初始化为0也可以,更容易理解
        for (int i = gap; i < arr.length; i++) {
            for (int j = i; j - gap >= 0 && arr[j] < arr[j - gap] ; j -= gap) {
                swap(arr,j,j - gap);
            }
        }
    }

2.选择排序

⭐直接选择排序(不稳定)
1.核心思路

每次在无序区间选择最小值与无序区间第一个位置元素交换,有序区间+1,无序区间-1,直至整个数组有序
七大排序算法详解,Java EE,排序算法,算法,数据结构

2.详细代码
    /**
     * 直接选择排序
     * @param nums
     */
    public static void selectionSort(int[] nums) {
        // 起始状态:有序区间[0,i)
        // 无需区间[i,n)
        for (int i = 0; i < nums.length - 1; i++) {
            // 指向当前无需区间最小值的下标
            int minIndex = i;
            for (int j = i+1; j < nums.length; j++) {
                // 若当前值比最小值还小
                if (nums[j] < nums[minIndex]) {
                    // 更新最小值下标
                    minIndex = j;
                }
            }
            // 此时minIndex指向无需区间的最小值,将其加载有序区间的后面,有序区间+1,无序区间-1
            swap(nums, i, minIndex);
        }
    }
⭐堆排序

堆排详情博客:
原地堆排序

3.交换排序

⭐冒泡排序(稳定)
1.核心思路

每次遍历将无序数组的最大元素交换至末尾,无序数组-1,有序数组+1,直至整个数组有序

2.详细代码
    // 无序区间[0...i]
    // 有序区间[]
    public static void bubbleSort(int[] arr) {
        // 外层循环表示要进行元素操作的趟数
        for (int i = 0; i < arr.length - 1; i++) {
            boolean isSwaped = false;
            for (int j = 0; j < arr.length - i - 1; j++) {
                if (arr[j] > arr[j + 1]) {
                    isSwaped = true;
                    swap(arr,j,j + 1);
                }
            }
            if (!isSwaped) {
                break;
            }
        }
    }
⭐快速排序(不稳定)
1.核心思路

每次从无序数组中选取一个元素作为分区点(pivot),将原集合中所有<pivot的元素都放在分区点的左侧,将所有>pivot的元素都放在分区点的右侧,这样分区点最终位置就确定了,继续在左半区间和右半区间重复此过程即可
七大排序算法详解,Java EE,排序算法,算法,数据结构

快速排序和直接选择排序不同的是在快排选择的过程中在不断地调整元素的顺序,在这个过程中原数组已经不断有序了

2.详细代码
    /**
     * 快速排序(挖坑法)
     */
    public static void quitSort(int[] nums) {
        quitSortInternal(nums, 0, nums.length-1);
    }

    private static void quitSortInternal(int[] nums, int l, int r) {
        if (l >= r) {
            return;
        }
        // 分区之后,返回已经放好位置的元素下标
        int p = quitSortByHole(nums, l, r);
        // 将放好位置元素的左侧丢进去排序
        quitSortInternal(nums, l, p - 1);
        // 在将放好位置元素的右侧丢进去排序
        quitSortInternal(nums, p + 1, r);
        // 此时数组就整体有序了
    }
        /**
     * 使用非递归的方式
     * @param nums
     * @param l
     * @param r
     */
    private static void quitSortInternal1(int[] nums, int l, int r) {
        Deque<Integer> stack = new ArrayDeque<>();
        stack.push(r);
        stack.push(l);
        while (!stack.isEmpty()) {
            // 获取左右区间
            int i = stack.pop();
            int j = stack.pop();
            if (i >= j) {
                continue;
            }
            // 调用获得一个位置的结果
            int p = quitSortByHole(nums, i, j);
            // 将左边压入栈中
            stack.push(p-1);
            stack.push(i);
            // 右边压入栈中
            stack.push(j);
            stack.push(p+1);
        }

    }

    private static int quitSortByHole(int[] nums, int l, int r) {
        // 分区数字
        int pivot = nums[l];
        int i = l;
        int j = r;
        while (i < j) {
            while (i < j && nums[j] >= pivot) {
                j--;
            }
            // 走到这说明nums[j] < pivot
            nums[i] = nums[j];
            while (i < j && nums[i] <= pivot) {
                i++;
            }
            // 走到这说明nums[i] > pivot
            nums[j] = nums[i];
        }
        // 出循环说明i==j
        // 将pivot写回i
        nums[i] = pivot;
        // 返回分区点最终位置
        return i;
    }

4.归并排序

⭐归并排序(稳定,时间复杂度O(nlogn),空间复杂度O(n))

对原始数据不敏感

1.核心思路

1. 先不断地将原数组一分为二,直至子数组长度为1
2. 不断地将两个相邻的有序子数组合并成一个更大的有序子数组,直至合并后的数组与原数组长度相同,此时排序完成
七大排序算法详解,Java EE,排序算法,算法,数据结构
核心操作:合并两个子数组merge(nums, l, mid, r)
int i=l代表左边数组走到的下标,
int j=mid+1代表右边数组走到的下标,
k代表当前原数组合并到哪个位置

2.归并排序应用

七大排序算法详解,Java EE,排序算法,算法,数据结构文章来源地址https://www.toymoban.com/news/detail-670132.html

3.详细代码
    /**
     * 归并排序
     */
    public static void mergeSort(int[] nums) {
        mergeSortInternal(nums, 0, nums.length-1);
    }

    /**
     * 在nums的l-r内进行归并排序
     * @param nums
     * @param l
     * @param r
     */
    private static void mergeSortInternal(int[] nums, int l, int r) {
        if (l >= r) {
            return;
        }
        int mid = l + ((r - l) >> 1);;
        // 将左边和右边丢到merge
        mergeSortInternal(nums, l, mid);
        mergeSortInternal(nums, mid+1, r);
        // 此时说明左右两个数组都已经排好序
        merge(nums, l, mid, r);
    }

    private static void merge(int[] nums, int l, int mid, int r) {
        // 创建一个大小与r-l+1一样大的数组
        int[] aux = new int[r - l + 1];
        System.arraycopy(nums, l, aux, 0, r - l + 1);
        int i = l;
        int j = mid+1;
        // i代表左边数组走到的下标,j代表右边数组走到的下标,k代表当前原数组合并到哪个位置
        for (int k = l; k <= r; k++) {
            if (i > mid) {
                // 说明左边的数组已经走完,把右边的全部写回原数组即可
                nums[k] = aux[j-l];
                j++;
            } else if (j > r) {
                // 说明右边的数组已经走完,把左边的全部写回原数组即可
                nums[k] = aux[i-l];
                i++;
            } else if (aux[i-l] <= aux[j-l]) {
                // 说明左边的数字小,把左边数组内的数字写回原数组
                nums[k] = aux[i-l];
                i++;
            } else {
                // 说明右边的数字小,把右边数组内的数字写回原数组
                nums[k] = aux[j-l];
                j++;
            }
        }
    }

到了这里,关于七大排序算法详解的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • 数据结构中的七大排序(Java实现)

    目录 一、直接插入排序 二、希尔排序 三、直接选择排序 四、堆排序 五、冒泡排序 六、快速排序 七、归并排序               定义i下标之前的元素全部已经有序 ,遍历一遍要排序的数组,把i下标前的元素全部进行排序,当遍历玩这个数组后,就已经排好序了。        

    2024年02月08日
    浏览(52)
  • 数据结构——七大排序[源码+动图+性能测试]

    本章代码gitee仓库:排序 我们日常打扑克牌,摸牌,让后将牌按顺序插入好,这其实就是插入排序的过程,打小插入排序的思想就植入我们的脑海 第一张牌不用管,直接拿在手里,之后的牌按照大小再一个一个插入即可 直接插入排序特性: 越接近有序,效率越高(不用那么多

    2024年02月09日
    浏览(49)
  • 【排序算法】数据结构排序详解

    前言: 今天我们将讲解我们数据结构初阶的最后一部分知识的学习,也是最为“炸裂”的知识---------排序算法的讲解!!!! 排序 :所谓排序,就是使一串记录,按照其中的某个或某些的大小,递增或递减的排列起来的操作。 稳定性 :假定在待排序的记录序列中,

    2023年04月08日
    浏览(50)
  • 【数据结构常见七大排序(一)】—插入排序篇【直接插入排序】And【希尔排序】

    目录 1.排序的概念及其运用 1.1排序的概念 1.2排序运用 1.3常见的七大排序 2.直接插入排序 2.1基本思想 2.2直接插入排序 2.3动图助解 2.4直接插入排序源码 2.5直接插入排序的特性总结 3.希尔排序( 缩小增量排序 ) 3.1希尔排序概念及思想 3.2希尔排序图解 3.3希尔排序源码 3.4希尔排序

    2024年02月13日
    浏览(53)
  • 【数据结构常见七大排序(二)】—选择排序篇【直接选择排序】And【堆排序】

    目录 前言 1.直接选择排序 1.1基本思想 1.2直接选择排序实现过程 1.3动图助解 1.4直接选择排序源码 2.堆排序 2.1堆排序的概念 2.2堆排序源码  选择排序有两种常见的【直接选择排序】、【堆排序】 每一次从待排序的数据元素中选出最小(或最大)的一个元素,存放在序列的起

    2024年02月16日
    浏览(56)
  • 【数据结构常见七大排序(三)上】—交换排序篇【冒泡排序】And【快速排序】

    目录 前言 1.冒泡排序 1.1冒泡排序动图 1.2冒泡排序源代码 1.3冒泡排序的特性总结 2.快速排序👑 2.1hoare版本实现思想 排序前 排序中 排序后 2.2hoare版本快排源代码 2.3分析先走 情况1🥇 情况2🥈 交换类排序两个常见的排序算法【冒泡排序】、【快速排序】 交换排序基本思想:

    2024年02月16日
    浏览(69)
  • 数据结构:手撕图解七大排序(含动图演示)

    插入排序分为直接插入排序和希尔排序,其中希尔排序是很值得学习的算法 希尔排序的基础是直接插入排序,先学习直接插入排序 直接插入排序类似于打扑克牌前的整牌的过程,假设我们现在有2 4 5 3四张牌,那么应该怎么整牌? 方法很简单,把3插到2和4中间,这样就完成了

    2024年02月15日
    浏览(51)
  • 【数据结构与算法】归并排序详解:归并排序算法,归并排序非递归实现

    归并排序是一种经典的排序算法,它使用了分治法的思想。下面是归并排序的算法思想: 递归地将数组划分成较小的子数组,直到每个子数组的长度为1或者0。 将相邻的子数组合并,形成更大的已排序的数组,直到最终得到一个完全排序的数组。 归并排序的过程可以分为三

    2024年01月22日
    浏览(70)
  • 算法 数据结构 递归插入排序 java插入排序 递归求解插入排序算法 如何用递归写插入排序 插入排序动图 插入排序优化 数据结构(十)

    1. 插入排序(insertion-sort):                                           是一种简单直观的排序算法。它的工作原理是通过构建有序序列,对于未排序数据,在已排序序列中从后向前扫描,找到相应位置并插入     算法稳定性:                  

    2024年02月09日
    浏览(56)
  • 【算法与数据结构】Java实现查找与排序

    也叫做折半查找,属于有序查找算法。 前提条件 :数组数据必须有序,从小到大,或者从大到小都是可以的。 如果是无序的,也可以先进行排序。 但是排序之后,会改变原有数据的顺序,查找出来元素位置跟原来的元素可能是不一样的,所以排序之后再查找只能判断当前数

    2024年01月19日
    浏览(51)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包