几种常用排序整理

排序分为内排和外排:

三种基本的内排算法:

1.插入排序:

有一个已经有序的数据序列,要求在这个已经排好的数据序列中插入一个数,但要求插入后此数据序列仍然有序,而插入排序的基本操作就是将一个数据插入到已经排好序的有序数据中,从而得到一个新的、个数加一的有序数据,算法适用于少量数据的排序。插入算法把要排序的数组分成两部分:第一部分包含了这个数组的所有元素,但将最后一个元素除外(让数组多一个空间才有插入的位置),而第二部分就只包含这一个元素(即待插入元素)。在第一部分排序完成后,再将这个最后元素插入到已排好序的第一部分中。

插入排序的基本思想是:每步将一个待排序的记录,按其关键码值的大小插入前面已经排序的文件中适当位置上,直到全部插入完为止。
 
举一个例子来说明:
        0  1  2  3  4  5  6  7  8  9  0

         4  8  2  0  9  5  7  1  5  6  3

       (4)(8  2  0  9  5  7  1  5  6  3)  //第一趟

          (4    8)    (2   0  9  5  7  1  5  6  3)    //第二趟

         (2  4  8)  (0  9  5  7  1  5  6  3)    //第三趟

         (0  2  4  8)  (9  5  7  1  5  6  3)    //第四趟

                     .......

是稳定的排序算法。时间复杂度的基本运算如果按比较和移动相同的话,则,时间复杂度固定为O(n*(n-1)/2)  =>O(n*n)。

最优的情况和最差的情况相同:

最优的情况(完全顺序),则,比较次数最多,移动次数为0;

最差的情况(完全逆序),则,比较次数最少,移动次数最多。

实现代码如下:

 1 void insertSort(int *data,int count){
 2     int fi;
 3     int j;
 4     
 5     for(fi = 1;fi < count; fi++){   //无序数组 
 6         int i ;
 7         int tmp = data[fi];            //有序数的数组data[]; 
 8         for(i = 0;i < fi;i++){
 9             if(data[i] > tmp){   //需要插入的data[i]和有序的tmp比较; 
10                 break;
11             }
12             for(j = fi;j > i;j--){    //移动 
13                 data[j] = data[j-1];
14             }
15             data[i] = tmp;
16         }
17     }
18 } 

2.选择排序:

选择排序(Selection sort)是一种简单直观的排序算法。它的工作原理是每一次从待排序的数据元素中选出最小(或最大)的一个元素,存放在序列的起始位置,直到全部待排序的数据元素排完。

举个例子来说明:

       4  7  2  5  9  1  5  8  6  3

       () (4  7  2  5  9  1  5  8  6  3)  //第一趟

      (1)(7  2  5  9  4  5  8  6  3)    //第二趟

      (1  2)(7  5  9  4  5  8  6  3)    //第三趟

      (1  2  3)(5  9  4  5  8  6  7)    //第四趟

              ........

稳定性分析:

选择排序是给每个位置选择当前元素最小的,比如给第一个位置选择最小的,在剩余元素里面给第二个元素选择第二小的,依次类推,直到第n-1个元素,第n个元素不用选择了,因为只剩下它一个最大的元素了。那么,在一趟选择,如果一个元素比当前元素小,而该小的元素又出现在一个和当前元素相等的元素后面,那么交换后稳定性就被破坏了。比较拗口,举个例子,序列5 8 5 2 9,我们知道第一遍选择第1个元素5会和2交换,那么原序列中两个5的相对前后顺序就被破坏了,所以选择排序是一个不稳定的排序算法。
 
算法时间复杂度:O(n(n - 1)/2) => O(n*n).
 
最优情况(完全顺序):时间复杂度只在于交换次数
最差情况(某种顺序):时间复杂度也只在于交换次数
 
代码如下:
 1 void chooseSort(int *data,int count){
 2     int index;
 3     int i ;
 4     int minIndex;
 5     int tmp;
 6     
 7     for(index = 0;index < count - 1;index++){        //遍历整个数组 
 8         for(minIndex = i = index;i < count;i++){    //拿出未排序第一个数与后面的数比较 
 9             if(data[minIndex] > data[i]){          //找到最小的 就是拿出来的那个数 
10                 minIndex = i;
11             }
12         }
13         if(minIndex != index){        //若拿出来的数不是最小的 
14             tmp = data[index];            //把拿出的这个数和后面比较出来最小的交换。 
15             data[index] = data[minIndex];
16             data[minIndex] = tmp;
17         }
18     }
19 }

3.直接交换排序

所谓交换,就是根据序列中两个记录键值的比较结果来对换这两个记录在序列中的位置,交换排序的特点是:将键值较大的记录向序列的尾部移动,键值较小的记录向序列的前部移动。

举个例子来说明:

        6  9  2  0  8  1  7  2  3  5  4

        6  2  0  8  1  7  2  3  5  4  9

        2  6  6  1  7  2  3  5  4  8  9

                                  ..........

稳定性:

由于在直接选择排序中存在着不相邻元素之间的互换,因此,直接选择排序是一种不稳定的排序方法。

时间复杂度:

在直接选择排序中,共需要进行n-1次选择和交换,每次选择需要进行 n-i 次比较 (1<=i<=n-1),而每次交换最多需要3次移动,因此,总的比较次数C=(n*n - n)/2,
总的移动次数 3(n-1).由此可知,直接选择排序的时间复杂度为 O(n2) ,所以当记录占用字节数较多时,通常比直接插入排序的执行速度快些。
代码如下:
 1 void swapSort(int * data;int count){
 2     boolean swap = TRUE;
 3     int tmp;
 4     
 5     for(int i = 0;swap&&i < n-1;i++){
 6         for(swap = FALSE,j = 0;j < n-1-i;j++){
 7             if(data[j] > data[j+1]){
 8                 tmp = data[j];
 9                 data[j] = data[j+1];
10                 data[j+1] = tmp;
11                 swap = TRUE;
12             }
13         }
14     } 
15 } 

 直接插入排序的改良排序:希尔排序。

基本思想:先取一个小于n的整数d1作为第一个增量,把文件的全部记录分组。所有距离为d1的倍数的记录放在同一个组中。先在各组内进行直接插入排序

然后,取第二个增量d2<d1重复上述的分组和排序,直至所取的增量=1(<…<d2<d1),即所有记录放在同一组中进行直接插入排序为止。

稳定性:由于多次插入排序,我们知道一次插入排序是稳定的,不会改变相同元素的相对顺序,但在不同的插入排序过程中,相同的元素可能在各自的插入排序中移动,最后其稳定性就会被打乱,所以shell排序是不稳定的。

在希尔排序过程中,屡次使用“直接插入排序”算法,但是,又与之前直接插入排序的环境有所不同。

后续更新。。。。。。




原文地址:https://www.cnblogs.com/youdiaodaxue16/p/9690484.html