说明: 常见的排序算法都是比较排序,非比较排序包括计数排序、桶排序和基数排序,非比较排序对数据有要求,因为数据本身包含了定位特征,所有才能不通过比较来确定元素的位置。比较排序的时间复杂度通常为O(n2)或者O(nlogn),比较排序的时间复杂度下界就是O(nlogn),而非比较排序的时间复杂度可以达到O(n),但是都需要额外的空间开销。本文将介绍的是各种比较排序算法:
一. 各种排序算法的比较:
二. 未优化的冒泡选择排序法
1.选择排序法
1 void sortlist1(int *arr,int n) 2 { 3 for(int i = 0;i < n-1;i++) 4 { 5 for(int j = i+1;j < n;j++) 6 { 7 if(arr[i] > arr[j]) 8 { 9 arr[i] ^= arr[j]; 10 arr[j] ^= arr[i]; 11 arr[i] ^= arr[j]; 12 } 13 } 14 } 15 }
2.冒泡排序法
1 void sortlist2(int *arr,int n) 2 { 3 for(int i = 0;i < n-1;i++) 4 { 5 for(int j = 0;j < n-1-i;j++) 6 { 7 if(arr[j] > arr[j+1]) 8 { 9 arr[j] ^= arr[j+1]; 10 arr[j+1] ^= arr[j]; 11 arr[j] ^= arr[j+1]; 12 } 13 } 14 } 15 }
三.优化冒泡选择两种排序方法
1.选择排序法的优化(以从小到大的排列顺序为例)
从上面的代码可知,选择排序法的思想是让第 i(i 从0开始) 个元素分别与其后面的每个元素进行比较,当比较结果为大于时,就进行交换,这样比较一轮下来,第i个元素成了此轮比较中的最小元素,再继续比较完所有轮,就实现了数组从小到大的排列。这样的排列使得选择排序法的交换次数过于多,降低了排序效率。所以,对选择排序法的优化方案就是:比而不换,记录下标!
1 void sortlist(int *p,int n) 2 { 3 for(int i = 0;i<n;i++) 4 { 5 int idx = i; 6 for(int j = i+1;j<n;j++) 7 { 8 if(p[idx] > p[j]) 9 idx = j; 10 } 11 if(idx != i) 12 { 13 p[idx] ^= p[i]; 14 p[i] ^= p[idx]; 15 p[idx] ^= p[i]; 16 } 17 } 18 }
如上代码,每次内重循环之后,idx记录本次循环中比较的最小值或最大值(此处为最小值),若idx != i,则说明 i 并不是这次比较的最大或最小值,则进行交换,结束本次循环。
2.冒泡排序法优化(以从小到大为例)
冒泡排序法的思想是每轮用第 j(j从0开始) 个元素与第 j+1个元素进行比较,如果大于则交换;这样一轮下来,最大的元素就像冒泡一样到了最后,这样继续比较完所有轮,就实现了冒泡从小到大排序。由此可见,对于冒泡排序法,当某一轮中没有发生过元素的交换时,则表明整个元素序列已经有序了,从而不需要在比较下去。因此,冒泡排序的优化方案为:序而不排。
1 void sortlist2(int *p,int n) 2 { 3 for(int i = 0;i<n;i++) 4 { 5 int flag = 0; 6 for(int j = 0;j<n-1-i;j++) 7 { 8 9 if(p[j] > p[j+1]) 10 { 11 p[j] ^= p[j+1]; 12 p[j+1] ^= p[j]; 13 p[j] ^= p[j+1]; 14 flag = 1; 15 } 16 } 17 if(flag == 0) 18 break; 19 } 20 }
如果在一个内循环之内,都为有序排列,即没发生过交换事件,则标志flag为0,直接退出循环。
四. 快速排序
排序思想:对一组元素,选取第一个元素为比较基数,然后其他元素与他进行比较,比它大的放右边,比它小的放左边,一轮完成,该元素左边都是比它自身小的,右边都是比它大的;然后分别对刚才基数左边和右边的元素重复上述操作,直至排序完成。
1 void sortlist3(int *p,int low,int high) 2 { 3 if(low < high) 4 //判断元素是否大于1,至少2个元素才排序 5 int l = low; 6 int h = high; 7 int middle = p[low ]; 8 //此处只能用p[low],不能用p[0],因为后面递归要用到 9 while(l < h) 10 { 11 while(p[h] >= middle && l<h) 12 h--; 13 p[l] = p[h]; 14 while(p[l] <= middle && l<h) 15 l++; 16 p[h] = p[l]; 17 } 18 p[h] = middle; 19 sortlist3(p,low,h-1); 20 sortlist3(p,h+1,high); 21 } 22 }
其中 p 为数组名,low为数组起始地址 0,high 为数组的元素个数减1。
五.插入排序法
1 void insertsort(int arr[],int length,int beg = 0,int step = 1) { 2 for(int i = beg+step; i<length; i+=step) { 3 if(arr[i] < arr[i-step]) { 4 int temparr = arr[i]; 5 int temp = i; 6 while(temp-step>=beg && temparr<arr[temp-step]) { 7 arr[temp] = arr[temp-step]; 8 temp = temp - step; 9 } 10 arr[temp] = temparr; 11 } 12 } 13 }
六.希尔排序法
1 void shellsort(int arr[],int length) { 2 cout<<"Shellsort the array: "; 3 int increment = length/3+1; 4 int flag = 0; 5 while(increment>=1) { 6 if(increment == 1) 7 flag = 1; 8 for(int i = 0; i<increment; i+=increment) 9 insertsort(arr,length,i,increment); //插入排序 10 if(flag == 1) 11 break; 12 increment = increment/3+1; 13 } 14 }
七. 归并排序法
1 /*合并两个有序数组*/ 2 void unionarray(int arr[],int beg,int mid,int end,int*p) { 3 int temp = mid+1; 4 int begg = beg; 5 for(int i = 0;i<end-beg+1;i++) { 6 if(begg > mid) 7 p[i] = arr[temp++]; 8 else if(temp>end) 9 p[i] = arr[begg++]; 10 else { 11 if(arr[begg]>arr[temp]) 12 p[i] = arr[temp++]; 13 else 14 p[i] = arr[begg++]; 15 } 16 } 17 for(int i = beg;i<=end;i++) 18 arr[i] = p[i-beg]; 19 } 20 /*归并排序*/ 21 void GuiBingsort(int arr[],int beg,int end,int *p) { 22 if(beg >= end) 23 return ; 24 int mid = (beg+end)/2; 25 GuiBingsort(arr,beg,mid,p); 26 GuiBingsort(arr,mid+1,end,p); 27 unionarray(arr,beg,mid,end,p); 28 }
八. 堆排序
1 /*交换数组两个元素*/ 2 void swap(int arr[],int a,int b) { 3 int temp = arr[a]; 4 arr[a] = arr[b]; 5 arr[b] = temp; 6 } 7 /*大顶堆维护*/ 8 void heapAdjust(int arr[],int pos,int _size) { 9 int max = pos; 10 int lchild = pos*2+1; 11 int rchild = pos*2+2; 12 if(lchild<_size && arr[lchild]>arr[max]) 13 max = lchild; 14 if(rchild<_size && arr[rchild]>arr[max]) 15 max = rchild; 16 if(pos != max) { 17 swap(arr,pos,max); 18 heapAdjust(arr,max,_size); 19 } 20 } 21 /*堆排序主程序*/ 22 void heapsort(int arr[],int _size) { 23 for(int i = _size/2-1;i>=0;i--) 24 heapAdjust(arr,i,_size); 25 for(int i = _size-1;i>0;i--) { 26 swap(arr,i,0); 27 heapAdjust(arr,0,i); 28 } 29 }