排序算法汇总

一.排序算法

1.直接插入排序

      算法思想:直接插入排序是利用顺序查找来确定r[i]在r[1..i-1]有序序列区中插入的位置,将第i个记录的关键字Ki与前面记录r[1]~r[i-1]的关键字从后面向前顺序进行比较,将所有关键字大于Ki的记录依次向后移动一个位置,知道遇到一个关键字小于或等于Ki的记录,该记录的位置即为r[i]的位置。

     c语言代码如下:

 1 void InsertSort(RecordList L)
 2 {
 3     for(int i=2;i<=L.length;i++)
 4     {
 5         if(L.r[i].Key<L.r[i-1].key)
 6         {
 7             L.r[0] = L.r[i];          //监视哨备份待查记录
 8             for(j=i-1;L.r[0].key<L.r[j].key;j--)
 9                 L.r[j+1] = L.r[j];  //记录后移
10                 L.r[j+1]=L.r[0];  //插入到正确的位置
11 
12         }
13     }
14 }
View Code

     java语言实现:

 1 public class InsertSort {
 2     public static void main(String[] args) {
 3        int [] arr = new int[]{4,5,2,1,0,3,2,5,7,98,0,12,34,6,7,4};
 4        insertSort(arr);
 5         for (int i = 0; i < arr.length; i++) {
 6             System.out.println(arr[i]);
 7         }
 8     }
 9     public static void insertSort(int [] arr){
10         for (int i = 1; i < arr.length; i++) {
11             if(arr[i] < arr[i - 1]){
12                 int temp = arr[i];
13                 for (int j = i ; j >= 0; j--) {
14                     if(temp < arr[j]) {
15                         arr[j + 1] = arr[j];
16                         arr[j] = temp;
17                     }
18                 }
19             }
20         }
21     }
22 }

      时间复杂度:在最坏情况下(倒序)时间复杂度为O(n^2)。

      空间复杂度:它只需要一个元素的辅助空间,即监视哨r[0],用于元素位置的交换,所以空间复杂度为O(1)。

      稳定性:插入排序是稳定的,因为具有相同值得元素必然插在同一值得前一个元素的后面。

2.折半插入排序

      算法思想:此算法思想与直接插入算法思想类似,将直接插入法每次折半后,再进行插入。

      c语言代码如下:

 1 void BiInsertSort(RecordList L)
 2 {
 3   for(int i=2;i<L.length;i++)
 4     {
 5       L.r[0] = L.r[i];  //监视哨备份待查记录
 6       if(L.r[i].key>L.r[i-1].key)
 7         {
 8           low=1; high=1; //折半查找r[i]的位置
 9           while(low<high)
10             {
11               mid = (low+high)/2;
12               if(L.r[i].key<L.r[mid].key)
13                   high=mid-1;
14               else low=mid+1;
15             }
16             for(j=i-1;j>=low;j-)
17                 L.r[j+1] = L.r[j];//记录后移
18             L.r[low]=L.r[0];//插入正确的位置
19         }
20     }
21 }
View Code

       时间复杂度:O(n^2)

       空间复杂度与稳定性和直接插入法一致。

3.希尔排序

      算法思想:先将整个待排的序列分割成若干个子序列,分别进行插入排序,然后依次缩减增量再进行排序,待整个序列中元素基本有序(增量足够小)时,再对全体元素进行一次直接插入排序。

      c语言代码如下:

 1 void shellInsert(RecordList L,int dk)
 2 {
 3     for(i=dk+1;i<=L.length;i++)
 4         if(L.r[i].key<L.r[i-dk].key)
 5         {
 6             L.r[0] = L.r[i];
 7             for(j=i-dk;j>0&&(L.r[0].key<L.r[j].key);j-=dk;)
 8             L.r[j+dk] = L.r[j];
 9             L.r[j+dk]=L.r[0];
10         }
11 }
12 void ShellSort(RecordList L,int dlta[],intt)
13 {
14     for(k=0;k<L.length;t++)
15         shellInsert(L,dlta);
16 }
View Code

     时间复杂度:O(n^2)

     空间复杂度与直接插入法一致,只需要一个辅助空间。

     稳定性:在排序过程中两个相同的关键字可能发生顺序的改变,所以不稳定。

