常见排序解析
本文将着重介绍直接插入排序,直接选择排序,冒泡排序,归并排序与快排排序,以下实现皆为升序。
直接插入排序
特点:稳定,时间复杂度:O(n^2)。
1 | def insertion_sort(a): |
排序过程:第一个数一定有序,从第二个值开始,将第二个值放入一个temp中,与第一个进行比较,大于放到第一个后面,不大于则将第一位向后移,将第二个数插入到第一位,此时前两个数已经排列好,第三位重复上述过程,在前部已排好的序列中找到位置并插入,原来插入位置极之后的值向后移。继续执行上述过程,直至排序完毕。
上述程序经过优化,将需要进行排序的数直接与前一位值比较,小于则换位置,然后继续向前比较,换位,直到本轮排序完毕,将向后移与插入的过程转换为比较换位。
直接选择排序
特点:不稳定,时间复杂度:O(n^2)。
1 | def selection_sort(a): |
排序过程:从第一位开始,与之后位的值进行比较,直到找出最小值,放到第一位,然后从第二位开始比较,直到找出第二小的数放到第二位,重复上述过程,直到排序完成。
冒泡排序
特点:稳定,平均时间复杂度:O(n^2)。
1 | def bubble_sort(a): |
排序过程:从第一个数开始,如果第一个数大于第二个,两者换位,继续向后比较,如果不大于则不换位,用第二位向后一位比较,重复上述比较过程。
上述程序经过优化,已排好顺序的部分将不参与比较。
归并排序
特点:稳定,时间复杂度O(nlog2n)
1 | def merge_sort(a): |
排序过程:采取分治法,将每组都排好序,
快排
特点:不稳定,时间复杂度:O(nlog2n)
1 | def quick_sort(a): |
排序过程:选择一个基值(一般为第一个数),将其放在中间位置,定义两个游标,从左边寻找比基值大的数,从右边找比基值小的数,左右两个游标的值交换,执行此操作直至两个指针相遇。一轮结束后,对基数左右两边的数组继续执行上述操作,直到排序完毕。
快排的每一轮的操作本质上来说就是将大的数放到基值右边,小的数放到基值左边,上述的代码就是通过递归来实现上述思想。
总结
排序方法 | 时间复杂度(平均) | 时间复杂度(最坏) | 时间复杂度(最好) | 空间复杂度 | 稳定性 | 复杂性 |
---|---|---|---|---|---|---|
直接插入排序 | O(n^2) | O(n^2) | O(n) | O(1) | 稳定 | 简单 |
直接选择排序 | O(n^2) | O(n^2) | O(n^2) | O(1) | 不稳定 | 简单 |
堆排序 | O(nlog2n) | O(nlog2n) | O(nlog2n) | O(1) | 不稳定 | 较复杂 |
冒泡排序 | O(n^2) | O(n^2) | O(n) | O(1) | 稳定 | 简单 |
快速排序 | O(nlog2n) | O(n^2) | O(nlog2n) | O(nlog2n) | 不稳定 | 较复杂 |
归并排序 | O(nlog2n) | O(nlog2n) | O(nlog2n) | O(n) | 稳定 | 较复杂 |
基数排序 | O(d(n+r)) | O(d(n+r)) | O(d(n+r)) | O(n+r) | 稳定 | 较复杂 |