吃透排序——直接插入排序、折半插入排序、希尔排序、冒泡排序、快速排序、堆排序、归并排序、基数排序、外部排序(包括详细代码、排序过程图解,特别的注意事项)

吃透排序

更新ing,有错误欢迎提出讨论~

一个网站

有个各类算法可视化的网站很不戳,对算法的执行过程不清晰地可以lou一眼,可以加深对算法的理解
网站地址:https://www.cs.usfca.edu/~galles/visualization/Algorithms.html
以排序算法为例,点开网站找到排序模块
在这里插入图片描述
点击任何一个排序进入,然后就可以愉快看到各种排序的动画
在这里插入图片描述

排序基本概念

思维导图

先上思维导图
在这里插入图片描述

概念理解

什么是算法的稳定性?
文绉绉地说就是排序后,能使关键字相同的元素保持原来顺序中的相对位置不变
如图就是相同的元素如两个3,排序后是否改变前后的相对位置
在这里插入图片描述
那稳定的排序算法一定优于不稳定的排序算法吗?
nonono,如果算法对稳定性压根没要求,或者根本没有相同的元素,那稳定的排序算法也派不上什么用场了

内部和外部排序有什么区别?
内部排序:数据全部在内存
外部排序:数据不全部在内存,有部分在外存
在这里插入图片描述
由于内存小,读写速度快,大约是外存(一般是硬盘)的600倍左右,所有内部排序我们更关注算法本身的优劣,即时间、空间复杂度

由于外存大,读写速度慢(数据取出,拍好序再存回外存都需要进行磁盘的读写),所以外部排序我们更关注磁盘的读写的次数,这个次数越少越好

插入排序

思维导图

在这里插入图片描述

拆解排序过程

插入排序又分为直接插入排序和折半插入排序
第一个元素默认排好,后面元素一个个按序插入
大致步骤就三步:
1.找
2.后移元素
3.插入
在这里插入图片描述

直接插入排序

上代码

  //直接插入排序
    void insertSort(int A[], int n) {
   
        int i, j, temp;//存放待排序元素
        for (i = 1; i < n; i++) {
   //从第二个元素开始插入排序
            if (A[i] < A[i - 1]) {
   
                temp = A[i];
                for (j = i - 1; j >= 0 && A[j] > temp; j--) {
   //元素后移
                    A[j + 1] = A[j];
                }
                A[j + 1] = temp//将待排序元素插入到正确的位置
            }
        }

    }

在这里插入图片描述
其实就是下图,需要j+1到正确的插入位置
在这里插入图片描述
还有一种带哨兵的直接插入排序的写法

什么是哨兵?
就是将数组A[0]的位置放放待排序的元素,然后整个数组的下标从1开始
在这里插入图片描述

上代码

 //    带哨兵的直接插入排序
    void insertSort1(int A[], int n) {
   
        int i, j;
        for (i = 2; i <= n; i++) {
   
            if (A[i] < A[i - 1]) {
   
                A[0] = A[i];
                for (j = i - 1; A[0] < A[j]; j--) {
   //元素后移
                    A[j + 1] = A[j];
                }
                A[j + 1] = A[0];//将待排序元素插入到正确的位置
            }
        }

    }

在这里插入图片描述
上一种写法的temp相当于A[0]
虽然第二种后移元素的判断条件少了,算法效率有所提升,但是提升效果并不明显,所以两种写法二选一,选自己喜欢的

在这里插入图片描述

折半插入排序

在查找正确的插入位置时,有没有更高效的方法,答案是有的,就是利用折半查找。
how?
首先我们需要3个指针:low,mid,high
在这里插入图片描述
待排序元素(就是i指向的元素)与mid指向的元素进行比较
如果A[i]<=A[mid],则high=mid-1(说明元素要插入的位置在左半边)
如果A[i]>A[mid],则low=mid+1(说明元素要插入的位置在右半边)
查找停止条件是什么呢?
第一次比较之后low=mid+1,mid=(low+high)/2
在这里插入图片描述
再下一次55<70,所以high=mid-1,mid=(low+high)/2,变成下图
在这里插入图片描述
最后55<60,high=mid-1,
在这里插入图片描述
所以查找结束的条件是:low>high
okk,可以上代码了

 //    带哨兵的折半插入排序
    void insertSort2(int A[], int n) {
   
        int i, j, low, high, mid;
        for (i = 2; i <= n; i++) {
   
            if (A[i] < A[i - 1]) {
   
                A[0] = A[i];
                low = 1;
                high = i - 1;
                while (low <= high) {
   //折半查找插入位置
                    mid = (low + high) / 2;
                    if (A[mid] > A[0])
                        high = mid - 1;
                    else
                        low = mid + 1;
                }
                for (j = i - 1; j >= low; j--) {
   //元素后移
                    A[j + 1] = A[j];
                }
                A[low] = A[0];//将待排序元素插入到正确的位置
            }
        }

    }

在这里插入图片描述

性能分析

分析时间、空间复杂度
直接插入排序:只需要一个temp或者A[0]一个辅助空间,所以空间的复杂度是O(1)
最好时间复杂度:有序的情况,对于n-1个元素每次都只需要进行一次比较,一次插入,所以最好时间复杂度为O(n)
最坏时间复杂度:逆序的情况

  • 5
    点赞
  • 37
    收藏
    觉得还不错? 一键收藏
  • 2
    评论
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值