各种常规排序算法总结

来源:互联网 发布:mac 查看node安装路径 编辑:程序博客网 时间:2024/05/16 09:57
原文链接http://blog.csdn.net/qll125596718/article/details/6901539#t1, 感谢qll125596718总结和分享

1.插入排序

        基本思想是:每次将一个待排序的记录,按其关键字大小插入到前面已经排好序的子表中的适当位置,直到全部记录插入完成为止。常规插入排序分两种,即直接插入排序和希尔排序。

1.1直接插入排序

        假设待排序的记录放在数组R[0...n-1]中,排序过程的某一中间时刻,R被划分成两个子区间R[0..i-1]和R[i..n-1],其中:前一个区间是已经排好序的有序区,后一个子区间是当前未排序的部分,不妨称为无序区。直接插入排序的基本操作是将当前无序区的第一个记录R[i]插入到R[0..i-1]中适当的位置,使R[0..i]变为新的有序区-------算法时间复杂度o(n^2)。
[cpp] view plaincopy
  1. // 插入排序  
  2. void insertSort(int array[], int length)  
  3. {  
  4.     int i, j, key;  
  5.     for (i = 1; i < length; i++)  
  6.     {  
  7.         key = array[i];  
  8.         // 把i之前大于array[i]的数据向后移动  
  9.         for (j = i - 1; j >= 0 && array[j] > key; j--)  
  10.         {  
  11.             array[j + 1] = array[j];  
  12.         }  
  13.         // 在合适位置安放当前元素  
  14.         array[j + 1] = key;  
  15.     }  
  16. }  

1.2shell排序

        希尔排序也是一种插入排序方法,实际上是一种分组插入方法。基本思想是:先取定一个小于n的整数d1作为第一个增量,把表的全部记录分成d1个组,所有距离为d1的倍数的记录放在同一个组中,在各组内进行直接插入排序;然后取第二个增量d2(<d1),重复上述的分组和排序,直至所取的增量dt=1(dt<dt-1<..d2<d1),及所有记录放在同一组中进行直接插入排序为止。算法最好时间复杂度o(nlogn)。
[cpp] view plaincopy
  1. // shell排序  
  2. void shellSort(int array[], int length)  
  3. {  
  4.     int key;  
  5.     // 增量从数组长度的一半开始,每次减小一倍  
  6.     for (int increment = length / 2; increment > 0; increment /= 2)  
  7.         for (int i = increment; i < length; ++i)  
  8.         {  
  9.             key = array[i];  
  10.             // 对一组增量为increment的元素进行插入排序  
  11.             for (int j = i - increment; j >= 0 && array[j] > key; j -= increment)  
  12.             {  
  13.                 array[j+increment] = array[j];  
  14.             }  
  15.             // 在合适位置安放当前元素  
  16.             array[j+increment] = key;  
  17.         }  
  18. }  

2.交换排序

          基本思想:两两比较待排序记录的关键字,发现两个记录的次序相反时,即进行交换,直到没有反序的记录为止。

2.1冒泡排序

         基本思想是,通过无序区中相邻记录关键字间的比较和位置的交换,使关键字最小的记录如气泡一般逐渐往上“漂浮”直至“水面”。整个算法是从最后面的记录开始,对每两个相邻的关键字进行比较,且使关键字较小的记录换至关键字较大的记录之上,使得经过一趟冒泡排序后,关键字最小的记录到大最上端,接着,再在剩下的记录中找到关键字次小的记录,并把它换在第二个位置上,依次类推,一直到所有记录都有序为止。算法时间复杂度o(n^2)。
[cpp] view plaincopy
  1. //冒泡排序  
  2. void bubble_sort(int a[], int length)  
  3. {  
  4.     int i, j, tag;  
  5.   
  6.     for(i = length - 1; i > 0; i--)//不断把前面无序区最大元素移到后面有序区  
  7.     {  
  8.         tag = 1;//标志位  
  9.         for(j = 0; j < i; j++)//前面无序区最大元素不断向后移  
  10.         {  
  11.             if(a[j] > a[j + 1])  
  12.             {  
  13.                 a[j] ^= a[j + 1];  
  14.                 a[j + 1] ^= a[j];  
  15.                 a[j] ^= a[j+1];  
  16.                 tag = 0;  
  17.             }  
  18.         }  
  19.         if(tag == 1)  
  20.         {  
  21.             break;  
  22.         }  
  23.     }  
  24. }  

