【算法】排序

  • ~2.19K 字
  1. 1. 排序
    1. 1.1. 直接插入排序
    2. 1.2. 折半插入排序
    3. 1.3. 希尔排序
    4. 1.4. 冒泡排序
    5. 1.5. 快速排序
    6. 1.6. 简单选择排序
    7. 1.7. 堆排序
    8. 1.8. 归并排序
      1. 1.8.1. 非递归
      2. 1.8.2. 递归
    9. 1.9. 基数排序

排序

直接插入排序

即将每个元素一次插入到有序的部分

一开始将第一个数作为有序区

直接插入排序即按顺序对每个元素与有序区的最后一个元素比较,若比其小(默认升序),则将该元素存入temp,让temp和有序区的各个元素比较,决定插入位置,插入后有序区扩充

我们采取倒着比较,可以实现同时比较与移动

  • 时间复杂度:(最好), (最坏), (平均)

  • 空间复杂度:(辅助空间)

  • 稳定性:稳定排序

折半插入排序

区别:找插入位置的方法改为了折半查找

每次将待插入元素放入temp,让left与right指向有序区首尾,通过二分找到合适的插入位置

  • 时间复杂度:(最好), (最坏), (平均)
  • 空间复杂度:(辅助空间)
  • 稳定性:稳定排序

希尔排序

基于插入排序的优势:基本有序与数量较小时的高效率

希尔排序通过增量d来对元素分组,d初始为长度的一半

按增量从下标为0开始,间隔d的元素分成一组,组内进行插入排序,排序完将起始点++,继续按间隔d的元素分成一组,以此类推,这是第一轮

第一轮结束后,将增量减半,继续分组进行插入排序

直到增量取值为1,此时即对整个数组插入排序

  • 时间复杂度:(最好), (最坏), (平均)
  • 空间复杂度:(辅助空间)
  • 稳定性:不稳定排序

冒泡排序

即每轮都从前往后比较相邻的两个,逆序就交换

直到不能移动即实现归位,排好了一个元素

改进:引入flag标记每一轮是否进行交换,若发生交换则改为true,每轮结束后判断是否为false,若为false则表示已经有序

  • 时间复杂度:(最好), (最坏), (平均)
  • 空间复杂度:(辅助空间)
  • 稳定性:稳定排序

快速排序

任取元素作为枢轴,划分成小于枢轴与大于枢轴两个部分,然后递归处理左右,直到空或只剩一个,以取第一个为例

定义一个pivot变量,将枢轴元素存入,设left与right指向数组首位,先让right向左移动,每个元素与枢轴比较,若小则移动到left位置,否则继续右移;然后让left向右移动,与枢轴比较,若大于则移动到right位置,否则继续右移

也可以不用pivot变量,而直接swap

即:

right从右往左找比枢轴小的元素去填left的坑

left从左往右找比枢轴大的元素去填right的坑

当left==right时,第一次划分结束,划分出两个区间,将枢轴填入指向的坑,此时枢轴归位

然后递归的处理每个区间

  • 时间复杂度:(最好) (最坏), (平均)
  • 空间复杂度:(辅助空间 最好), (辅助空间 最差), (辅助空间 平均)
  • 稳定性:不稳定排序

简单选择排序

即每轮在剩下的数里选最小的换到前面

定义一个k变量,保存最小值下标,每轮设为剩下元素中的第一个位置,从下标1开始依次和k中下标变量比较,并更新最小元素下标,搜索一趟后,找到最小值位置,与下标0的元素交换,此时该位置元素归位

  • 时间复杂度:(最好) (最坏), (平均)
  • 空间复杂度:(辅助空间)
  • 稳定性:不稳定排序

堆排序

堆排序是使用堆实现的

  1. 建堆:倒着将每个节点为根的子树调整成堆,可以直接从非叶子节点开始调整

    寻找最后一个非叶子节点,即第号节点(第n号节点是最后一个叶子节点),拿其与其子树比较,判断是否为堆,若不是则交换不符合的父子节点

    交换后,若子树非叶子节点,则需要继续往下比较,防止已有结构被破坏

    (即从最后一个非叶节点开始依次向下调整)

  2. 排序:每次将堆顶元素与最后一个元素做交换,然后向下调整新的堆顶,此时该元素归位,隐去

  • 时间复杂度:(最好) (最坏), (平均)
  • 空间复杂度:(辅助空间)
  • 稳定性:不稳定排序

归并排序

将两个有序数组合并为一个

取两个指针指向两个数组的开头,比较更小的放入新数组并移动指针

其中一个放完后,另一个剩下的元素直接放到最后

非递归

归并排序即每轮堆相邻的子序列两两归并

一开始把每个元素作为单独子序列,此时所有序列均有序,之后开始归并,归并方法按照上文

一轮归并完后再进行归并,直到变成一个序列

递归

从自顶向下思考

首先通过左右端点下标确定中间位置,根据中间位置划分为两个区间,

递归左右区间,通过中间位置划分为两个区间,再递归左右区间

直到两个区间有序,则回溯并执行归并操作

  • 时间复杂度:(最好) (最坏), (平均)
  • 空间复杂度:(辅助空间)
  • 稳定性:稳定排序

基数排序

这是一种非比较排序,进行逐位排序

首先统一各元素位数,不够的加前导零

按照从最高位和从最低位排序,分为LSD(最低位优先)与MSD(最高位优先)

LSD较为简单:

首先将所有数按照个位分配,对于十进制,基数为0-9,造十个桶来存储,把每个数按照个位放到对应桶里

这里的桶采用链式存储,满足先进先出,即队列

然后从小到大遍历每个桶,把元素取出并链起来(next指针指向每个桶的队头)

然后按照十位分配,操作同上,直到整体有序

  • 时间复杂度:,其中d为最大数位数,n为要排的n个数,r为基数
  • 空间复杂度:(辅助空间)
  • 稳定性:稳定排序
赞助喵
非常感谢您的喜欢!
赞助喵