# 排序算法 **排序的稳定性** 是指对于相等的元素,排序之后,任然保存2个元素的位置没有变,就是稳定的排序,反之就是不稳定排序。 * 交换排序算法 * 桶排序 ### 交换排序算法 * 冒泡排序 :没轮确定一个最大的数排后面 * 选择排序 :每轮选择最小的数排前面 * 快排 : 选最后一个作为pivot(基数), 将数据分为 左边小于 pivot, 右边大于 pivot; 分治递归, 二叉树的前序遍历思路 * 归并排序 : 将无序的数组,分成2个子数组分别排序,然后再merge ; 分治递归, 二叉树的后续遍历思路 * 插入排序 : * 希尔排序 : * 堆排序 : ### 线性排序算法 * 桶排序 ### 小结 常见的排序算法都是比较排序,比较排序的时间复杂度通常为 O(n^2) 或 O(nlogn) 但是如果带排序的数字有一些特俗性时,我们可以根据这来设计更加优化的排序算法。 # 交换排序算法 排序算法的复杂度由 `比较的次数` 和 `交换的次数` 一起决定。 ### 直接选择排序 1. 从未排序的序列中选择最小的元素,与放在第一个位置的元素交换 2. 依次类推,直到全部排序 在a【i,n】中最小的元素和 a[i]交换位置。空间复杂度O(1),时间复杂度 O(n^2) ![](./selectsort.gif) ### 冒泡排序 1. 相邻的2各元素比较,大的向后移,经过一轮比较,做大的元素排在最后 2. 第二轮,第二大的元素排倒数第二个位置 3. 直到全部排好 这样,即使是排好序的拿冒泡排序排序,比较的时间复杂度O(n^2) ![](./bubblesort.gif) ### 快速排序 时间复杂度 平均复杂度 O(n * logn) , 最坏 O(n^2) 空间复杂度 快速排序是对冒泡排序的改进,划分交换排序。 递归一次,pivot 左边都比它小,右边都比它大。这是递归,分治的思想。 > 快速排序就是个二叉树的前序遍历思路,归并排序就是个二叉树的后序遍历思路 代码框架如下 ``` void quicksort(int *a, int left, int right){ if (left=tmp){ j--; } if (i0; --i) { //交换 heap_swop(&a[0],&a[i]); //调整 heap_adjust(a,i); } } 推排序还可以用来求 top-K 大(小)的问题。 #排序动画演示 接下来,我们看一组排序的动画,你看看能不能猜到他们使用了什么排序算法完成。 ![](./qsort.gif) ![](./mergesort.gif) ![](./heapsort.gif) ![](./selectsort.gif) ![](./bubblesort.gif) ![](./shellsort.gif) 答案是: 快排 |归并排序|堆排序 选择排序|冒泡排序|希尔排序 国外也有人通过舞蹈的方式编排了几种基本的排序算法,非常有趣。[点这里去看看](http://v.youku.com/v_show/id_XMzMyODk4NTQ4.html?from=s1.8-1-1.2) # 线性排序算法 上面的算法都是基于比较的排序,时间复杂度最好也是 NlogN. 而非基于比较的排序,可以突破NlogN的时间下限。当然,非比较的排序,也是需要有一些限定条件的。 ### 桶排序 bucket sort 比如给全校学生做个分数排序,最大分100分。我们使用一个100个空间的辅助数据,以key为分数,value为命中的次数。通过O(n)复杂度就可以完成排序任务。这种排序方式就是桶排序。 也就是分配一个hash[100]的空间,初始化为0,遍历一遍,出现的数字就hash[k]++,这样再次遍历一次,就可以得到n个数的顺序了。