推广 热搜: page  数据  小红  红书  考试  论文  数据分析  关键词  哪些  搜索 

插入排序

   日期:2024-12-25     移动:https://sicmodule.kub2b.com/mobile/quote/12868.html

思想:插入排序就是从第二个数开始(因为第一个数后面已经没有数了,不用进行比较,往后遍历比较,遇到比它大的则继续往后,当遇到比它小的,则将前面的数全部往后挪动,将这个数插入在比它小的前面,然后继续从第三个数开始,再往后比较

动图演示

 代码演示

 

思想:希尔排序是属于插入排序的一种优解,当数组为从大到小排序,而我们需要将这个数组从变成从小到大排序时,插入排序的时间将会达到最大,此时希尔排序则能有效地优化插入排序,我们定义一个gap的数,然后从0开始将间距为gap的数进行插入排序,然后再从0+1开始将间距为gap的数进行插入排序,一直循环gap-1次(也就是从0到gao-1开始的间距为gap的数都进行插入排序,这是第一趟排序,第二趟则将gap减小再次进行排序,第三第四趟也是如此,上述的排序称为“预排序”

那么当gap=1时,数组已经接近有序了,此时再进行一次排序(gap=1时,其实就是将数组的全部元素进行一次插入排序,数组就是有序了。

这是大佬对于希尔排序的解释

图解

那么,怎么选择gap的值呢,有几种方法:gap=[n/2]或者gap=[n/3],那么如何让最后一次的gap等于1呢?gap=[n/2]时,gap最终都会=1,gap=[n/3]时,gap有可能会变成0,所以可以令gap=[n/3 +1 ],这样gap最后总是会等于1

所以,gap可以取 [n/2]或者[n/3 +1],这里我们选用后一种 gap=[n/3+1]

代码

第一种是用两个for循环进行排序,最里面的一层for循环是对间隔为gap的数组进行插入排序,外面一层for循环是从0到gap之间的起始数开始循环,外面的while则是令gap不断减小,直到等于1则停止循环。

 

 第二种则在第一种的情况下优化了一下,只进行了一次for循环,但是外内各有一层while,for循环则控制起始坐标从0到gap之间,里面的while则是让间距为gap之间的数进行插入排序,而这些数最后都会在数组内,所以条件则为当最后一个数的数组越界之后则停止插入排序,最外面的while则同样的对gap进行调整。

 
 

思想:选择排序较为简单粗暴,遍历一边数组,选出最小的,放到第一位,从第二位开始遍历,选出最小的,放到第二位,从第三位开始遍历,选出最小的,放到第三位,以此类推

动图演示

 代码

 
 

堆排序在之前的文章中已经顺带介绍过了,下面有链接可以跳转进去。

插入排序

 图解

 这里提醒一下,它是选择排序的一种。它是通过堆来进行选择数据。需要注意的是排升序要建大堆,排降序建小堆。

假设需要排升序,那么数组则是从小到大的,如果排的是小堆,那么堆顶的元素则为最小的,然后我们需要忽略掉第一个元素,从第二个元素开始作为堆顶重新做堆,那么此时大家的关系有可能都会乱套,那么就需要重新建堆,每排一次都要建一次堆,这不行,很麻烦且复杂且时间复杂度高

假如我们排的是大堆,那么堆顶的元素则为最大的,我们将堆顶的元素与堆尾的元素进行交换,并且忽略掉倒数第一个元素,然后将交换后的堆顶进行向下调整,那么此时堆则不会被破坏,而最后一个数也为最大的,符合升序,然后再将次大的与倒数第二个数进行交换,反复进行,最后就拍完序了,那么降序也是一样,需要建小堆

所以,结论就是排升序要建大堆,排降序建小堆。

代码思路:假设需要升序,那么将乱序数组建堆,建成大堆,然后令堆顶与堆尾交换,然后忽略掉倒数第一个元素,然后对堆顶进行向下调整,第二次第三次以此类推。

建堆需要用到向上调整算法

而向上调整算法与向下调整算法都在上面给出链接,希望读者能结合两处情况进行考虑

思想:相信冒泡排序很多人都会学过,原理就是不断地选取较大的数与后面的数进行比较,遇到较小数则进行交换,当遇到更大的数则选取更大的数,然后继续和后面的数进行比较

动图演示

代码

 

任取待排序元素序列中的某元素作为基准值,按照该排序码将待排序集合分割成两子序列,左子序列中所有元素均小于基准值,右子序列中所有元素均大于基准值,然后最左右子序列重复该过程,直到所有元素都排列在相应位置上为止

而快速排序从出现到现在,有着三种不同的方法

思想:定义左指针left与右指针right,首先将左边第一个数定为key,然后右边开始往前走,遇到比key小的数,则停止,然后左边开始走,遇到比key大的数,则停止,然后将左右两数进行交换,然后右边继续先走,然后再到左边,一直反复,直到left与right相遇,然后令key与right的值进行交换,然后令此时left与right相遇的值与下标重新定义为key,然后此时由key将数组分割成两份,左数组为[0,key-1],而右数组为[key+1,n-1]此时,第一次排序已经完成,然后再对左数组看成一个新的数组重新排序,以此类推,不断地递归,那么停止的标准就是当最开始的begin≥end,也就是数组的开头≥尾的时候就可以停止分割停止排序了

代码

 

 需要注意到的问题

要知道,左指针是找比key大的值,右指针是找比key小的值,而左指针先动,那么右指针是一定要跟着动,如果右指针先动,那么左指针也一定要跟着动,也就是说,左右指针无论谁先动,都一定要动完整个周期(左->右或者右->左

如果左侧先动的话,无法保证相遇时对应的数比key小,那么最后交换key的时候就会产生错误,右侧先动的话,右指针的时候就一定会停在比key小的地方,然后左指针开始移动就一定相遇在比key小的值,这就是为什么一定要右指针先走动

思想:也是定义左指针left与右指针right,key对应的下标为piti,然后将左边第一个元素放到key里面,然后此时左边就有了坑,然后右边开始往前走,遇到比key小的,则与key交换,那么此时右指针的地方则变成新坑,然后左边走,左边遇到比key大的数则交换,然后左边变成新坑,以此类推,当相遇时停止,然后将key放进相遇的坑位,然后分割成两个左右数组,左数组为[0,piti-1],而右数组为[piti+1,n-1],然后就是一样的对左右数组进行重新排序,不断地递归

动图演示

 代码

 
 

思想:定义左边第一个数为key,然后定义前指针cur,与后指针prev=cur+1,首先判断cur指针的值,如果比key小,那么prev往后挪,如果prev等于cur,那么cur往后挪,如果cur的值大于key,那么prev不动,cur往后挪,然后当遇到比key小的值,那么prev的后一位就是比key大的,此时prev往后挪然后将prev的值与cur的值交换即可,一直到最后,cur到达尾部时停止循环,然后将key的值与prev对应的值交换,此时prev的值则为key,prev也将两个数组分割成左右两个数组,然后进行递归

动图演示

代码

 
 

前面三种的key都不约而同地将左边第一个值当成key,假如最左边的数是一个极端值(为数组中最大或者最小的,那么此时将会是最复杂的一种情况

那么此时我们的key可以使用三数取中法确定

三数取中代码

 

 当数组递归到较小区间时可以使用插入排序

上述三种方法都需要用到递归,不断地递归到小的数组且接近有序,此时插入排序的优点就体现出来了

思想:归并排序可以看成一种分治的思想,就是对数组不断地分割,分割成不可再分割的数组,然后再进行排序递归

动图演示

 代码

 
 

思想:计数排序就是将出现过的元素使用相对映射统计一边,然后重新放回数组里,这种方法比较适合范围较集中的数组

动图演示

代码

 

复杂度与稳定性

稳定性是指,排序的过程中,对于同样的值不会改变先后位置,比如说a=3,b=3吗,a的下标为1,b的下标为2,a在b的前面,排完序之后,a的下标仍然比b的下标要小,也就是a始终在b的前面,那么就是稳定的情况,如果改变了先后位置,那么就是不稳定

排序方式最好情况最坏情况平均情况空间复杂度稳定性插入排序O(N)O(N^2)O(N^2)O(1)稳定希尔排序O(N^1.3)O(N^2)O(N*logN)~O(N^2)O(1)不稳定选择排序O(N^2)O(N^2)O(N^2)O(1)不稳定堆排序O(N*logN)O(N*logN)O(N*logN)O(1)不稳定冒泡排序O(N^2)O(N^2)O(N^2)O(1)稳定快速排序O(N*logN)O(N^2)O(N*logN)O(logN~N)不稳定归并排序O(N*logN)O(N*logN)O(N*logN)O(N)稳定计数排序O(max(range,N)O(max(range,N)O(max(range,N)O(range)不稳定
本文地址:https://sicmodule.kub2b.com/quote/12868.html     企库往 https://sicmodule.kub2b.com/ , 查看更多

特别提示:本信息由相关用户自行提供,真实性未证实,仅供参考。请谨慎采用,风险自负。


0相关评论
相关最新动态
推荐最新动态
点击排行
网站首页  |  关于我们  |  联系方式  |  使用协议  |  版权隐私  |  网站地图  |  排名推广  |  广告服务  |  积分换礼  |  网站留言  |  RSS订阅  |  违规举报  |  鄂ICP备2020018471号