各类排序小记

本文详细介绍了直接插入排序、希尔排序、直接选择排序、霍尔快速排序、挖坑快排和前后指针快排,以及归并排序的基本思想、实现和特点,展示了这些排序算法在处理无序数据时的工作原理和适用场景。

目录

​编辑

直接插入排序: 

代码的实现: 

插入排序总结:

希尔排序: 

代码实现: 

预排序: 

gap 的 本质  :

总结: 

希尔排序总结:

直接选择排序:

本质:

优化:

霍尔快速排序:

概念:

代码实现:​编辑

常见问题:

挖坑快排: 

代码实现: 

前后指针快排:

 非递归的快排:

快速排序总结:

归并排序:

基本思想:

思路分析: 

代码实现:​编辑

归并排序总结:


直接插入排序: 

直接插入排序是一种简单的插入排序法,其基本思想是:把待排序的记录按其关键码值的大小逐个插入到一个已经排好序的有序序列中,直到所有的记录插入完为 止,得到一个新的有序序列 。 

  • 简单来说,直接插入排序的前提是需要有一个有序的序列作为基础。

代码的实现: 

 代码的实现本质上也分为内外两层结构。

直接插入排序的内层是用来实现有序序列的排序,而直接插入排序的外层则是用来扩大排序的范围。

 

如图所示,以升序为例,直接插入排序的内层进行寻找插入元素应当插入的位置和对原来排序中的元素进行移位,以此保持插入元素后仍能保持有序。

插入排序的外层是进行引入 插入的元素和扩大有序排序的范围,以此将整个数组变为 一个有序排序。

总结,通过内层将一个无序数组的一部分变成有序排序,通过外层扩大有序排序的范围最后将整个数组变成有序数组。

 

插入排序总结:

  1. 元素集合越接近有序,直接插入排序算法的时间效率越高
  2. 时间复杂度:O(N^2)
  3. 空间复杂度:O(1),它是一种稳定的排序算法
  4. 稳定性:稳定 

希尔排序: 

希尔排序分为预排序和直接插入排序 

  • 预排序是又称接近有序排序的排序,它是将数组内的元素进行分组,每一组内进行直接插入排序。
  • 当每一组都完成排序后,在对整个数组进行直接插入排序。

代码实现: 

预排序: 

预排序的内部和直接排序毫无区别,只是进行将数组分为了几组,在组内进行元素的交换

gap 的 本质  :
  • gap越大,大的值更快调到后面,小的值可以更快的调到前面,越不接近有序gap越小,跳得越慢,但是越接近有序。

总结: 

希尔排序其实就是直接插入排序的升级版本,本质上是将数组中的元素分为多组进行直接排序后,在将整个数组进行直接排序。 

希尔排序总结:

  1. 希尔是对插入排序的优化,这种优化是在无序的序列中才有明显的效果,如果序列接近有序,反而是插入最优。
  2. 时间复杂度:O(N^2)
  3. 空间复杂度:O(1),它是一种稳定的排序算法
  4. 稳定性:稳定 

直接选择排序:

本质:

直接选择排序的本质就是在数组中进行遍历挑选出最大的元素,讲最大的元素放到对应的位置后,再次选出次大的位置,而后又放到对应的位置..........................直到数组成为一个有序序列。

优化:

  • 利用直接选择排序的本质思想,在数组上设立两个遍历数组的下标变量,二者分别找数组中的最小值和最大值,并将其放到应该对应的位置后,在搜索数组中的次大值和次小值..................直到变成一个有序的序列

 

代码实现:

霍尔快速排序:

概念:

快速排序是Hoare于1962年提出的一种二叉树结构的交换排序方法,其基本思想为:

任取待排序元素序列中 的某元素作为基准值,按照该排序码将待排序集合分割成两子序列。

左子序列中所有元素均小于基准值,右 子序列中所有元素均大于基准值,然后最左右子序列重复该过程,直到所有元素都排列在相应位置上为止。 

如上面动画所展示,选择数组最左端的元素作为基准值key ,又在数组的两端设置两个遍历变量进行数组的遍历。

左边的遍历负责查找比key大的数值,右边的遍历负责查找比key小的数值。

当左边遇到了比key大的值停下,等待右边遇到比key小的值,随后二者所指向的元素进行交换,进行多次操作,等到二者相遇后再将处在最左端的key值和相遇位置的元素进行交换。

这样做的目的是使用key值把整个数组进行了分隔,左端的元素都比key小,右端的元素都比key大。

