======来自N多资料,主要参考http://blog.csdn.net/hguisu/article/details/7776068 以及 http://blog.csdn.net/onedreamer/article/details/6745006 ===============

一、稳定性和时间复杂度总结

[数据结构复习]八大内排序算法总结_排序算法
当n较大,则应采用时间复杂度为O(nlog2n)的排序方法:快速排序、堆排序或归并排序序。
快速排序是目前基于比较的内部排序中被认为是最好的方法,当待排序的关键字是随机分布时,快速排序的平均时间最短;

(1)平方阶(O(n2))排序
  各类简单排序:直接插入、直接选择和冒泡排序;
(2)线性对数阶(O(nlog2n))排序
  快速排序、堆排序和归并排序;
(3)O(n1+§))排序,§是介于0和1之间的常数。
希尔排序
(4)线性阶(O(n))排序
  基数排序,此外还有桶、箱排序。
说明:
当原表有序或基本有序时,直接插入排序和冒泡排序将大大减少比较次数和移动记录的次数,时间复杂度可降至O(n);
而快速排序则相反,当原表基本有序时,将蜕化为冒泡排序,时间复杂度提高为O(n2);
原表是否有序,对简单选择排序、堆排序、归并排序和基数排序的时间复杂度影响不大。

二、排序算法思想总结

下面按照上图的顺序总结它们的排序思想。

1.直接插入

将一个记录插入到已排序好的有序表中,从而得到一个新的,记录数增1的有序表。如果碰见一个和插入元素相等的,那么插入元素把想插入的元素放在相等元素的后面。所以,相等元素的前后顺序没有改变,从原无序序列出去的顺序就是排好序后的顺序,所以插入排序是稳定的。
其他的插入排序有二分插入排序,2-路插入排序。
二分很容易理解:在插入法中添加了二分查找的意思。不赘述。
2-路:它的目的就是想减少数据的移动次数,因此,另外开辟辅助空间。首先开辟一个长度为n的临时数组,将待排序数组的第1个元素放到临时数组的第0位,作为初始化。将该值作为每次排序的参照,大于等于这个参照值就后插,小于参照值就前插。同时定义两个游标first和final分别指向临时数组当前最小值和最大值所在位置。如下图所示:
[数据结构复习]八大内排序算法总结_排序算法_02

2.shell排序

相对直接排序有较大的改进。希尔排序又叫缩小增量排序。先将整个待排序的记录序列分割成为若干子序列分别进行直接插入排序,待整个序列中的记录“基本有序”时,再对全体记录进行依次直接插入排序。
操作方法:
选择一个增量序列t1,t2,…,tk,其中ti递减,tk=1;
按增量序列个数k,对序列进行k 趟排序;
每趟排序,根据对应的增量ti,将待排序列分割成若干长度为m 的子序列,分别对各子表进行直接插入排序。仅增量因子为1 时,整个序列作为一个表来处理,表长度即为整个序列的长度。
我们简单处理增量序列:增量序列d = {n/2 ,n/4, n/8 …..1} n为要排序数的个数
即:先将要排序的一组记录按某个增量d(n/2,n为要排序数的个数)分成若干组子序列,每组中记录的下标相差d.对每组中全部元素进行直接插入排序,然后再用一个较小的增量(d/2)对它进行分组,在每组中再进行直接插入排序。继续不断缩小增量直至为1,最后使用直接插入排序完成排序。
示例:
[数据结构复习]八大内排序算法总结_时间复杂度_03

3.直接选择

在要排序的一组数中,选出最小(或者最大)的一个数与第1个位置的数交换;然后在剩下的数当中再找最小(或者最大)的与第2个位置的数交换,依次类推,直到第n-1个元素(倒数第二个数)和第n个元素(最后一个数)比较为止。
对直接选择排序的一种改进是:
一次循环找出最大以及最小的数,分别放在前面和后面。这样可以减少一半的循环次数。

4.堆排序

堆对应一棵完全二叉树
建堆方法:对初始序列建堆的过程,就是一个反复进行筛选的过程。
1)n 个结点的完全二叉树,则最后一个结点是第[数据结构复习]八大内排序算法总结_总结_04个结点的子树。
2)筛选从第[数据结构复习]八大内排序算法总结_总结_04个结点为根的子树开始,该子树成为堆。(怎么做:从当前结点开始,与它的左右子女中的最大的比,如果比最大的子女大,就交换位置,继续向下比较直到无子女。)
3)之后向前依次对各结点为根的子树进行筛选,使之成为堆,直到根结点。
如图建堆初始过程:无序序列:(49,38,65,97,76,13,27,49)
[数据结构复习]八大内排序算法总结_时间复杂度_06
贴段代码助理解