2.2快速排序

         快速排序是由冒泡排序改进而得的,它的基本思想是:在待排序的n个记录中任取一个记录(通常取第一个记录),把该记录放入适当位置后,数据序列被此记录划分成两部分。所有关键字比该记录关键字小的记录放置在前一部分,所有比它大的记录放置在后一部分,并把该记录排在这两部分的中间(称为该记录归位),这个过程称作一趟快速排序。之后对所有的两部分分别重复上述过程,直至每个部分内只有一个记录或为空为止。简单的说,每趟使表的第一个元素放入适当位置,将表一分为二,对子表按递归方法继续这种划分,直至划分的子表长为1或0.-------算法最好时间复杂度o(nlog2n)
[cpp] view plaincopy
  1. // 对一个给定范围的子序列选定一个枢纽元素,执行完函数之后返回分割元素所在的位置,  
  2. // 在分割元素之前的元素都小于枢纽元素,在它后面的元素都大于这个元素  
  3. int partition(int array[], int low, int high)  
  4. {  
  5.     // 采用子序列的第一个元素为枢纽元素  
  6.     int pivot = array[low];  
  7.     while (low < high)  
  8.     {  
  9.         // 从后往前在后半部分中寻找第一个小于枢纽元素的元素  
  10.         while (low < high && array[high] >= pivot)  
  11.             --high;  
  12.         // 将这个比枢纽元素小的元素交换到前半部分  
  13.         array[low] = array[high];  
  14.         // 从前往后在前半部分中寻找第一个大于枢纽元素的元素  
  15.         while (low < high && array[low] <= pivot)  
  16.             ++low;  
  17.         // 将这个比枢纽元素大的元素交换到后半部分  
  18.         array[high] = array[low];  
  19.     }  
  20.     array[low] = pivot;  
  21.     // 返回枢纽元素所在的位置  
  22.     return low;  
  23. }  
  24. // 快速排序  
  25. void quickSort(int array[], int low, int high)  
  26. {  
  27.     if (low < high)  
  28.     {  
  29.         int n = partition(array, low, high);  
  30.         quickSort(array, low, n);  
  31.         quickSort(array, n + 1, high);  
  32.     }  
  33. }  

3.选择排序

         基本思想:每一趟从待排序的记录中选出关键字最小的记录,顺序放在已排好序的子表的最后,直到全部记录排序完毕。由于选择排序方法每一趟总是从无序区中选出全局最小(或最大)的关键字,所以适合于从大量的记录中选择一部分排序记录,如,从10000个记录中选择出关键字前10位的记录,就适合使用选择排序法。

3.1直接选择排序

         直接选择排序法:第i趟排序开始时,当前有序区和无序区分别为R[0..i-1]和R[i..n-1](0≤ i≤n-1),该趟排序则是从当前无序区中选出关键字最小的记录R[k],将它与无序区的第一个记录R[i]交换,使得R[0..i]和R[i+1..n-1]分别为新的有序区和新的无序区
[cpp] view plaincopy
  1. //直接选择排序  
  2. void selectSort(int array[],int nLength)  
  3. {  
  4.     int i,j,k;  
  5.     for(i = 0; i < nLength - 1; i++)  
  6.     {  
  7.         k = i;  
  8.         for(j = i+1; j < nLength; j++)  
  9.         {  
  10.             if(array[j] < array[k])  
  11.                 k = j;  
  12.         }  
  13.         if(k != i)  
  14.             swap(&array[k],&array[i]);  
  15.     }  
  16. }  

