1.快速排序法
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
1 //方法1 从大到小 2 #include <iostream.h> 3 void run(int* pData,int left,int right) 4 { 5 int i,j; 6 int middle,iTemp; 7 i = left; 8 j = right; 9 middle = pData[(left+right)/2]; //求中间值 10 do{ 11 while((pData[i]<middle) && (i<right))//从左扫描大于中值的数 12 i++; 13 while((pData[j]>middle) && (j>left))//从右扫描大于中值的数 14 j--; 15 if(i<=j)//找到了一对值 16 { 17 //交换 18 iTemp = pData[i]; 19 pData[i] = pData[j]; 20 pData[j] = iTemp; 21 i++; 22 j--; 23 } 24 }while(i<=j);//如果两边扫描的下标交错,就停止(完成一次) 25 26 //当左边部分有值(left<j),递归左半边 27 if(left<j) 28 run(pData,left,j); 29 //当右边部分有值(right>i),递归右半边 30 if(right>i) 31 run(pData,i,right); 32 } 33 34 void QuickSort(int* pData,int Count) 35 { 36 run(pData,0,Count-1); 37 } 38 39 void main() 40 { 41 int data[] = {10,9,8,7,6,5,4}; 42 QuickSort(data,7); 43 for (int i=0;i<7;i++) 44 cout<<data[i]<<" "; 45 cout<<" "; 46 }
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
1 //方法2 从大到小 2 //参照《数据结构》(C语言版) 3 //调用:quicksort-->qsort-->partitions 4 int partitions(int a[],int low,int high){ 5 int pivotkey=a[low]; //*从数组的最左边开始作中间值 6 //a[0]=a[low]; 7 while(low<high){ 8 while(low<high && a[high]>=pivotkey) --high; 9 a[low]=a[high]; 10 while(low<high && a[low]<=pivotkey) ++low; 11 a[high]=a[low]; 12 } 13 //a[low]=a[0]; 14 a[low]=pivotkey; 15 return low; 16 } 17 void qsort(int a[],int low,int high){ 18 int pivottag; 19 if(low<high){ 20 //递归调用 21 pivottag=partitions(a,low,high); 22 qsort(a,low,pivottag-1); 23 qsort(a,pivottag+1,high); 24 } 25 } 26 void quicksort(int a[],int n){ 27 qsort(a,0,n); 28 } 29 //简单示例 30 #include <stdio.h> 31 //#include <math.h> 32 #include "myfunc.h" //存放于个人函数库中 33 int main(void){ 34 int i,a[11]={0,11,12,5,6,13,8,9,14,7,10}; 35 for(i=0;i<11;printf("%3d",a[i]),++i); 36 printf(" "); 37 quicksort(a,10); 38 for(i=0;i<11;printf("%3d",a[i]),++i); 39 printf(" "); 40 }
正如其名快速排序,其效率也是比较高的,时间复杂度为O(nlogn)。其算法思想是每次确定一个基准值的位置,也就是函数int Partition(int a[],int p,int r)的作用。然后通过递归不断地确定基准值两边的子数组的基准值的位置,直到数组变得有序。
2.希尔排序法
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
1 void ShellSort(int *array,int length) 2 3 { 4 5 int d = length/2; //设置希尔排序的增量 6 /* 求“增量”的公式 h(n+1)=3*h(n)+1,(h>N/9停止)这个公式可能选择增量不是最合适,但是却适用一般“增量”的设定 */ 7 int i ; 8 int j; 9 int temp; 10 while(d>=1) 11 { 12 for(i=d;i<length;i++) // 小序列里的直接插入排序 13 { 14 temp=array[i]; 15 j=i-d; 16 while(j>=0 && array[j]>temp) 17 { 18 array[j+d]=array[j]; 19 j=j-d; 20 } 21 array[j+d] = temp; 22 } 23 //Display(array,10); 24 d= d/2; //缩小增量 25 } 26 }
首先需要一个递减的步长。工作原理是首先对相隔d个元素的所有内容排序,然后再使用同样的方法对相隔d/2个的元素排序,以此类推。
先取一个小于n的整数d1作为第一个增量,把文件的全部记录分成d1个组。所有距离为d1的倍数的记录放在同一个组中。先在各组内进行直接插入排序;然后,取第二个增量d2<d1重复上述的分组和排序,直至所取的增量dt=1(dt<dt-l<…<d2<d1),即所有记录放在同一组中进行直接插入排序为止。
3.双向冒泡法
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
1 #include <iostream.h> 2 void Bubble2Sort(int* pData,int Count) 3 { 4 int iTemp; 5 int left = 1; 6 int right =Count -1; 7 int t; 8 do 9 { 10 //正向的部分 11 for(int i=right;i>=left;i--) 12 { 13 if(pData[i]<pData[i-1]) 14 { 15 iTemp = pData[i]; 16 pData[i] = pData[i-1]; 17 pData[i-1] = iTemp; 18 t = i; 19 } 20 } 21 left = t+1; 22 23 //反向的部分 24 for(i=left;i<right+1;i++) 25 { 26 if(pData[i]<pData[i-1]) 27 { 28 iTemp = pData[i]; 29 pData[i] = pData[i-1]; 30 pData[i-1] = iTemp; 31 t = i; 32 } 33 } 34 right = t-1; 35 }while(left<=right); 36 } 37 38 void main() 39 { 40 int data[] = {10,9,8,7,6,5,4}; 41 Bubble2Sort(data,7); 42 for (int i=0;i<7;i++) 43 cout<<data[i]<<" "; 44 cout<<" "; 45 }
以整数升序排序为例来简单说明一下双向冒泡排序的过程:首先从前往后把最大数移到最后,然后反过来从后往前把最小的一个数移动到数组最前面,这一过程就是第一轮,然后重复这一过程,最终就会把整个数组从小到大排列好。双向冒泡排序要稍微优于传统的冒泡排序,因为双向排序时数组的两头都排序好了,我们只需要处理数组的中间部分即可,而单向即传统的冒泡排序只有尾部的元素是排好序的,这时每轮处理都需要从头一直处理到已经排好序元素的前面一个元素。虽然它在效率上有了点改进,但它也不能大幅度提高其排序的效率,这是由冒泡排序的基本过程所决定了的。
4.堆排序法
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
1 //堆排序 2 //////////////////////////////////////////////////////////////////////////// 3 int Parent(int i) 4 { 5 return i/2; 6 } 7 int Left(int i) 8 { 9 return 2*i; 10 } 11 int Right(int i) 12 { 13 return 2*i+1; 14 } 15 16 //把以第i个节点给子树的根的子树调整为堆 17 void MaxHeap(int *a,int i,int length) 18 { 19 int L=Left(i); 20 int R=Right(i); 21 int temp; 22 int largest; //记录子树最大值的下表,值可能为根节点下标、左子树下表、右子树下标 23 if (L<=length&&a[L-1]>a[i-1]) //length是递归返回的条件 24 { 25 largest=L; 26 } 27 else largest=i; 28 if (R<=length&&a[R-1]>a[largest-1]) //length是递归返回的条件 29 largest=R; 30 if (largest!=i) 31 { 32 temp=a[i-1]; 33 a[i-1]=a[largest-1]; 34 a[largest-1]=temp; 35 MaxHeap(a,largest,length); 36 } 37 } 38 39 void BuildMaxHeap(int *a,int length) 40 { 41 42 for (int i=length/2;i>=1;i--) 43 MaxHeap(a,i,length); 44 } 45 46 void HeapSort(int *a,int length) 47 { 48 BuildMaxHeap(a,length); 49 for (int i=length;i>0;i--) 50 { 51 int temp; 52 temp=a[i-1]; 53 a[i-1]=a[0]; 54 a[0]=temp; 55 length-=1; 56 MaxHeap(a,1,length); 57 } 58 }
其实堆排序是简单选择排序的一种进化,它最主要是减少比较的次数。什么是堆?若将序列对应看成一个完全二叉树,完全二叉树中所有非终端节点的值均不大于(或者不小于)其左右孩子节点的值,可以称作为堆。由堆的性质可以知道堆顶是一个最大关键字(或者最小关键字)。在输出堆顶后,使剩下的元素又建成一个堆,然后在输出对顶。如此反复执行,便能得到一个有序序列,这个过程成便是堆排序。堆排序主要分为两个步骤:(1)从无序序列建堆。(2)输出对顶元素,在调成一个新堆。
5.归并排序法
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
1 //归并排序 2 void MergeSort(int b[10],int d[10],int min,int max) 3 { 4 //用与存放中间分区域得到的序列 5 int c[10]; 6 void Merge(int c[10],int d[10],int min,int mid,int max); 7 if(min==max)d[min]=b[min]; 8 else 9 { 10 //平分成两个区域 11 int mid=(min+max)/2; 12 //将这个区域进行归并排序 13 MergeSort(b,c,min,mid); 14 //将这个区域进行归并排序 15 MergeSort(b,c,mid+1,max); 16 //两个区域归并 17 Merge(c,d,min,mid,max); 18 } 19 } 20 21 //将有序序列d[min-mid]与d[mid+1-max]归并成有序序列c[min-max] 22 void Merge(int c[10],int d[10],int min,int mid,int max) 23 { 24 int i,j,k; 25 for(i=j=min,k=mid+1;j<=mid&&k<=max;i++) 26 { 27 if(c[j]>c[k]) 28 { 29 d[i]=c[k]; 30 k++; 31 } 32 else 33 { 34 d[i]=c[j]; 35 j++; 36 } 37 } 38 if(j<=mid) 39 { 40 for(;j<=mid;j++,i++) 41 { 42 d[i]=c[j]; 43 } 44 } 45 if(k<=max) 46 { 47 for(;k<=max;k++,i++) 48 { 49 d[i]=c[k]; 50 } 51 } 52 }
假设初始序列含有n个记录,则可看成n个有序的子序列,每个子序列长度为1,然后两两归并,得到[n/2]个长度为2或者为1(这里长度为1可能这里序列长度是奇数,那么最后一个序列就落单了,所以长度为1);在两两归并,如此重复,直至得到一个长度为n的有序序列为止。
6.基数排序法
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
1 //基数排序 2 ///////////////////////////////////////////////// 3 int GetMaxTimes(int *a,int n) 4 { 5 int max=a[0]; 6 int count=0; 7 for (int i=1;i<n;i++) 8 { 9 if(a[i]>max) 10 max=a[i]; 11 } 12 while(max) 13 { 14 max=max/10; 15 count++; 16 } 17 return count; 18 } 19 20 void InitialArray(int *a,int n) 21 { 22 for (int i=0;i<n;i++) 23 a[i]=0; 24 } 25 26 // void InitialArray1(int a[][],int m,int n) 27 // { 28 // for (int i=0;i<m;i++) 29 // for (int j=0;j<n;j++) 30 // a[i][j]=0; 31 // } 32 33 void RadixSort(int *a,int n) 34 { 35 int buckets[10][10000]={0}; 36 int times=GetMaxTimes(a,n); 37 int index,temp; 38 int record[10]={0}; 39 for (int i=0;i<times;i++) 40 { 41 int count=0; 42 temp=pow(10,i);//index=(a[j]/temp)%10;用来从低位到高位分离 43 for (int j=0;j<n;j++) 44 { 45 index=(a[j]/temp)%10; 46 buckets[index][record[index]++]=a[j]; 47 } 48 //把桶中的数据按顺序还原到原数组中 49 for(int k=0;k<10;k++) 50 for (int m=0;m<100000;m++) 51 { 52 if(buckets[k][m]==0)break; 53 else 54 { 55 a[count++]=buckets[k][m]; 56 //cout<<buckets[k][m]<<" "; 57 } 58 } 59 //重新初始化桶,不然前后两次排序之间会有影响 60 //buckets[10][10000]={0}; 61 //record[10]={0}; 62 //InitialArray1(buckets,10,10000); 63 for (k=0;k<10;k++) 64 for (int m=0;m<100000;m++) 65 { 66 if(buckets[k][m]==0)break; 67 else buckets[k][m]=0; 68 } 69 InitialArray(record,10); 70 } 71 }
最后一种是比较特别的基数排序(属于分配式排序,前几种属于比较性排序)又称“桶子法”,基本思想是通过键值的部分信息分配到某些桶中,藉此达到排序的作用,基数排序属于稳定的排序,其时间复杂度为O(nlog(r)m),r为所采取的的基数,m为堆的个数,在某些情况下基数排序法的效率比其他比较性排序效率要高。
推荐文章:
http://www.cnblogs.com/maxiaofang/p/3381692.html
http://zh.wikipedia.org/wiki/%E6%8E%92%E5%BA%8F%E7%AE%97%E6%B3%95