各种排序算法的C++实现
这篇文章的源码是大二时数据结构课的实验。当时的实验目的是比较各种排序算法的性能。现在感觉其中的排序源码还比较有用,就贴出来了。
minheap.h 用于堆排序
//使用时注意将关键码加入 #ifndef MINHEAP_H #define MINHEAP_H #include <assert.h> #include <iostream> using std::cout; using std::cin; using std::endl; using std::cerr; #include <stdlib.h> //const int maxPQSize = 50; template <class Type> class MinHeap { public: MinHeap ( int maxSize );//根据最大长度建堆 MinHeap ( Type arr[], int n );//根据数组arr[]建堆 ~MinHeap ( ) { delete [] heap; } const MinHeap<Type> & operator = ( const MinHeap &R );//重载赋值运算符 int Insert ( const Type &x );//插入元素 int RemoveMin ( Type &x );//移除关键码最小的元素,并赋给x int IsEmpty ( ) const { return CurrentSize == 0; }//检查堆是否为空 int IsFull ( ) const { return CurrentSize == MaxHeapSize; }//检查对是否满 void MakeEmpty ( ) { CurrentSize = 0; }//使堆空 private: enum { DefaultSize = 50 };//默认堆的大小 Type *heap; int CurrentSize; int MaxHeapSize; void FilterDown ( int i, int m );//自上向下调整堆 void FilterUp ( int i );//自下向上调整堆 }; template <class Type> MinHeap <Type>::MinHeap ( int maxSize ) { //根据给定大小maxSize,建立堆对象 MaxHeapSize = (DefaultSize < maxSize ) ? maxSize : DefaultSize; //确定堆大小 heap = new Type [MaxHeapSize]; //创建堆空间 CurrentSize = 0; //初始化 } template <class Type> MinHeap <Type>::MinHeap ( Type arr[], int n ) { //根据给定数组中的数据和大小,建立堆对象 MaxHeapSize = DefaultSize < n ? n : DefaultSize; heap = new Type [MaxHeapSize]; if(heap==NULL){cerr <<"fail" <<endl;exit(1);} for(int i =0; i< n; i++) heap[i] = arr[i]; //数组传送 CurrentSize = n; //当前堆大小 int currentPos = (CurrentSize-2)/2; //最后非叶 while ( currentPos >= 0 ) { //从下到上逐步扩大,形成堆 FilterDown ( currentPos, CurrentSize-1 ); currentPos-- ; //从currentPos开始,到0为止, 调整currentPos--; } } } template <class Type> void MinHeap<Type>::FilterDown ( const int start, const int EndOfHeap ) { // 结点i的左、右子树均为堆,调整结点i int i = start, j = 2*i+1; // j 是 i 的左子女 Type temp = heap[i]; while ( j <= EndOfHeap ) { if ( j < EndOfHeap && heap[j] > heap[j+1] ) j++;//两子女中选小者 if ( temp<= heap[j] ) break; else { heap[i] = heap[j]; i = j; j = 2*j+1; } } heap[i] = temp; } template <class Type> int MinHeap<Type>::Insert ( const Type &x ) { //在堆中插入新元素 x if ( CurrentSize == MaxHeapSize ) //堆满 { cout << "堆已满" << endl; return 0; } heap[CurrentSize] = x; //插在表尾 FilterUp (CurrentSize); //向上调整为堆 CurrentSize++; //堆元素增一 return 1; } template <class Type> void MinHeap<Type>::FilterUp ( int start ) { //从 start 开始,向上直到0,调整堆 int j = start, i = (j-1)/2; // i 是 j 的双亲 Type temp = heap[j]; while ( j > 0 ) { if ( (heap[i].root->data.key )<= (temp.root->data.key) ) break; else { heap[j] = heap[i]; j = i; i = (i -1)/2; } } heap[j] = temp; } template <class Type> int MinHeap <Type>::RemoveMin ( Type &x ) { if ( !CurrentSize ) { cout << "堆已空 " << endl; return 0; } x = heap[0]; //最小元素出队列 heap[0] = heap[CurrentSize-1]; CurrentSize--; //用最小元素填补 FilterDown ( 0, CurrentSize-1 ); //从0号位置开始自顶向下调整为堆 return 1; } #endif
sort.cpp 主要的排序函数集包括冒泡排序、快速排序、插入排序、希尔排序、计数排序
//n^2 //冒泡排序V[n]不参与排序 void BubbleSort (int V[], int n ) { bool exchange; //设置交换标志置 for ( int i = 0; i < n; i++ ){ exchange=false; for (int j=n-1; j>i; j--) { //反向检测,检查是否逆序 if (V[j-1] > V[j]) //发生逆序,交换相邻元素 { int temp=V[j-1]; V[j-1]=V[j]; V[j]=temp; exchange=true;//交换标志置位 } } if (exchange == false) return; //本趟无逆序,停止处理 } } //插入排序,L[begin],L[end]都参与排序 void InsertionSort ( int L[], const int begin, const int end) { //按关键码 Key 非递减顺序对表进行排序 int temp; int i, j; for ( i = begin; i < end; i++ ) { if (L[i]>L[i+1]) { temp = L[i+1]; j=i; do { L[j+1]=L[j]; if(j == 0) { j--; break; } j--; } while(temp<L[j]); L[j+1]=temp; } } } //n*logn //快速排序A[startingsub],A[endingsub]都参与排序 void QuickSort( int A[], int startingsub, int endingsub) { if ( startingsub >= endingsub ) ; else{ int partition; int q = startingsub; int p = endingsub; int hold; do{ for(partition = q ; p > q ; p--){ if( A[q] > A[p]){ hold = A[q]; A[q] = A[p]; A[p] = hold; break; } } for(partition = p; p > q; q++){ if(A[p] < A[q]){ hold = A[q]; A[q] = A[p]; A[p] = hold; break; } } }while( q < p ); QuickSort( A, startingsub, partition - 1 ); QuickSort( A, partition + 1, endingsub ); } } //希尔排序,L[left],L[right]都参与排序 void Shellsort( int L[], const int left, const int right) { int i, j, gap=right-left+1; //增量的初始值 int temp; do{ gap=gap/3+1; //求下一增量值 for(i=left+gap; i<=right; i++) //各子序列交替处理 if( L[i]<L[i-gap]){ //逆序 temp=L[i]; j=i-gap; do{ L[j+gap]=L[j]; //后移元素 j=j-gap; //再比较前一元素 }while(j>left&&temp<L[j]); L[j+gap]=temp; //将vector[i]回送 } }while(gap>1); } //n //计数排序,L[n]不参与排序 void CountingSort( int L[], const int n ) { int i,j; const int k =1001; int tmp[k]; int *R; R = new int[n]; for(i=0;i<k;i++) tmp[i]= 0; for(j=0;j<n;j++) tmp[L[j]]++; //执行完上面的循环后,tmp[i]的值是L中等于i的元素的个数 for(i=1;i<k;i++) tmp[i]=tmp[i]+tmp[i-1]; //执行完上面的循环后, //tmp[i]的值是L中小于等于i的元素的个数 for(j=n-1;j>=0;j--) //这里是逆向遍历,保证了排序的稳定性 { R[tmp[L[j]]-1] = L[j]; //L[j]存放在输出数组R的第tmp[L[j]]个位置上 tmp[L[j]]--; //tmp[L[j]]表示L中剩余的元素中小于等于L[j]的元素的个数 } for(j=0;j<n;j++) L[j] = R[j]; } //基数排序 void printArray( const int Array[], const int arraySize ); int getDigit(int num, int dig); const int radix=10; //基数 void RadixSort(int L[], int left, int right, int d){ //MSD排序算法的实现。从高位到低位对序列划分,实现排序。d是第几位数,d=1是最低位。left和right是待排序元素子序列的始端与尾端。 int i, j, count[radix], p1, p2; int *auxArray; int M = 5; auxArray = new int[right-left+1]; if (d<=0) return; //位数处理完递归结束 if (right-left+1<M){//对于小序列可调用直接插入排序 InsertionSort(L,left,right); return; } for (j=0; j<radix; j++) count[j]=0; for (i=left; i<=right; i++) //统计各桶元素的存放位置 count[getDigit(L[i],d)]++; for (j=1; j<radix; j++) //安排各桶元素的存放位置 count[j]=count[j]+count[j-1]; for (i=right; i>=left; i--){ //将待排序序列中的元素按位置分配到各个桶中,存于助数组auxArray中 j=getDigit(L[i],d); //取元素L[i]第d位的值 auxArray[count[j]-1]=L[i]; //按预先计算位置存放 count[j]--; //计数器减1 } for (i=left, j=0; i<=right; i++, j++) L[i]=auxArray[j]; //从辅助数组顺序写入原数组 delete []auxArray; for (j=0; j<radix; j++){ //按桶递归对d-1位处理 p1=count[j]+left; //取桶始端,相对位置,需要加上初值$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$ (j+1 <radix )?(p2=count[j+1]-1+left):(p2=right) ; //取桶尾端 // delete []count; if(p1<p2){ RadixSort(L, p1, p2, d-1); //对桶内元素进行基数排序 // printArray(L,10); } } } int getDigit(int num, int dig) { int myradix = 1; /* for(int i = 1;i<dig;i++) { myradix *= radix; }*/ switch(dig) { case 1: myradix = 1; break; case 2: myradix = 10; break; case 3: myradix = 1000; break; case 4: myradix = 10000; break; default: myradix = 1; break; } return (num/myradix)%radix; }
maintest.cpp 测试例子
#include<iostream> using std::cout; using std::cin; using std::endl; #include <cstdlib> #include <ctime> #include<iostream> using std::cout; using std::cin; using std::ios; using std::cerr; using std::endl; #include<iomanip> using std::setw; using std::fixed; #include<fstream> using std::ifstream; using std::ofstream; using std::flush; #include<string> using std::string; #include <stdio.h> #include <stdlib.h> #include <time.h> #include"minheap.h" void BubbleSort(int arr[], int size);//冒泡排序 void QuickSort( int A[], int startingsub, int endingsub);//快速排序 void InsertionSort ( int L[], const int begin,const int n);//插入排序 void Shellsort( int L[], const int left, const int right);//希尔排序 void CountingSort( int L[], const int n );//计数排序 int getDigit(int num, int dig);//基数排序中获取第dig位的数字 void RadixSort(int L[], int left, int right, int d);//基数排序 void printArray( const int Array[], const int arraySize );//输出数组 int main() { clock_t start, finish; double duration; /* 测量一个事件持续的时间*/ ofstream *ofs; string fileName = "sortResult.txt"; ofs = new ofstream(fileName.c_str(),ios::out|ios::app); const int size = 100000; int a[size]; int b[size]; srand(time(0)); ofs->close(); for(int i = 0; i < 20;i++) { ofs->open(fileName.c_str(),ios::out|ios::app); if( ofs->fail()){ cout<<"!!"; ofs->close(); } for(int k =0; k <size;k++) { a[k] = rand()%1000; b[k] = a[k]; } /* for( k =0; k <size;k++) { a[k] = k; b[k] = a[k]; } */ //printArray(a,size); //计数排序 for( k =0; k <size;k++) { a[k] = b[k]; } start = clock(); CountingSort(a,size); finish = clock(); // printArray(a,size); duration = (double)(finish - start) / CLOCKS_PER_SEC; printf( "%s%f seconds\n", "计数排序:",duration ); *ofs<<"第"<<i<<"次:\n " <<"排序内容:0~999共" << size << " 个整数\n" ; *ofs<<"第"<<i<<"次计数排序:\n " <<" Time: " <<fixed<< duration << " seconds\n"; //基数排序 for( k =0; k <size;k++) { a[k] = b[k]; } start = clock(); RadixSort(a, 0,size-1, 3); finish = clock(); // printArray(a,size); duration = (double)(finish - start) / CLOCKS_PER_SEC; printf( "%s%f seconds\n", "基数排序:",duration ); *ofs<<"第"<<i<<"次基数排序:\n " <<" Time: " << duration << " seconds\n"; //堆排序 MinHeap<int> mhp(a,size); start = clock(); for( k =0; k <size;k++) { mhp.RemoveMin(a[k]); } finish = clock(); // printArray(a,size); duration = (double)(finish - start) / CLOCKS_PER_SEC; printf( "%s%f seconds\n", "堆排序:",duration ); *ofs<<"第"<<i<<"次堆排序:\n " <<" Time: " << duration << " seconds\n"; //快速排序 for( k =0; k <size;k++) { a[k] = b[k]; } //printArray(a,size); start = clock(); QuickSort(a,0,size-1); finish = clock(); // printArray(a,size); duration = (double)(finish - start) / CLOCKS_PER_SEC; printf( "%s%f seconds\n", "快速排序:",duration ); *ofs<<"第"<<i<<"次快速排序:\n " <<" Time: " << duration << " seconds\n"; //希尔排序 for( k =0; k <size;k++) { a[k] = b[k]; } start = clock(); Shellsort(a,0,size-1); finish = clock(); // printArray(a,size); duration = (double)(finish - start) / CLOCKS_PER_SEC; printf( "%s%f seconds\n", "希尔排序:",duration ); *ofs<<"第"<<i<<"次希尔排序:\n " <<" Time: " << duration << " seconds\n"; //插入排序 for( k =0; k <size;k++) { a[k] = b[k]; } start = clock(); InsertionSort (a,0,size-1); finish = clock(); // printArray(a,size); duration = (double)(finish - start) / CLOCKS_PER_SEC; printf( "%s%f seconds\n", "插入排序:",duration ); *ofs<<"第"<<i<<"次插入排序:\n " <<" Time: " << duration << " seconds\n"; //冒泡排序 for( k =0; k <size;k++) { a[k] = b[k]; } start = clock(); BubbleSort(a,size); finish = clock(); // printArray(a,size); duration = (double)(finish - start) / CLOCKS_PER_SEC; printf( "%s%f seconds\n", "冒泡排序:",duration ); *ofs<<"第"<<i<<"次冒泡排序:\n " <<" Time: " << duration << " seconds\n"; ofs->close(); } return 0; } void printArray( const int Array[], const int arraySize ) { for( int i = 0; i < arraySize; i++ ) { cout << Array[ i ] << " "; if ( i % 20 == 19 ) cout << endl; } cout << endl; }
最后贴一下运行结果和当时的实验统计结果
实验结果 排序算法性能仿真 |
|||||||
排序内容:从0~999中随机产生,共100000 个整数,该表中单位为秒 |
|||||||
次数 |
计数排序 |
基数排序 |
堆排序 |
快速排序 |
希尔排序 |
直接插入排序 |
冒泡排序 |
1 |
0.0000 |
0.0310 |
0.0470 |
0.0470 |
0.0310 |
14.7970 |
58.0930 |
2 |
0.0000 |
0.0470 |
0.0310 |
0.0470 |
0.0470 |
16.2500 |
53.3280 |
3 |
0.0000 |
0.0310 |
0.0310 |
0.0310 |
0.0310 |
14.4850 |
62.4380 |
4 |
0.0000 |
0.0320 |
0.0320 |
0.0470 |
0.0310 |
17.1090 |
61.8440 |
5 |
0.0000 |
0.0310 |
0.0470 |
0.0470 |
0.0310 |
16.9380 |
62.3280 |
6 |
0.0000 |
0.0310 |
0.0310 |
0.0470 |
0.0310 |
16.9380 |
57.7030 |
7 |
0.0000 |
0.0310 |
0.0470 |
0.0310 |
0.0310 |
16.8750 |
61.9380 |
8 |
0.0150 |
0.0470 |
0.0310 |
0.0470 |
0.0320 |
17.3910 |
62.8600 |
9 |
0.0000 |
0.0320 |
0.0470 |
0.0460 |
0.0310 |
16.9530 |
62.2660 |
10 |
0.0000 |
0.0470 |
0.0310 |
0.0470 |
0.0310 |
17.0160 |
60.1410 |
11 |
0.0000 |
0.0930 |
0.0780 |
0.0320 |
0.0310 |
14.6090 |
54.6570 |
12 |
0.0000 |
0.0310 |
0.0320 |
0.0310 |
0.0310 |
15.0940 |
62.3430 |
13 |
0.0000 |
0.0310 |
0.0310 |
0.0470 |
0.0310 |
17.2340 |
61.9530 |
14 |
0.0000 |
0.0320 |
0.0470 |
0.0470 |
0.0310 |
16.9060 |
61.0620 |
15 |
0.0000 |
0.0320 |
0.0320 |
0.0460 |
0.0320 |
16.7810 |
62.5310 |
16 |
0.0000 |
0.0470 |
0.0470 |
0.0620 |
0.0310 |
17.2350 |
57.1720 |
17 |
0.0150 |
0.0160 |
0.0320 |
0.0470 |
0.0310 |
14.1400 |
52.0320 |
18 |
0.0150 |
0.0160 |
0.0310 |
0.0310 |
0.0310 |
14.1100 |
52.3590 |
19 |
0.0000 |
0.0310 |
0.0320 |
0.0460 |
0.0320 |
14.1090 |
51.8750 |
20 |
0.0000 |
0.0310 |
0.0320 |
0.0460 |
0.0320 |
14.0780 |
52.4840 |
21 |
0.0150 |
0.0780 |
0.0470 |
0.0470 |
0.0310 |
16.3750 |
59.5150 |
22 |
0.0000 |
0.0310 |
0.0310 |
0.0470 |
0.0320 |
16.8900 |
60.3440 |
23 |
0.0000 |
0.0310 |
0.0310 |
0.0310 |
0.0310 |
16.3440 |
60.0930 |
24 |
0.0000 |
0.0310 |
0.0310 |
0.0470 |
0.0310 |
16.3440 |
60.5780 |
25 |
0.0000 |
0.0320 |
0.0470 |
0.0470 |
0.0470 |
16.3590 |
59.7810 |
26 |
0.0160 |
0.0470 |
0.0310 |
0.0470 |
0.0310 |
16.1250 |
61.0620 |
27 |
0.0000 |
0.0310 |
0.0470 |
0.0470 |
0.0310 |
16.7810 |
59.6100 |
28 |
0.0150 |
0.0320 |
0.0320 |
0.0470 |
0.0310 |
16.9220 |
56.8130 |
29 |
0.0000 |
0.0310 |
0.0310 |
0.0310 |
0.0310 |
15.0790 |
57.8120 |
30 |
0.0000 |
0.0310 |
0.0320 |
0.0460 |
0.0320 |
14.7810 |
58.8280 |
31 |
0.0000 |
0.0310 |
0.0310 |
0.0470 |
0.0310 |
15.8590 |
59.1400 |
32 |
0.0000 |
0.0470 |
0.0320 |
0.0310 |
0.0310 |
16.0940 |
59.1560 |
33 |
0.0000 |
0.0470 |
0.0310 |
0.0310 |
0.0310 |
15.9850 |
59.1400 |
34 |
0.0000 |
0.0310 |
0.0310 |
0.0470 |
0.0320 |
16.0150 |
59.2500 |
35 |
0.0000 |
0.0310 |
0.0470 |
0.0470 |
0.0310 |
16.7660 |
57.9840 |
36 |
0.0000 |
0.0310 |
0.0320 |
0.0470 |
0.0310 |
15.3750 |
59.0470 |
37 |
0.0000 |
0.0320 |
0.0460 |
0.0470 |
0.0320 |
16.0310 |
58.9060 |
38 |
0.0000 |
0.0310 |
0.0310 |
0.0470 |
0.0310 |
15.9530 |
57.2650 |
39 |
0.0160 |
0.0310 |
0.0470 |
0.0470 |
0.0310 |
15.9530 |
57.5160 |
40 |
0.0150 |
0.0310 |
0.0320 |
0.0470 |
0.0310 |
14.7030 |
56.6710 |
平均值 |
0.0031 |
0.0360 |
0.0372 |
0.0437 |
0.0320 |
15.9946 |
58.7480 |
最小值 |
0.0000 |
0.0160 |
0.0310 |
0.0310 |
0.0310 |
14.0780 |
51.8750 |
最大值 |
0.0160 |
0.0930 |
0.0780 |
0.0620 |
0.0470 |
17.3910 |
62.8600 |