C++排序:冒泡排序,简单选择排序,直接插入排序,希尔排序,堆排序,归并排序,快速排序
1、排序的稳定性:
假设 Ki=Kj (1≤i≤n,1≤j≤n,i≠j),在排序前的序列中 i<j,如果排序后 i 仍然领先于 j ,则所用排序方法稳定;反之若可能使排序后序列 j 领先 i,则所用排序方法不稳 定。
2、内排序与外排序
内排序是在排序整个过程中,待排序的所有记录全部被放置在内存中;外排序是由于排序的记录个数太多,不能同时放置在内存,整个排序过程需要在内外村之间多次交换 数据才行。
1)对于内排序,排序算法的性能主要受3个方面影响:1.时间性能;2.辅助空间(辅助存储空间);3)算法的复杂性(算法本身的复杂度)。
2)根据排序过程中借助的主要操作,内排序分为:插入排序、交换排序、选择排序、归并排序。
3)根据算法的复杂度分为两大类:1.简单算法:冒泡排序、简单选择排序、直接插入排序;2.改进算法:希尔排序、堆排序、归并排序、快速排序。
//按顺序输出数组 void print(int a[], int n) { for(int i=0;i<n;i++) { cout<< a[i] <<" "; } cout<<endl; } //数组两元素的交换 void swap(int a[], int i, int j) { int temp = a[i]; a[i] = a[j]; a[j] = temp; }
1.冒泡排序:
//对数组a[]作交换排序(冒泡排序初级版) void BubbleSort0(int a[], int n) { for(int i=0;i<n-1;i++) { for(int j=i+1;j<n;j++) { if(a[i]>a[j]) swap(a,i,j); } } } //冒泡排序 void BubbleSort(int a[], int n) { for(int i=0;i<n-1;i++) { for(int j=n-1;j>i;j--) { if(a[j]<a[j-1]) swap(a,j,j-1); } } } //改进冒泡算法 void BubbleSort2(int a[], int n) { int flag = 1;//flag做为标记 for(int i=0;i<n-1&&flag==1;i++) { flag = 0; for(int j=n-1;j>i;j--) { if(a[j]<a[j-1]) { swap(a,j,j-1); flag = 1;//有数据交换则flag为1 } } } }
2.简单选择排序:
//简单选择排序 void SelectSort(int a[], int n) { int min; for(int i=0;i<n-1;i++) { min = i; for(int j=i+1;j<n;j++) { if(a[min]>a[j]) min = j; } if(i != min) swap(a,i,min); } }
3.直接插入排序:
//直接插入排序 void InsertSort(int a[],int n) { for(int i=1;i<n;i++) { if(a[i]<a[i-1]) { int temp = a[i]; int j; for(j=i-1;a[j]>temp;j--) { a[j+1] = a[j]; } a[j+1] = temp; } } }
4.希尔排序:
//希尔排序 void ShellSort(int a[], int n) { int num = n; int x; do { num = num/3 +1; for(int i=num;i<n;i++) { if(a[i]<a[i-num]) { x = a[i]; int j=i-num; for(;j>=0&&x<a[j];j-=num) a[j+num] = a[j]; a[j+num] = x; } } } while(num>1); }
5.堆排序:
1 //堆排序 2 //使a[s,m]成为一个大顶堆 3 //若根结点存在序号0处, i结点的父结点下标就为(i-1)/2, 4 //i结点的左右子结点下标分别为2*i+1和2*i+2 5 //如果根结点是从1开始,则左右孩子结点分别是2i和2i+1 6 void HeadAdjust(int a[], int s, int m) 7 { 8 int temp = a[s]; 9 for(int j=2*s+1; j<=m; j*=2) 10 { 11 if(j<m && a[j]<a[j+1]) 12 j++; 13 if(temp>=a[j]) 14 break; 15 a[s] = a[j]; 16 s = j; 17 } 18 a[s] = temp; 19 } 20 //对数组a进行堆排序 21 void HeadSort(int a[], int n) 22 { 23 for(int i=n/2;i>=0;i--) 24 HeadAdjust(a,i,n); 25 for(int i=n-1;i>0;i--) 26 { 27 swap(a,0,i); 28 HeadAdjust(a,0,i-1); 29 } 30 }
6.归并排序:
1)递归实现:
//归并排序 //将有序的SR[i..m]和SR[m+1..n]归并为有序的TR[i..n] void Merge(int SR[], int TR[], int i, int m, int n) { int j,k,x; for(j=m+1,k=i; i<=m && j<=n; k++) { if(SR[i] < SR[j]) TR[k] = SR[i++]; else TR[k] = SR[j++]; } while(i<=m) { TR[k++] = SR[i++]; } while(j<=n) { TR[k++] = SR[j++]; } } //将SR[s..t]归并排序为TR1[s..t] void MSort(int SR[], int TR1[], int s, int t) { int m; int TR2[20]; if(s==t) TR1[s]=SR[s]; else { m = (s+t)/2; MSort(SR,TR2,s,m); MSort(SR,TR2,m+1,t); Merge(TR2,TR1,s,m,t); } } //对数组a[]进行归并排序 void MergeSort(int a[], int b[], int n) { MSort(a,b,0,n-1); }
2)非递归实现:
7.快速排序:
1)
//交换数组a[]中子集的记录,使枢轴记录到位,并返回其所在位置 //此时在它之前(后)的记录均不大(小)于它 int Partition(int a[], int low, int high) { int pivotkey = a[low]; while(low<high) { while(low<high && a[high]>=pivotkey) high--; swap(a,low,high); while(low<high && a[low]<=pivotkey) low++; swap(a,low,high); } return low; } //对数组a[]在子集a[low..high]作快速排序 void QSort(int a[], int low, int high) { if(low<high) { int pivot = Partition(a,low,high); QSort(a,low,pivot-1); QSort(a,pivot+1,high); } } //对数组a[]作快速排序 void QuickSort(int a[], int n) { QSort(a,0,n-1); }
2)优化小数组时的排序方案(如果数组非常小时,快速排序反而不如直接插入排序来的更好):
//优化小数组时的排序方案 const int MAX_LENGTH_INSERT_SORT = 7; void QSort1(int a[], int low, int high) { if((high-low)>MAX_LENGTH_INSERT_SORT) { int pivot = Partition(a,low,high); QSort(a,low,pivot-1); QSort(a,pivot+1,high); } else InsertSort(a,high-low+1); }
3)优化递归操作:
//优化递归操作 void QSort2(int a[], int low, int high) { if((high-low)>MAX_LENGTH_INSERT_SORT) { while(low<high) { int pivot = Partition(a,low,high); QSort2(a,low,pivot-1); low = pivot+1; } } else InsertSort(a,high-low+1); }
3)优化选取枢轴和不必要交换:
//优化选取枢轴和不必要交换 int Partition1(int a[], int low, int high) { //优化选取枢轴 int m = low+(high-low)/2; if(a[low]>a[high]) swap(a,low,high); if(a[m]>a[high]) swap(a,high,m); if(a[m]>a[low]) swap(a,m,low); int pivotkey = a[low]; int flag = pivotkey;//枢轴备份到flag while(low<high) { while(low<high && a[high]>=pivotkey) high--; a[low] = a[high];//采用替换而不是交换的方式 while(low<high && a[low]<=pivotkey) low++; a[high] = a[low];//采用替换而不是交换的方式 } a[low] = flag;//将枢轴数值替换回a[low] return low; }