4.冒泡排序法

     算法思想:对待排序的记录的关键字两两进行比较,只要发现两个记录为逆序之后进行交换,知道没有逆序为止。

     C语言代码如下:

 1 void BubbleSort(RecordList L)
 2 {
 3   flag = 1;
 4   for(int i=1;i<L.length-1&&flag;i++)
 5     {
 6       flag=0;
 7       for(j=1;j<L.length-i;j++)
 8          if( L.r[j].key>L.r[j+1].key)
 9          }
10              t=L.r[j];
11              L.r[j]=L.r[j+1];
12              L.r[j+1] = t;
13              flag=1;
14          {
15          
16     }
17 }
View Code

   时间复杂度:O(n^2)

   空间复杂度:需要一个辅助空间进行交换,为O(1)。

5.快速排序法

    算法思想:从待排序列中任意选择一个记录,以该记录的关键字作为“枢轴”,凡是关键字小于枢轴的记录均移动至该记录之前,反之凡是关键字大于轴枢的记录均移至该记录之后。

    c语言代码如下:

 1 一趟排序
 2 int QKpass(RecordList L,int low,int high)
 3 {
 4     L.r[0]=L.r[low];
 5     while(low<high)
 6     {
 7         while(low<high&&L.r[high].key>=L.r[0].key) --high;
 8         L.r[low] = L.r[high];
 9         while(low<high&&L.r[low].key<=L.r[0].key) ++low;
10         L.r[high] = L.r[low];
11     }
12     L.r[low]=L.r[0];
13     return low;
14 }
15 //快速排序
16 void QKSort(RecordList L,int low,int high)
17 {
18     if(low<high)
19     {
20         pos=QKpass(L,low,high);
21         QKSort(L,low,pos-1);
22         QKSort(L,pos+1;high);
23     }
24 }
View Code

    时间复杂度:最坏情况下:O(n^2)

                          最好情况下:T(n)=θ(nlogn)

    空间复杂度:快排总共需要分割log2n次,即需要log2n个辅助空间记录枢轴的位置,所以复杂度为O(log2n)。

    稳定性:不稳定。

java实现

  if(left >= right){
            return;
        }
        int i = left;
        int j = right;
        int key = arr[left];
        while (i < j){
            while (i < j && arr[j] >= key) j--;
            arr[i] = arr[j];
            while (i < j && arr[i] <= key) i++;
            arr[j] = arr[i];
        }
        arr[i] = key;
        quickSort(arr,left,i - 1);
        quickSort(arr,i + 1,right);

  

6.简单选择排序法

    算法思想:从第一个记录开始,将后面n-1个记录进行比较,找到最小的和第一个记录交换,从第二个记录开始,重复以上步骤。

    c语言代码如下:

 1 void sellectSort(RecordList L)
 2 {
 3     for(int i=1;i<L.length;i++)
 4     {
 5         k=i;
 6         for(j=i+1;j<L.length;j++)
 7             if(L.r[j]<L.r[i])
 8             k=j;
 9         if(k!=i)
10         {
11             t=L.r[i];
12             L.r[i]=L.r[k];
13             L.r[k]=t;     
14         }
15     }
16 }
View Code

     时间复杂度:O(n^2)

     空间复杂度:需要一个辅助空间进行交换,故为O(1).