3.2堆排序

         n个关键字序列Kl,K2,…,Kn称为堆,当且仅当该序列满足如下性质(简称为堆性质):

          (1) ki≤K2i且ki≤K2i+1 或(2)Ki≥K2i且ki≥K2i+1(1≤i≤)
         若将此序列所存储的向量R[1……n]看做是一棵完全二叉树的存储结构,则堆实质上是满足如下性质的完全二叉树:树中任一非叶结点的关键字均不大于(或不小于)其左右孩子(若存在)结点的关键字。
         堆的这个性质使得可以迅速定位在一个序列之中的最小(大)的元素。
         堆排序算法的过程如下:1)得到当前序列的最小(大)的元素 2)把这个元素和最后一个元素进行交换,这样当前的最小(大)的元素就放在了序列的最后,而原先的最后一个元素放到了序列的最前面 3)交换可能会破坏堆序列的性质(注意此时的序列是除去已经放在最后面的元素),因此需要对序列进行调整,使之满足于上面堆的性质。重复上面的过程,直到序列调整完毕为止。

[cpp] view plaincopy
  1. // array是待调整的堆数组,i是待调整的数组元素的位置,length是数组的长度  
  2. void heapAdjust(int array[], int i, int nLength)  
  3. {  
  4.     int nChild, nTemp;  
  5.     for (nTemp = array[i]; 2 * i + 1 < nLength; i = nChild)  
  6.     {  
  7.         // 子结点的位置是 父结点位置 * 2 + 1  
  8.         nChild = 2 * i + 1;  
  9.         // 得到子结点中较大的结点  
  10.         if (nChild != nLength - 1 && array[nChild + 1] > array[nChild])  
  11.             ++nChild;  
  12.         // 如果较大的子结点大于父结点那么把较大的子结点往上移动,替换它的父结点  
  13.         if (nTemp < array[nChild])  
  14.             array[i] = array[nChild];  
  15.         else// 否则退出循环  
  16.             break;  
  17.     }  
  18.     // 最后把需要调整的元素值放到合适的位置  
  19.     array[i] = nTemp;  
  20. }  
  21. // 堆排序算法  
  22. void heapSort(int array[], int length)  
  23. {  
  24.     //建立大顶堆  
  25.     for (int i = length / 2 - 1; i >= 0; --i)  
  26.         heapAdjust(array, i, length);  
  27.     // 从最后一个元素开始对序列进行调整,不断的缩小调整的范围直到第一个元素  
  28.     for (int j = length - 1; j > 0; --j)  
  29.     {  
  30.         // 把第一个元素和当前的最后一个元素交换,  
  31.         // 保证当前的最后一个位置的元素都是在现在的这个序列之中最大的  
  32.         swap(&array[0], &array[j]);  
  33.         // 不断缩小调整heap的范围,每一次调整完毕保证第一个元素是当前序列的最大值  
  34.         heapAdjust(array, 0, j);  
  35.     }  
  36. }  

4.归并排序

       归并排序是多次将两个或两个以上的有序表合并成一个有序表。最简单的归并是直接将两个有序的子表合并成一个有序的表。
       两个有序表直接合并成一个有序表的算法Merge().设两个有序表存放在同一数组中相邻的位置上:R[low..mid],R[mid+1..high],先将他们合并到一个局部的暂存数组R1中,待合并完成后将R1复制到R中。每次从两个段中取出一个记录进行关键字的比较,将较小者放入R1中,最后将各段中余下的部分直接复制到R1中。
[cpp] view plaincopy
  1. void merge(int array[],int start,int mid,int end)  
  2. {  
  3.     int i,j,k;  
  4.     i = start;  
  5.     j = mid + 1;  
  6.     k = 0;  
  7.     int * p = (int *)malloc((end - start + 1) * sizeof(int));  
  8.   
  9.     while((i <= mid) && (j <= end))  
  10.     {  
  11.         if(array[i] < array[j])  
  12.             p[k++] = array[i++];  
  13.         else  
  14.             p[k++] = array[j++];  
  15.     }  
  16.     while(i <= mid)  
  17.         p[k++] = array[i++];  
  18.     while(j <= end)  
  19.         p[k++] = array[j++];  
  20.   
  21.     k = 0;  
  22.     while(start <= end)  
  23.         array[start++] = p[k++];  
  24.   
  25.     free(p);  
  26. }  
  27. //归并排序  
  28. void mergeSort(int array[],int start,int end)  
  29. {  
  30.     if(start < end)  
  31.     {  
  32.         int i = (start + end) / 2;  
  33.         mergeSort(array,start,i);  
  34.         mergeSort(array,i+1,end);  
  35.         merge(array,start,i,end);  
  36.     }  
  37. }  

