(C/C++学习)9.C/C++优化排序

说明: 常见的排序算法都是比较排序,非比较排序包括计数排序、桶排序和基数排序,非比较排序对数据有要求,因为数据本身包含了定位特征,所有才能不通过比较来确定元素的位置。比较排序的时间复杂度通常为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 }
原文地址:https://www.cnblogs.com/tuihou/p/9753851.html