void HeapAdjust(int H[],int s, int length)   {       int tmp  = H[s];       int child = 2*s+1; //左孩子结点的位置。(child+1 为当前调整结点的右孩子结点的位置)       while (child < length) {           if(child+1 <length && H[child]<H[child+1]) { // 如果右孩子大于左孩子(找到比当前待调整结点大的孩子结点)               ++child ;           }           if(H[s]<H[child]) {  // 如果较大的子结点大于父结点               H[s] = H[child]; // 那么把较大的子结点往上移动,替换它的父结点               s = child;       // 重新设置s ,即待调整的下一个结点的位置               child = 2*s+1;           }  else {            // 如果当前待调整结点大于它的左右孩子,则不需要调整,直接退出                break;           }           H[s] = tmp;         // 当前待调整的结点放到比其大的孩子结点位置上       }       print(H,length);   }     /**   * 初始堆进行调整   * 将H[0..length-1]建成堆   * 调整完之后第一个元素是序列的最小的元素   */   void BuildingHeap(int H[], int length)   {        //最后一个有孩子的节点的位置 i=  (length -1) / 2       for (int i = (length -1) / 2 ; i >= 0; --i)           HeapAdjust(H,i,length);   }  

**输出堆顶元素后,对剩余n-1元素重新建成堆的调整过程。
调整小顶堆的方法:**
1)设有m 个元素的堆,输出堆顶元素后,剩下m-1 个元素。将堆底元素送入堆顶((最后一个元素与堆顶进行交换),堆被破坏,其原因仅是根结点不满足堆的性质。
2)将根结点与左、右子树中较小元素的进行交换。
3)若与左子树交换:如果左子树堆被破坏,即左子树的根结点不满足堆的性质,则重复方法 (2).
4)若与右子树交换,如果右子树堆被破坏,即右子树的根结点不满足堆的性质。则重复方法 (2).
5)继续对不满足堆性质的子树进行上述交换操作,直到叶子结点,堆被建成。
称这个自根结点到叶子结点的调整过程为筛选。如图:
[数据结构复习]八大内排序算法总结_时间复杂度_07
最后的排序算法也是利用上面的HeapAdjust方法:

/**   * 堆排序算法   */   void HeapSort(int H[],int length)   {       //初始堆       BuildingHeap(H, length);       //从最后一个元素开始对序列进行调整       for (int i = length - 1; i > 0; --i)       {           //交换堆顶元素H[0]和堆中最后一个元素           int temp = H[i]; H[i] = H[0]; H[0] = temp;           //每次交换堆顶元素和堆中最后一个元素之后,都要对堆进行调整           HeapAdjust(H,0,i);     }   }   

5.冒泡排序

在要排序的一组数中,对当前还未排好序的范围内的全部数,自上而下对相邻的两个数依次进行比较和调整,让较大的数往下沉,较小的往上冒。即:每当两相邻的数比较后发现它们的排序与排序要求相反时,就将它们互换。
改进:
加个变量记录本次遍历是否有交换。如果没有,停止循环。

6.快速排序

要记得是递归的!
1)选择一个基准元素,通常选择第一个元素或者最后一个元素,
2)通过一趟排序讲待排序的记录分割成独立的两部分,其中一部分记录的元素值均比基准元素值小。另一部分记录的 元素值比基准值大。
3)此时基准元素在其排好序后的正确位置
4)然后分别对这两部分记录用同样的方法继续进行排序,直到整个序列有序。
示例:
(a)一趟排序的过程:
[数据结构复习]八大内排序算法总结_总结_08
(b)排序的全过程
[数据结构复习]八大内排序算法总结_总结_09
快排的一种改进:
只对长度大于k的子序列递归调用快速排序,让原序列基本有序,然后再对整个基本有序序列插入排序算法排序。实践证明,改进后的算法时间复杂度有所降低,且当k取值为 8 左右时,改进算法的性能最佳。

7.归并排序

归并(Merge)排序法是将两个(或两个以上)有序表合并成一个新的有序表,即把待排序序列分为若干个子序列,每个子序列是有序的。然后再把有序子序列合并为整体有序序列。
示例:
[数据结构复习]八大内排序算法总结_数据结构_10
合并方法:
设r[i…n]由两个有序子表r[i…m]和r[m+1…n]组成,两个子表长度分别为n-i +1、n-m。
1.j=m+1;k=i;i=i; //置两个子表的起始下标及辅助数组的起始下标
2.若i>m 或j>n,转⑷ //其中一个子表已合并完,比较选取结束
3.//选取r[i]和r[j]较小的存入辅助数组rf
如果r[i]

8.基数排序

先看下桶排序:

三、具体代码实现

看着上面的思路自己写。
留待日后补充。

1.直接插入