排序算法

总体介绍

类别 算法名 平均时间 最好时间 最坏时间 辅助存储 稳定性
插入排序 直接插入 O(n^2) O(n) O(n^2) O(1) 稳定
插入排序 希尔(shell)排序 O(n^1.3) O(n) O(n^2) O(1) 不稳定
选择排序 直接选择 O(n^2) O(n^2) O(n^2) O(1) 不稳定
选择排序 堆排序 O(nlog2(n)) O(nlog2(n)) O(nlog2(n)) O(1) 不稳定
交换排序 冒泡排序 O(n^2) O(n) O(n^2) O(1) 稳定
交换排序 快速排序 O(nlog2(n)) O(nlog2(n)) O(n^2) O(nlog2(n)) 不稳定
归并排序 归并 O(nlog2(n)) O(nlog2(n)) O(nlog2(n)) O(1) 稳定
基数排序 基数 O(d(r+n)) O(d(rd+n)) O(d(r+n)) O(d(rd+n)) 稳定

口诀:

插冒归,它很稳,插冒归喜欢选冒插,插完就慌(fang)了(指选冒插的平均时间复杂度n^2),快归堆,nlog。

插入排序

很简单,就是遍历到一个元素时,去找前边比自己大的数前边的位置,这位置之后更大的数整体后移,空出来的位置插入该元素。

希尔排序

  1. 从步长d1=n/2开始两两建立子表,第一次建子表后有两个元素,这两个元素构成的子表构成逻辑上连在一起的一组数,对这两个数执行插入排序(交换位置)。

  2. 所有子表都遍历结束后,进一步缩小步长,使得d2=d1/2继续建立四个元素的子表(依然位置逻辑上一组,位置不连续),对这四个元素比较并进行插入排序(实际上也是这四个元素交换位置)。

  3. 然后进一步减小步长d3=d2/2,重复组内元素的插入排序。直至dn = dn-1/2=1,最终肯定会为1的,进行最后一次插入排序。

步长d1=n/2形成子表。

第二趟步长d2=d1/2继续形成子表

第三趟,步长d3=d2/2,当步长最后为1,执行一次原始的插入排序,完成排序。

冒泡排序

遍历每一个元素,让其与n-1个元素两两对比,更小的往前放(冒泡)。

比如:

5 6 4 2 3 1 2 3, 开始从末尾3开始,与2比,不用交换,且2更小,比较的数换成2,2再与1比,不用交换,比较的数再换成1,1与3比,交换(5 6 4 2 1<>3 2 3),继续比较,不断上浮,(5 6 4 1<>2 3 2 3)(5 6 1<>4 2 3 2 3)(5 1<>6 4 2 3 2 3)(1<>5 6 4 2 3 2 3)到此第一个元素完成。

1 5 6 4 2 3 2 3,第一轮从3开始,与2不交换,且换成更小的元素2继续比较,交换(1 5 6 4 2 2<>3 3),然后与2比较,冒泡排序时稳定的,即遇到相同的元素,保持先后关系,故不交换,且缓存前一个2继续上浮,直至完成(1 2<>5 6 4 2 3 3)

其他元素也依次进行,直至完成。

快速排序

选择第一个元素作为中轴元素,进入快排后,中轴元素位置缓存在一个变量中,让指针low指向该位置,high指向最后位置,high开始往前走,直到找到一个元素比中轴元素小的时候暂停,把该元素拷贝至low的位置,此时指向high的位置空缺,然后low向右移动,直至找到个比中轴元素大的元素暂停,把该元素拷贝至high的位置,这时low的位置再度空缺,一轮循环结束;下一次循环,high继续左移,直到一更小元素拷贝至low处,low继续右移,找到个大的拷贝至high处,直至low和high相遇,结束循环,并把中轴元素拷贝回low和high相遇的位置。

这样就形成了左边的都比中轴元素小,右边的都比中轴元素大的局面,然后让0到low - 1、low + 1到n的两组元素继续执行快排,递归调用即可,直至最后拆解到两元素时结束。

low和high相遇时,放入中轴元素,这个位置就是中轴元素在整个数组中排序完成的位置,所以快速排序也用于快速选择算法,用于寻找一个与目标匹配的元素或位置。
C++代码

void quikSort(vector<int>& nums, int i, int j) {
    if (i + 1 > j) return;
    int midNum = nums[i];
    int l = i, r = j;
    while (l < r) {
        while(r > l && nums[r] >= midNum) --r;
        nums[l] = nums[r];
        while (l < r && nums[l] <= midNum) ++l;
        nums[r] = nums[l];
    }
    nums[l] = midNum;
    quikSort(nums, i, l - 1);
    quikSort(nums, l + 1, j);
}

简单直接选择排序

每一次遍历,找到一最小值,与第一个元素交换,然后在剩余n-1个元素内继续找到一个最小的,与第二个元素交换,找最小元素的过程与冒泡很像。

堆排序

将元素建立一个二叉树,并调整好节点位置,使得根节点位置大于左节点、且大于等于右节点,然后把根元素值(最大元素)放如数组最后的位置,让树的末尾节点移动至根节点,继续调整位置使得树满足所有节点满足根节点大于左且大于等于右,再移出根,不断重复该过程直至完成。

归并排序

将两个有序并为一个有序。首先一个元素分成一个组,两两归并,小的在前大的在后,然后递归,进一步分组,此时两个元素一个组,继续两个组归并,比较并合并成一个四个元素的组,且四个元素有序,然后递归合并成八个元素有序组,直至归并成原始元素个数的组。类似于希尔排序的逆过程。

桶排序

将数组内的数放到多个桶里,对各个桶进行进行排序,后合并桶。

基数排序

先看个位,构成一个个位从9到0的队列,再看十位,继续构成一个从9到0的队列,然后完成排序。

posted @ 2023-07-09 23:46  00lab  阅读(27)  评论(0编辑  收藏  举报