随后便是将分隔的两部分 分别 进行刚才的操作,继续分隔成两部分直到不能再分隔位置。

代码实现:

常见问题

  1. 遇到等于选项时该怎么办?
  2. key值是否会产生变动?
  3. 相遇时,如果条件没有达成可能不会停下。
  4. key易写成局部变量
  5. 第一趟的左端遍历变量的初始下标位置是0还是1?
  6. 遇到相等的元素是否需要停下遍历变量的前进循环?

挖坑快排: 

挖坑法,顾名思义,先把key这个标准值取出,随后之前key所在的位置就成为了坑位,然后和hoare的方法一样进行左右进行遍历

只不过不同的是当右边遇到比key小的数时,会把这个数取出,然后放入坑位所在的位置,随后被取出的那个数的所在位置就是新的坑位了 

 

代码实现: 

当然,挖坑快排和快排一样,需要使用递归,而这里将递归变成了一个外部的调用函数,由挖坑排序返回最后的key值,再外部调用函数中进行分割序列然后递归调用。

前后指针快排:

前后指针的用法略微的巧妙和复杂,先设置两个指针,一个叫cur,一个叫prev

cur指针是查看是否有比key值小的元素,如果有遇见比key小的元素,则prev移动,随后将prev所处位置的元素和cur所处位置的元素交换,交换完成后cur往前移动。
而若cur指针遇见比key值大的元素,则进往前移动。 
最后cur越界后,将prev所处的位置元素和key所处位置的元素进行交换。

代码实现:

 非递归的快排:

众所周知,递归变成非递归,而如果还想具有递归的功能,那么递归的那部分则需要变成循环来实现。 

而再我们的排序中,我们可以采取栈的方式,用入栈、出栈、栈是否为空来完成递归的部分。

我们可以将一段序列的最左端下标和最右端下标丢入栈内,随后赋予临时变量之后出栈,然后利用临时变量组成的区间将序列进行一次的快排

快排结束返回key值,再根据key值继续划分序列,并且再度传入序列的最左端和最右端下标入栈随后立马赋予临时变量然后出栈,这样用入栈和出栈来控制循环。

代码演示:

这串代码的本质是利用了栈的后进先出的原理,以及二叉树后序遍历的原理。

当一个元素入栈后立马出栈,只要序列不是只剩下一个元素,那么它会带入两个元素入栈。

而这入栈,同时也是一种遍历,如下代码所示,通过计算我们得知最开始是数组的前端后入栈,但是是先出栈,出栈后他会带着四个元素入栈,而后端的两个下标则是被压倒了栈底,直到前端不能再入栈了后端才会出栈并且带四个元素入栈
 

快速排序总结:

  1. 初始顺序影响较大,有序时,性能最差

  2. 时间复杂度:O(N*logN)
  3. 空间复杂度:O(logN),递归算法,所递归的深度大概为二叉树的深度,即logn
  4. 稳定性:不稳定

归并排序:

基本思想:

归并排序(MERGE-SORT)是建立在归并操作上的一种有效的排序算法,该算法是采用分治法(Divide and Conquer)的一个非常典型的应用。

将已有序的子序列合并,得到完全有序的序列;即先使 每个子序列内部 有序,再使每个子序列段 间 有序。若将两个有序表合并成一个有序表,称为二路归并。 

思路分析: 

而放到排序中,我们归并的前提是要左右区间有序,而对于一个无序的数组而言左右区间并不是有序的,而要将他变得有序,则可以采取递归的方法。

那么,做法便成为了使用递归的方法,将序列区间连续的对半划分,直到不能划分位置,随后这些被划分的区间再进行排序组成一个有序的序列区间,随后再归并回去。
而再这些被划分区间组成一个有序的序列区间其实也会用到归并的思想
所以本质上就是大区间变成了小区间,数个小区间排列层有序的区间后和另一个相同等级的序列区间再度进行排序,直到变成有序的数组为止。 

代码实现:

代码就是将大区间变小区间,然后小区间的元素进行尾插到新数组内排序,而后新数组的元素拷贝到原来的小区间内

然后小区间在和它同级的小区间进行相同的操作变成一个更大的有序的区间,然后再和其他更大的区间进行相同的操作,最后的最后变成一个有序的数组并拷贝回原来的数组空间 

归并排序总结:

  1. 归并对初始顺序不敏感

  2. 时间复杂度:O(N*logN)
  3. 空间复杂度:O(N),要重新开一个数组拷贝原数组
  4. 稳定性:稳定
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值