7.堆排序

     算法思想及步骤:

        ①建堆,建堆是不断调整堆的过程,从len/2处开始调整,一直到第一个节点,此处len是堆中元素的个数。建堆的过程是线性的过程,从len/2到0处一直调用调整堆的过程,相当于o(h1)+o(h2)…+o(hlen/2) 其中h表示节点的深度,len/2表示节点的个数,这是一个求和的过程,结果是线性的O(n)。
        ②调整堆:调整堆在构建堆的过程中会用到,而且在堆排序过程中也会用到。利用的思想是比较节点i和它的孩子节点left(i),right(i),选出三者最大(或者最小)者,如果最大(小)值不是节点i而是它的一个孩子节点,那边交互节点i和该节点,然后再调用调整堆过程,这是一个递归的过程。调整堆的过程时间复杂度与堆的深度有关系,是lgn的操作,因为是沿着深度方向进行调整的。
       ③堆排序:堆排序是利用上面的两个过程来进行的。首先是根据元素构建堆。然后将堆的根节点取出(一般是与最后一个节点进行交换),将前面len-1个节点继续进行堆调整的过程,然后再将根节点取出,这样一直到所有节点都取出。堆排序过程的时间复杂度是O(nlgn)。因为建堆的时间复杂度是O(n)(调用一次);调整堆的时间复杂度是lgn,调用了n-1次,所以堆排序的时间复杂度是O(nlgn)[2] 
      c语言代码:
 1 void HeapSort(RecordList L)
 2 {
 3     CreatHeap(L);
 4     for(i=L.length;i>=2;i--)
 5     {
 6         L.r[0]=L.r[1];
 7         L.r[1]=L.r[i];
 8         L.r[i]=L.r[0];
 9     }
10 }
11 //建初始堆
12 void CreatHeap(RecordList L)
13 {
14     for(i=L.length/2;i>=1;i--)
15         HeapAdjust(L,i,L,length);
16 }
17 //堆的筛选
18 void HeapAdjust(RecordList L,int s,int m)
19 {
20     t=L.r[s];
21     for(j=2*s;j<=m;j*=2)
22     {
23         if(j<m&&L.r[j].key>L.r[j+1].key)
24             j++;
25         if(t.key<=L.r[j].key)
26             break;
27         L.r[s]=L.r[j];
28         s=j;
29     }
30     L.r[s]=t;
31 }
View Code

     时间复杂度:O(nLog2n)

     空间复杂度:O(1)

     稳定性:不稳定。

8.桶排序

     桶排序的前提条件:必须知道待排的数据的范围。有以下两种情况:

   (1)待排数据大小的范围比较小的情况,例如:有5个待排的序列(a[4,7,9,4,3]),每个数字的大小都在0~10之间.

     算法思想:创建10个桶,即大小为10的一维数组b,初始化为0,依次遍历原数组(4,7,9,4,3),将遍历的每个数字对应下标的数组值加1(例如:遍历第一个数字为4,则b[4]+1;第二个数为7,则b[7]+1;.....)最后得到数组内b[3]=1;b[4]=2;b[7]=1;b[9]=1;最后将b数组打印出来就是所排的序列(例如:b[3]=1,则打印一个3,b[4]=2打印两个4)。

     c语言代码如下:

 1 void TSort(int a[], int n)
 2 {
 3     int t=0;
 4     int b[k] = {0};    //k为桶的个数,自行定义
 5     for (int i = 0; i< n; i++)
 6     {  
 7         t = a[i];
 8         b[t]++;
 9     }
10     for (int i = 1; i< 10; i++)
11      for (int j = 1; j <= b[i]; j++)
12         printf("%d ", i);
13 }
View Code

    (2)待排数据范围比较大的情况,例如有20个待排数据,每个数据的范围为0~999,那么如果按照上面的方法,则需要创建999个桶,能用到的桶<=20,显然不是最优算法,那么就需要第二种解法:

      算法思想:创建10个桶即创建大小为10 的一维数组,进行三次桶排:

      第一次:将20个数的元素本身依次放入个位数对应下标的数组中(例如:将123放入b[3]中)每个桶中可能有多个数。

再讲20个数字依次存入原来的数组中。

      第二次:将第一次排好的数组中的20个数的元素本身依次放入十位数对应下标的数组中(例如:将123放入b[2]中)每个桶中可能有多个数,再讲20个数字依次存入原来的数组中。

     第三次:将第二次排好的数组中的20个数的元素本身依次放入百位数对应下标的数组中(例如:将123放入b[1]中)每个桶中可能有多个数,再讲20个数字依次存入原来的数组中。即已经排序好。

posted on 2017-03-26 16:42  程序员简笔  阅读(185)  评论(0编辑  收藏  举报

导航