排序算法
总体介绍
类别 | 算法名 | 平均时间 | 最好时间 | 最坏时间 | 辅助存储 | 稳定性 |
---|---|---|---|---|---|---|
插入排序 | 直接插入 | 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。
插入排序
很简单,就是遍历到一个元素时,去找前边比自己大的数前边的位置,这位置之后更大的数整体后移,空出来的位置插入该元素。
希尔排序
-
从步长d1=n/2开始两两建立子表,第一次建子表后有两个元素,这两个元素构成的子表构成逻辑上连在一起的一组数,对这两个数执行插入排序(交换位置)。
-
所有子表都遍历结束后,进一步缩小步长,使得d2=d1/2继续建立四个元素的子表(依然位置逻辑上一组,位置不连续),对这四个元素比较并进行插入排序(实际上也是这四个元素交换位置)。
-
然后进一步减小步长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的队列,然后完成排序。
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 阿里最新开源QwQ-32B,效果媲美deepseek-r1满血版,部署成本又又又降低了!
· 单线程的Redis速度为什么快?
· SQL Server 2025 AI相关能力初探
· AI编程工具终极对决:字节Trae VS Cursor,谁才是开发者新宠?
· 展开说说关于C#中ORM框架的用法!