本文对各个排序算法进行了一点复习整理,并通过一段代码对几种排序算法进行了实现。这包括:冒泡排序,插入排序,选择排序,希尔排序,堆排序,归并排序,快速排序,基数排序,计数排序等。相关简要讨论在程序中有一定说明。
各种算法实现见以下示例代码:
/******************************************************************* *各种排序算法示例程序---By F8Master */ #include<stdlib.h> #include<iostream> #include<vector> #include<iomanip> using namespace std; template <class Comparable> void bubbleSort(vector<Comparable> &a); template<typename Comparable> void insertSort(vector<Comparable> &a); template<typename Comparable> void selectSort(vector<Comparable> &a); template<typename Comparable> void shellSort(vector<Comparable> &a); template<typename Comparable> void heapSort(vector<Comparable> &a); template<typename Comparable> void mergeSort(vector<Comparable> &a); template<typename Comparable> void quickSort(vector<Comparable> &a); template<typename Comparable> void countSort(vector<Comparable> &a); template<typename Comparable> void radixSort(vector<Comparable> &a); void main() { vector<int> v; while(true) { cout<<"Choose sort Algorithm(0 for end) :"<<endl; int num=0; cout<<setw(2)<<++num<<setw(20)<<"BubbleSort"<<endl; cout<<setw(2)<<++num<<setw(20)<<"InsertSort"<<endl; cout<<setw(2)<<++num<<setw(20)<<"SelectSort"<<endl; cout<<setw(2)<<++num<<setw(20)<<"ShellSort"<<endl; cout<<setw(2)<<++num<<setw(20)<<"HeapSort"<<endl; cout<<setw(2)<<++num<<setw(20)<<"MergeSort"<<endl; cout<<setw(2)<<++num<<setw(20)<<"QuickSort"<<endl; cout<<setw(2)<<++num<<setw(20)<<"CountSort"<<endl; cout<<setw(2)<<++num<<setw(20)<<"RadixSort"<<endl; int selnum; cin>>selnum; if(selnum==0) break; v.clear(); for(int i=0;i<128;i++) v.push_back(rand()%1000); cout<<"Before sort:"<<endl; for(int i =0;i<v.size();i++) cout<<setw(5)<<v[i]; cout<<endl; switch(selnum) { case 1: bubbleSort(v); case 2: insertSort(v); case 3:selectSort(v); case 4:shellSort(v); case 5: heapSort(v); case 6: mergeSort(v); case 7: quickSort(v); case 8: countSort(v); case 9: radixSort(v); default:break; } cout<<" After sort:"<<endl; for(int i =0;i<v.size();i++) cout<<setw(5)<<v[i]; cout<<endl; } system("pause"); } /*****************************************************************/ /* 冒泡排序基本思想是:两两比较相邻记录的关键字,如果反序则交换 *时间复杂度最好的情况为O(n),最坏的情况是O(n^2);是一种稳定的排序算法 */ template <class Comparable> void bubbleSort(vector<Comparable> &a)//冒泡 { for(int i = 1;i<a.size();i++) { for(int j = 0;j<a.size()-i;j++) { if(a[j]>a[j+1]) swap(a[j],a[j+1]); } } } /**************************************************************************/ /**************************************************************************/ /*插入排序基本思想: 将一个记录插入到前面已经排好序的序列中, 从而得到一个新的,记录数增1的序列 * 时间复杂度也为O(n^2), 若列表基本有序,则插入排序比冒泡、选择更有效率 */ template<typename Comparable> void insertSort(vector<Comparable> &a)//插入 { insertSort(a,0,a.size()-1); } template<typename Comparable> void insertSort(vector<Comparable> &a, int left, int right)//插入实现,将在快排中用到 { for(int i = left+1;i<right-left+1;i++) { int tmp = a[i]; int j; for(j=i-1;j>=i &&tmp<a[j];j--) a[j+1]=a[j]; a[j+1]=tmp; } } /**************************************************************************/ /**************************************************************************/ /* 选择排序基本思想:就是通过n-i次比较,从n-i+1个记录中选择关键字最小的记录,并和第i(1<=i<=n)个记录交换。 * 时间复杂度也为O(n^2),但选择排序的性能要略优于冒泡排序 */ template<typename Comparable> void selectSort(vector<Comparable> &a)//选择 { for(int i=0;i<a.size();i++) { int pos = i; int min = a[i]; for(int j = i+1;j<a.size();j++) { if(a[j]<min) { min = a[j]; pos = j; } } swap(a[i],a[pos]); } } /**************************************************************************/ /*希尔排序基本思想:间隔一定增量的元素进行排序,一次见效增量值直到1 *效率估计O(nlog2^n)~O(n^1.5),取决于增量值的最初大小。建议使用质数作为增量值,本程序并未如此实现 /**************************************************************************/ template<typename Comparable> void shellSort(vector<Comparable> &a)//希尔 { for(int gap = a.size()/2;gap>0;gap/=2) { for(int i=gap;i<a.size();i++) { int tmp = a[i]; int j=i; for( ; j>=gap&&tmp<a[j-gap];j-=gap) a[j]=a[j-gap]; a[j]=tmp; } } } /**************************************************************************/ /**************************************************************************/ /*通过构造最大堆,并依次交换最大元素与末尾元素实现排序 *时间复杂度为 O(nlogn) */ template<typename Comparable> void heapSort(vector<Comparable> &a)//堆排序 { for(int i=a.size()/2;i>=0;i--)//构造最大堆 percDown(a,i,a.size()); for(int j = a.size()-1;j>0;j--) { swap(a[0],a[j]); percDown(a,0,j); } } int leftChild(int i) { return i*2+1; } template<typename Comparable> void percDown(vector<Comparable> &a,int i,int n) { int child; int tmp;//存较小的值 for(tmp = a[i];leftChild(i)<n;i=child) { child = leftChild(i); if(child!=n-1 && a[child]<a[child+1]) child++; if(tmp<a[child]) a[i]=a[child]; else break; } a[i]=tmp; } /********************************************************************************/ /********************************************************************************/ /*通过递归实现,将已经有序的两个序列合并为一个序列,该方法对空间的要求较高 * 时间复杂度为O(nlogn),空间复杂度为O(n+logn) */ template<typename Comparable> void mergeSort(vector<Comparable> &a)//归并排序 { vector<Comparable> tmpArray(a.size());//临时存储数组 mergeSort(a,tmpArray,0,a.size()-1); } template<typename Comparable> void mergeSort(vector<Comparable> &a, vector<Comparable> &tmpArray, int left, int right)//归并排序递归调用部分 { if(left<right) { int center = (left + right)/2; mergeSort(a,tmpArray,left,center); mergeSort(a,tmpArray,center+1,right); merge(a,tmpArray,left,center+1,right); } } template<typename Comparable> void merge(vector<Comparable> &a, vector<Comparable> &tmpArray, int leftPos, int rightPos, int rightEnd)//归并排序合并部分 { int leftEnd = rightPos-1; int tmpPos = leftPos; int numElements= rightEnd - leftPos +1; while(leftPos<=leftEnd && rightPos<=rightEnd) { if(a[leftPos]<a[rightPos]) tmpArray[tmpPos++]=a[leftPos++]; else tmpArray[tmpPos++]=a[rightPos++]; } while(leftPos<=leftEnd) tmpArray[tmpPos++]=a[leftPos++]; while(rightPos<=rightEnd) tmpArray[tmpPos++]=a[rightPos++]; for(int i=0;i<numElements;i++,rightEnd--) a[rightEnd]=tmpArray[rightEnd]; } /********************************************************************************/ /********************************************************************************/ /*快速排序基本思想:通过递归实现,选定一个枢纽元素,对待排序序列进行分割, 分割之后的序列一个部分小于枢纽元素,一个部分大于枢纽元素,再对这两个分割好的子序列进行上述的过程。 平均时间复杂度O(nlogn) */ template<typename Comparable> void quickSort(vector<Comparable> &a)//快速排序 { quickSort(a,0,a.size()-1); } template<typename Comparable> void quickSort(vector<Comparable> &a,int left, int right)//快速排序实现 { if(left+10<=right) { Comparable pivot = median3(a,left,right);//确定枢纽元 int i =left,j=right-1; for( ; ; ) { while(a[++i]<pivot){}//找到左边首个不小于pivot的值 while(a[--j]>pivot){}//找到右边首个不大于pivot的值 if(i<j) swap(a[i],a[j]); else break; } swap(a[i],a[right-1]); quickSort(a,left,i-1); quickSort(a,i+1,right); } else insertSort(a,left,right); } template<typename Comparable> const Comparable &median3(vector<Comparable> &a,int left,int right) { int center = (left+right)/2; if(a[left]>a[center]) swap(a[left],a[center]); if(a[left]>a[right]) swap(a[left],a[right]); if(a[center]>a[right]) swap(a[center],a[right]);//交换后大小顺序为左<中<右 swap(a[center],a[right-1]);//枢纽元放在a[right-1]位置 return a[right-1]; } /********************************************************************************/ /********************************************************************************/ /*计数排序基本思想:通过一个额外的count数据记录出每个元素的个数,并计算出应该出现的位置,从而实现排序 *该方法不基于比较 */ template<typename Comparable> void countSort(vector<Comparable> &a)//计数排序 { Comparable min,max; findMinMax(a,a.size(),&min,&max); int numElements = max-min+1; //跨度范围 vector<Comparable> count(numElements,int(0)); for(int i = 0;i<a.size();i++)//计数 { count[a[i]-min]++; } for(int i=0,j=0;i<numElements;i++)//重写原数组 { while(count[i]>0) { a[j++]=i+min; --count[i]; } } } template<typename Comparable> void findMinMax(vector<Comparable> &a,int size,Comparable *min,Comparable *max) { if(size==0) return; else if(size==1) { *min = *max = a[0]; return; } else { *min = a[0]<a[1]?a[0]:a[1]; *max = a[0]>a[1]?a[0]:a[1]; Comparable tmpMin; Comparable tmpMax; int i,j; for(i = 2,j = 3 ; i<size&&j<size ;i+=2,j+=2) { tmpMin = a[i]<a[j]?a[i]:a[j]; tmpMax = a[i]>a[j]?a[i]:a[j]; if(tmpMin<*min) *min = tmpMin; if(tmpMax>*max) *max = tmpMax; } if(size%2!=0) { if(a[size -1] > *max) *max = a[size - 1]; else if(a[size -1] < *min) *min = a[size -1]; } } } /********************************************************************************/ /********************************************************************************/ /*基数排序基本思想:对于int型而言,可以解释为一次一句百位、十位、个位进行分组,组内递归调用进行排序 */ template<typename Comparable> void radixSort(vector<Comparable> &a)//基数排序 { radixSort(a,0,a.size()-1,3); } template<typename Comparable> void radixSort(vector<Comparable> &a,int left,int right,int d) { int i,j,radix=10,p1,p2; vector<Comparable> count(radix,int(0));//计数数组 vector<Comparable> auxArray(right-left+1);//辅助数组 if(d<=0)//递归截止条件 return; for(i=left;i<=right;i++) count[getDigit(a[i],d)]++; for(j=1;j<radix;j++) count[j]+=count[j-1]; for(i=left;i<=right;i++) { j=getDigit(a[i],d); auxArray[count[j]-1]=a[i]; count[j]--; } for(i=left,j=0;i<=right;i++,j++)//辅助数组元素写入原数组 { a[i]=auxArray[j]; } for(j=0;j<radix;j++) { p1=count[j]+left; if(j==radix-1) p2=right; else p2=count[j+1]-1+left; if(p1<p2) radixSort(a,p1,p2,d-1); } } int getDigit(int a,int d)//返回指定位的值,个位为d=1,以此类推 { int tmp=1; for(int i=0;i<d-1;i++) tmp*=10; return (a / tmp)%10; }