5.计数排序和基数排序      

        在之前介绍过的排序方法,都是属于[比较性]的排序法,也就是每次排序时,都是比较整个关键字的大小以进行排序。计数排序是一个非基于比较的线性时间排序算法。
        计数排序算法的基本思想是对于给定的输入序列中的每一个元素x,确定该序列中值小于x的元素的个数。一旦有了这个信息,就可以将x直接存放到最终的输出序列的正确位置上。例如,如果输入序列中只有17个元素的值小于x的值,则x可以直接存放在输出序列的第18个位置上。

[cpp] view plaincopy
  1. //计数排序  
  2. //nMaxValue为数组array中最大值  
  3. void countingSort(int array[],int nMaxValue,int nLength)  
  4. {  
  5.     int i;  
  6.     int *pTemp = (int *)malloc((nMaxValue + 1) * sizeof(int));  
  7.     int *pResult = (int *)malloc((nLength + 1) * sizeof(int));  
  8.   
  9.     for(i = 0; i <= nMaxValue; i++)  
  10.         pTemp[i] = 0;  
  11.     // 此过程记录每一个元素的个数  
  12.     for(i = 0; i < nLength; i++)  
  13.         pTemp[array[i]]++;  
  14.     // 此过程确定小于元素x的元素的个数  
  15.     for(i = 1; i <= nMaxValue; i++)  
  16.         pTemp[i] += pTemp[i-1];  
  17.     for(i = nLength-1; i >= 0; i--)  
  18.     {  
  19.         pResult[pTemp[array[i]]] = array[i];  
  20.         pTemp[array[i]]--;  
  21.     }  
  22.     for(i = 1; i <= nLength; i++)  
  23.         array[i-1] = pResult[i];  
  24. }  
         基数排序的主要思路是,将所有待比较数值(注意,必须是正整数)统一为同样的数位长度,数位较短的数前面补零. 然后, 从最低位开始, 依次进行一次稳定排序.这样从最低位排序一直到最高位排序完成以后, 数列就变成一个有序序列.
         比如这样一个数列排序: 342 58 576 356, 以下描述演示了具体的排序过程
第一次排序(个位):
3 4 2
5 7 6
3 5 6
0 5 8
第二次排序(十位):
3 4 2
3 5 6
0 5 8
5 7 6
第三次排序(百位):
0 5 8
3 4 2
3 5 6
5 7 6
结果: 58 342 356 576

[cpp] view plaincopy
  1. //基数排序  
  2. //nMaxBit为数字中的最高位数,如最大数为235,则nMaxBit为3  
  3. void radixSort(int *array, int nLength ,int nMaxBit)  
  4. {  
  5.     int i,j;  
  6.     int temp[10];  
  7.     int nTmp;  
  8.     int nRadix = 1;  
  9.     int *pResult = (int *)malloc(nLength * sizeof(int));   
  10.       
  11.     for(j = 1; j <= nMaxBit; j++)  
  12.     {  
  13.         // 以下和计数排序一样  
  14.         for(i = 0; i < 10; i++)  
  15.             temp[i] = 0;  
  16.         // 此过程记录每一个元素的个数  
  17.         for(i = 0; i < nLength; i++)  
  18.         {  
  19.             nTmp = (array[i] / nRadix) % 10;  
  20.             temp[nTmp]++;  
  21.         }  
  22.         // 此过程确定小于元素x的元素的个数  
  23.         for(i = 1; i < 10; i++)  
  24.             temp[i] += temp[i-1];  
  25.         for(i = nLength-1; i >= 0; i--)  
  26.         {  
  27.             nTmp = (array[i] / nRadix) % 10;  
  28.             temp[nTmp]--;  
  29.             pResult[temp[nTmp]] = array[i];  
  30.         }  
  31.         for(i = 0; i < nLength; i++)  
  32.             array[i] = pResult[i];  
  33.         nRadix *= 10;  
  34.     }  
  35. }  

 


原创粉丝点击