说明:代码使用codeblocks编译,C++实现,个人编写,如有错误,还望指正。
总结
排序方法 | 稳定性 | 平均时间复杂度 | 最优时间复杂度 | 最坏时间复杂度 | 空间复杂度 |
---|---|---|---|---|---|
插入排序 | 稳定 | O($$n^{2}$$) | O($$n$$) | O($$n^{2}$$) | 1 |
冒泡排序 | 稳定 | O($$n^{2}$$) | O($$n^{2}$$) | O($$n^{2}$$) | 1 |
二路归并排序 | 稳定 | O($$nlog$$) | |||
二叉树排序 | 稳定 | O($$nlogn$$) | |||
计数排序 | 稳定 | O($$n+k$$) | |||
桶排序 | 不稳定 | O(n) | |||
选择排序 | 不稳定 | O($$n^{2}$$) | O($$n^{2}$$) | O($$n^{2}$$) | 1 |
堆排序 | 不稳定 | O($$nlogn$$) | O($$nlogn$$) | O($$nlogn$$) | 1 |
希尔排序 | 不稳定 | O($$nlogn$$) | |||
基数排序 | 不稳定 | O($$n+k$$) | |||
快速排序 | 不稳定 | O($$nlogn$$) | O($$nlogn$$) | O($$n^{2}$$) | O($$nlogn$$) |
插入排序
插入排序把序列分为两个部分,一部分有序,一部分无序。每一次循环都把无序的第一个元素插入到有序的序列中。
以序列 {4,2,1,3,5}为例。
当一个序列中只有一个元素的时候,我们认为这个序列有序。所以最开始的时候,有序和无序序列如下:
{4|, 2,1,3,5}
接下来取无序中的第一个元素,和有序元素中的最后一个元素,也就是最大的元素比较,如果大于,则不需要移动,去下一个无序元素即可,如果小于,则一直交换到合适的位置。
取2和4比较,小于,则和4交换位置{2,4|,1,3,5},发现到达有序的第一个位置,则停止。
然后取1,和4比较,小于则交换{2,1,4|,3,5},继续和2比较交换{1,2,4|,3,5}至此1的位置也找到了。
接下来元素3,需要和4比较交换{1,2,3,4|,5},继续和2比较不交换,结束。
元素5 和4比较不交换,结束。
整个过程可以在原序列上直接操作,只需要一个临时的变量用于交换。所以空间复杂度认为是O(1);
时间上,如果本来是有序的队列,每个元素只需要和自己前一位的元素比较一次就可以完成排序,这个是最优时间复杂度:O(n),相反,如果这个一个倒序的序列,第n元素都需要和n-1个元素比较,这个时候是最坏时间复杂度:O(n2)。平均时间复杂度是O(n2);
插入排序是稳定的。
1 | void insert_sort(int array[],int len) |
冒泡排序
冒泡排序总是比较和交换相邻的两个元素。再一次循环中,获得到一个最大的值,把他交换到序列的最后,然后再剩下的序列中同样找到一个最大的数。
以序列 {4,2,1,3,5}为例。
寻找最大的数字,比较交换,放到最后:4和2比较交换。
{2, 4,1,3,5}
4和1比较交换:{2, 1,4,3,5}
4和3比较交换:{2, 1,3,4,5}
4和5比较不交换{2, 1,3,4,5},这一轮循环下来,得到了最大的值5:{2, 1,3,4,|5}
第二轮以同样的方式:2和1比较交换,2和3比较不交换,3和4比较不交换,得到{1, 2,3,|4,5}
在经过两轮的比较就完成了排序。
整个过程可以在原序列上直接操作,只需要一个临时的变量用于交换。所以空间复杂度认为是O(1);
时间上,不管序列是否有序,我们都需要进行比较,一共需要比较(n-1)轮,每轮比较的次数是n的线性表达式。我们认为最优。最坏。平均的时间复杂度都是O(n2)。
冒泡排序是稳定的。
1 | void insert_sort(int array[],int len) |
选择排序
1 | void insert_sort(int array[],int len) |
快速排序
快速排序采用分治法,把一个串,按照一个基准值分为左右两部分,将以同样的方式排序左右两部分,每一次调用的结果固定了基准值的最终位置。:在下面的代码中,基准值选择串尾的数,基准值左面都比它小,右面都比它大
1 | int Partition(int array[],int len,int start,int end) |
堆排序
1、建最大堆。
2、把堆顶元素放在末尾。
3、把这个堆的最后一个元素删除,重新调整这个堆。
4、重复2、3;
1 | void max_heap_adjust(int array[],int len,int i) |