C++排序算法总结

【1】插入排序:

是一个对少量元素进行排序的有效算法。实现比较简单。时间复杂度:O(n^2),空间复杂度:O(1)。是稳定的排序方法。

代码:

  1. //insertion sort 
  2. #include <iostream> 
  3. using namespace std; 
  4.  
  5. //insertion sort 
  6. void InsertionSort(int *a,int n) 
  7.     int temp; 
  8.     for(int i = 1;i < n;++i) 
  9.     { 
  10.         temp = *(a + i); 
  11.         int j = i - 1; 
  12.         while(j >= 0 && *(a + j) > temp) 
  13.         { 
  14.             *(a + j + 1) = *(a + j); 
  15.             --j; 
  16.         } 
  17.         *(a + j + 1) = temp; 
  18.     } 
  19.  
  20. int main() 
  21.     int n,temp; 
  22.     cout<<"please input the number of the values that need to sort:"<<endl; 
  23.     cin>>n; 
  24.     int *a = (int*)malloc(n *sizeof(int)); 
  25.     cout<<"please input each value:"<<endl; 
  26.     for(int i = 0;i < n;++i) 
  27.     { 
  28.         cin>>temp; 
  29.         *(a + i) = temp; 
  30.     } 
  31.     /*
  32.     //insertion sort
  33.     for(int i = 1;i < n;++i)
  34.     {
  35.         temp = *(a + i);
  36.         int j = i - 1;
  37.         while(j >= 0 && *(a + j) > temp)
  38.         {
  39.             *(a + j + 1) = *(a + j);
  40.             --j;
  41.         }
  42.         *(a + j + 1) = temp;
  43.     }*/ 
  44.     InsertionSort(a,n); 
  45.  
  46.     cout<<"the values after sort:"<<endl; 
  47.     for(int i = 0;i < n;++i) 
  48.         cout<<*(a + i)<<" "
 
  1. free(a); 
 

数据测试:


上述代码可以改进的一个地方是:在查找插入位置的时候可以采用二分查找,但是这样依然不可以把时间复杂度降低为O(nlogn),因为移动元素的复杂度没有降低。所以时间复杂度仍然是O(n^2)。

做此改进需要添加函数InsertLoc用于二分查找需要插入的位置,以及修改函数InsertionSort的实现。具体如下:

  1. //改进:用二分查找来找到插入的位置 
  2. //在数组a[low]---a[high]查找val插入的位置 
  3. int InsertLoc(int *a,int low,int high,int val) 
  4.     if(low == high) 
  5.     { 
  6.         if(val > *(a + low))return (low + 1); 
  7.         else 
  8.             return low; 
  9.     } 
  10.     int mid = (low + high) / 2; 
  11.     if(val > *(a + mid) && val > *(a + mid + 1)) 
  12.         return InsertLoc(a,mid + 1,high,val); 
  13.     else if(val < *(a + mid) && val < *(a + mid + 1)) 
  14.         return InsertLoc(a,low,mid,val); 
  15.     else 
  16.         return mid; 
  17.  
  18. void InsertionSort(int *a,int n) 
  19.     int temp,insert_location; 
  20.     for(int i = 1;i < n;++i) 
  21.     { 
  22.         temp = *(a + i); 
  23.         int j = i - 1; 
  24.         insert_location = InsertLoc(a,0,j,temp); 
  25.         cout<<"insert_location:"<<insert_location<<endl; 
  26.         while(j >= insert_location) 
  27.         { 
  28.             *(a + j + 1) = *(a + j); 
  29.             --j; 
  30.         } 
  31.         *(a + insert_location) = temp; 
  32.         for(int m = 0;m <= i;++m) 
  33.             cout<<*(a + m)<<" "
  34.         cout<<endl; 
  35.     } 

【2】选择排序

第一次找出A[0,...,n-1]的最小的元素,与A[0]交换,接着,找出A[1,...,n-1]的次小得元素,与A[1]互换。对A中头n-1个元素执行这一过程。时间复杂度:O(n^2),空间复杂度O(1)。是不稳定的排序方法。比如序列5 8 5 2 9,第一遍选择第1个元素5会和2交换,那么原序列中2个5的相对前后顺序就被破坏了,所以选择排序是不稳定的排序算法。

但是严蔚敏的《数据结构》书上面Page289页说,所有时间复杂度为O(n^2)的简单排序都是稳定的。不知道为什么?求指导~~

其给出的简单排序的伪代码:

  1. void SelectSort(SqList &L) 
  2.     //对顺序表L做简单排序 
  3.     for(i = 1;i < L.length;++i)//选择第i小得记录,并交换到位 
  4.     { 
  5.         j = SelectMinKey(L,i);//在L.r[i..L.length]中选择key最小的记录 
  6.         if(i != j)//与第i个记录交换 
  7.         { 
  8.             temp = L.r[i]; 
  9.             L.r[i] = L.r[j]; 
  10.             L.r[j] = temp; 
  11.         } 
  12.     } 

代码:

  1. //选择排序 
  2. #include <iostream> 
  3. using namespace std; 
  4.  
  5. void ChoseSort(int* a,int n) 
  6.     int temp,minVal,minIndex; 
  7.     for(int i = 0;i < n - 1;++i) 
  8.     { 
  9.         minVal = *(a + i);//记录a[i,...,n-1]之间的最小值 
  10.         minIndex = i;//记录a[i,...,n-1]之间的最小值的下标 
  11.         for(int j = i + 1;j < n;++j) 
  12.         { 
  13.             if(minVal > *(a + j)) 
  14.             { 
  15.                 minVal = *(a + j); 
  16.                 minIndex = j; 
  17.             } 
  18.         } 
  19.         //交换a[i]和a[i,...,n-1]之间的最小值最小值 
  20.         if(minIndex != i) 
  21.         { 
  22.             temp = *(a + i); 
  23.             *(a + i) = *(a + minIndex); 
  24.             *(a + minIndex) = temp; 
  25.         } 
  26.     } 
  27.  
  28. int main() 
  29.     int n,temp; 
  30.     cout<<"please input the number of the values that need to sort:"<<endl; 
  31.     cin>>n; 
  32.     int *a = (int*)malloc(n *sizeof(int)); 
  33.     cout<<"please input each value:"<<endl; 
  34.     for(int i = 0;i < n;++i) 
  35.     { 
  36.         cin>>temp; 
  37.         *(a + i) = temp; 
  38.     } 
  39.     ChoseSort(a,n); 
  40.     cout<<"the values after sort:"<<endl; 
  41.     for(int i = 0;i < n;++i) 
  42.         cout<<*(a + i)<<" "
  43.     free(a); 

【3】合并排序

采用分治法。将n个元素分成各含n/2个元素的子序列,用合并排序法对两个子序列递归的排序(子序列长度为1时递归结束),最后合并两个已排序的子序列得到结果。时间复杂度:O(nlogn),空间复杂度:O(n)。是稳定的排序方法。

代码:

  1. //合并排序 
  2. #include <iostream> 
  3. using namespace std; 
  4.  
  5. #define MAX_VALUE 100000//用于设置哨兵,避免检查是否每一个堆都是空的 
  6.  
  7. //合并两个子数组的函数 
  8. void Merge(int *a,int p,int q,int r) 
  9.     int num1,num2; 
  10.     num1 = q - p + 1; 
  11.     num2 = r - q; 
  12.     int *a1 = (int*)malloc((num1 + 1) *sizeof(int)); 
  13.     int *a2 = (int*)malloc((num2 + 1) *sizeof(int)); 
  14.     for(int i = 0;i < num1;++i) 
  15.         *(a1 + i) = *(a + p + i); 
  16.     *(a1 + num1) = MAX_VALUE;//设置哨兵元素 
  17.     for(int i = 0;i < num2;++i) 
  18.         *(a2 + i) = *(a + q + 1 + i); 
  19.     *(a2 + num2) = MAX_VALUE;//设置哨兵元素 
  20.      
  21.     //进行排序 
  22.     int index1 = 0; 
  23.     int index2 = 0; 
  24.     for(int i = p;i <= r;++i) 
  25.     { 
  26.         if(*(a1 + index1) < *(a2 + index2)) 
  27.         { 
  28.             *(a + i) = *(a1 + index1); 
  29.             ++index1; 
  30.         } 
  31.         else 
  32.         { 
  33.             *(a + i) = *(a2 + index2); 
  34.             ++index2; 
  35.         } 
  36.     } 
  37.     free(a1); 
 
  1. free(a2); 
 
  1. //递归合并排序算法 
  2. void MergeSort(int *a,int p,int r) 
  3.     if(p < r) 
  4.     { 
  5.         int q = (p + r) / 2; 
  6.         MergeSort(a,p,q); 
  7.         MergeSort(a,q + 1,r); 
  8.         Merge(a,p,q,r); 
  9.     } 
  10.  
  11. int main() 
  12.     int n,temp; 
  13.     cout<<"please input the number of the values that need to sort:"<<endl; 
  14.     cin>>n; 
  15.     int *a = (int*)malloc(n *sizeof(int)); 
  16.     cout<<"please input each value:"<<endl; 
  17.     for(int i = 0;i < n;++i) 
  18.     { 
  19.         cin>>temp; 
  20.         *(a + i) = temp; 
  21.     } 
  22.     MergeSort(a,0,n - 1); 
  23.     cout<<"the values after sort:"<<endl; 
  24.     for(int i = 0;i < n;++i) 
  25.         cout<<*(a + i)<<" "
  26.     free(a); 
 

如果不使用哨兵元素,需要修改Merge函数,如下:

  1. //合并两个子数组的函数(不使用哨兵元素) 
  2. void Merge(int *a,int p,int q,int r) 
  3.     int num1,num2; 
  4.     num1 = q - p + 1; 
  5.     num2 = r - q; 
  6.     int *a1 = (int*)malloc(num1 *sizeof(int)); 
  7.     int *a2 = (int*)malloc(num2 *sizeof(int)); 
  8.     for(int i = 0;i < num1;++i) 
  9.         *(a1 + i) = *(a + p + i); 
  10.     for(int i = 0;i < num2;++i) 
  11.         *(a2 + i) = *(a + q + 1 + i); 
  12.      
  13.     //进行排序 
  14.     int index1 = 0; 
  15.     int index2 = 0; 
  16.     int index = p; 
  17.     while(index1 < num1 && index2 <num2) 
  18.     { 
  19.         if(*(a1 + index1) < *(a2 + index2)) 
  20.         { 
  21.             *(a + index) = *(a1 + index1); 
  22.             ++index; 
  23.             ++index1; 
  24.         } 
  25.         else
  26.             *(a + index) = *(a2 + index2); 
  27.             ++index; 
  28.             ++index2; 
  29.         } 
  30.     } 
  31.     while(index1 < num1) 
  32.     { 
  33.         *(a + index) = *(a1 + index1); 
  34.         ++index; 
  35.         ++index1; 
  36.     } 
  37.     while(index2 < num2) 
  38.     { 
  39.         *(a + index) = *(a2 + index2); 
  40.         ++index; 
  41.         ++index2; 
  42.     } 
  43.     free(a1);<pre class="cpp" name="code">  free(a2);</pre> 
  44. <pre></pre> 
  45. <pre class="cpp" name="code">}</pre> 
  46. <p><span style="color: rgb(255, 0, 0); font-family: KaiTi_GB2312; font-size: 24px;"><strong>【4】冒泡排序</strong></span></p> 
  47. <p>每一趟都比较相邻两个元素,若是逆序的,则交换。结束的条件应该是“在一趟排序过程中没有进行过交换元素的操作”。时间复杂度:O(n^2),空间复杂度O(1)。是稳定的排序。</p> 
  48. <pre class="cpp" name="code">#include <iostream> 
  49. using namespace std; 
  50.  
  51. void BubbleSort(int *a,int n) 
  52.     int flag,temp;//标记是否进行过交换操作 
  53.     for(int i = 0;i < n - 1;++i) 
  54.     { 
  55.         flag = 0; 
  56.         for(int j = 0;j < n - 1 - i;++j) 
  57.         { 
  58.             if(*(a + j) > *(a + j + 1)) 
  59.             { 
  60.                 temp = *(a + j); 
  61.                  *(a + j) =  *(a + j + 1); 
  62.                  *(a + j + 1) = temp; 
  63.                  flag = 1; 
  64.             } 
  65.         } 
  66.         if(flag == 0)break
  67.     } 
  68.  
  69. int main() 
  70.     int n,temp; 
  71.     cout<<"please input the number of the values that need to sort:"<<endl; 
  72.     cin>>n; 
  73.     int *a = (int*)malloc(n *sizeof(int)); 
  74.     cout<<"please input each value:"<<endl; 
  75.     for(int i = 0;i < n;++i) 
  76.     { 
  77.         cin>>temp; 
  78.         *(a + i) = temp; 
  79.     } 
  80.     BubbleSort(a,n); 
  81.     cout<<"the values after sort:"<<endl; 
  82.     for(int i = 0;i < n;++i) 
  83.         cout<<*(a + i)<<" "
  84. <pre class="cpp" name="code">   free(a);</pre> 
  85. <pre></pre> 
  86. <pre class="cpp" name="code">}</pre> 
  87. <p><span style="color: rgb(255, 0, 0); font-family: KaiTi_GB2312; font-size: 24px;"><strong>【5】快速排序</strong></span></p> 
  88. <p>它是对冒泡排序的一种改进。它的基本思想是:通过一趟排序将待排序元素分成两个部分,其中一部分元素比另一部分元素小。再分别对这两部分元素进行排序。以达到整个元素序列有序。时间复杂度:O(nlogn),空间复杂度O(logn),是不稳定的算法。</p> 
  89. <p>代码:</p> 
  90. <pre class="cpp" name="code">#include <iostream> 
  91. using namespace std; 
  92.  
  93. int Partition(int *a,int low,int high) 
  94.     int PivotKey = *(a + low);//用第一个元素做枢轴 
  95.     while(low < high) 
  96.     { 
  97.         while(low < high && *(a + high) > PivotKey)--high; 
  98.         *(a + low) = *(a + high); 
  99.         while(low < high && *(a + low) < PivotKey)++low; 
  100.         *(a + high) = *(a + low); 
  101.     } 
  102.     *(a + low) = PivotKey; 
  103.     return low; 
  104.  
  105. void QuickSort(int *a,int low,int high) 
  106.     if(low < high) 
  107.     { 
  108.         int PivotLoc = Partition(a,low,high); 
  109.         QuickSort(a,low,PivotLoc - 1); 
  110.         QuickSort(a,PivotLoc + 1,high); 
  111.     } 
  112.  
  113. int main() 
  114.     int n,temp; 
  115.     cout<<"please input the number of the values that need to sort:"<<endl; 
  116.     cin>>n; 
  117.     int *a = (int*)malloc(n *sizeof(int)); 
  118.     cout<<"please input each value:"<<endl; 
  119.     for(int i = 0;i < n;++i) 
  120.     { 
  121.         cin>>temp; 
  122.         *(a + i) = temp; 
  123.     } 
  124.     QuickSort(a,0,n - 1); 
  125.     cout<<"the values after sort:"<<endl; 
  126.     for(int i = 0;i < n;++i) 
  127.         cout<<*(a + i)<<" "
  128.     free(a);}</pre> 
  129. <p><br> 
  130. </p> 
  131. <p><span style="color: rgb(255, 0, 0); font-family: KaiTi_GB2312; font-size: 24px;"><strong>【6】计数排序</strong></span></p> 
  132. <p>计数排序的思想是对每一个输入元素x,确定出小于x的元素的个数。然后我们就可以直接把它放在嘴中输出数组中相应的位置上。</p> 
  133. <p>但是计数排序基于这样一个假设:n个输入元素的每一个大小范围都是[0,k]。</p> 
  134. <p>代码:</p> 
  135. <p><pre class="cpp" name="code">#include <iostream> 
  136. using namespace std; 
  137.  
  138. //Counting Sort Algorithm 
  139. //A:array before sorting 
  140. //B:array after sorting 
  141. //n:the number of A 
  142. //k:all the elements is in [0,k] 
  143. void CountintSort(int A[],int *B,int n,int k,int *C) 
  144.     //初始化C数组 
  145.     for (int i = 0;i <= k;++i) 
  146.     { 
  147.         C[i] = 0; 
  148.     } 
  149.  
  150.     for (int i = 0;i < n;++i) 
  151.     { 
  152.         ++C[A[i]];//C[i]:值等于i的元素的个数 
  153.     } 
  154.  
  155.     for (int i = 1;i <= k;++i) 
  156.     { 
  157.         C[i] += C[i - 1];//C[i]:值小于等于i的元素的个数 
  158.     } 
  159.      
  160.     for (int i = n - 1;i >= 0;--i) 
  161.     { 
  162.         B[C[A[i]] - 1] = A[i];//注意:下标索引从0开始! 
  163.         --C[A[i]]; 
  164.     } 
  165.  
  166. int main() 
  167.     int A[6] = {2,7,1,4,0,3}; 
  168.     int n = 6; 
  169.     int k = 7; 
  170.     int *B = (int *)malloc(n *sizeof(int)); 
  171.     int *C = (int *)malloc((k + 1) *sizeof(int)); 
  172.     cout << "排序之前的元素:" << endl; 
  173.     for (int i = 0;i < n;++i) 
  174.     { 
  175.         cout << A[i] << " "
  176.     } 
  177.     cout << endl; 
  178.     CountintSort(A,B,n,k,C); 
  179.     cout << "排序之后的元素:" << endl; 
  180.     for (int i = 0;i < n;++i) 
  181.     { 
  182.         cout << B[i] << " "
  183.     } 
  184.     cout << endl; 
  185.     free(B); 
  186.     free(C); 
  187. }</pre><br> 
  188. 运行结果:<p></p> 
  189. <p><img alt="" src="http://my.csdn.net/uploads/201206/10/1339316958_2887.jpg"><br> 
  190. </p> 
  191. <p><strong>时间复杂度分析:</strong></p> 
  192. <p>时间复杂度是O(k + n)。一般,当k = O(n)时,常常采用计数排序。这时候的运行时间为O(n)。</p> 
  193. <p>计数排序是稳定的排序。</p> 
  194. <p><br> 
  195. </p> 
  196. <p>一些好的参考资料:不同排序算法间的比较:<a href="http://commons.wikimedia.org/wiki/File:SortingAlgoComp.png">http://commons.wikimedia.org/wiki/File:SortingAlgoComp.png</a><br> 
  197. 一些排序算法的 C 及 Pascal 实现 :<br> 
  198. <a href="http://www.nocow.cn/index.php/%E6%8E%92%E5%BA%8F%E7%AE%97%E6%B3%95">http://www.nocow.cn/index.php/%E6%8E%92%E5%BA%8F%E7%AE%97%E6%B3%95</a></p> 
  199. <p>最后,简要比较一下各排序算法,转自维基百科:</p> 
  200. <p><span id=".E7.AE.80.E8.A6.81.E6.AF.94.E8.BE.83"class="mw-headline">简要比较</span> 
  201. <table class="wikitable     "
  202. <tbody> 
  203. <tr> 
  204. <th rowSpan="2">名称</th> 
  205. <th rowSpan="2">数据对象</th> 
  206. <th rowSpan="2">稳定性</th> 
  207. <th colSpan="2">时间复杂度</th> 
  208. <th rowSpan="2">空间复杂度</th> 
  209. <th rowSpan="2">描述</th> 
  210. </tr> 
  211. <tr> 
  212. <th>平均</th> 
  213. <th>最坏</th> 
  214. </tr> 
  215. <tr> 
  216. <td>插入排序</td> 
  217. <td>数组、链表</td> 
  218. <td>√</td> 
  219. <td colSpan="2"><span dir="ltr"class="texhtml"><em>O</em>(<em>n</em><sup>2</sup>)</span></td> 
  220. <td>O(1)</td> 
  221. <td>(有序区,无序区)。把无序区的第一个元素插入到有序区的合适的位置。对数组:比较得少,换得多。</td> 
  222. </tr> 
  223. <tr> 
  224. <td rowSpan="2">直接选择排序</td> 
  225. <td>数组</td> 
  226. <td>×</td> 
  227. <td rowSpan="2" colSpan="2"><span dir="ltr"class="texhtml"><em>O</em>(<em>n</em><sup>2</sup>)</span></td> 
  228. <td rowSpan="2">O(1)</td> 
  229. <td rowSpan="2">(有序区,无序区)。在无序区里找一个最小的元素跟在有序区的后面。 对数组:比较得多,换得少。</td> 
  230. </tr> 
  231. <tr> 
  232. <td>链表</td> 
  233. <td>√</td> 
  234. </tr> 
  235. <tr> 
  236. <td>堆排序</td> 
  237. <td>数组</td> 
  238. <td>×</td> 
  239. <td colSpan="2">O(nlogn)</td> 
  240. <td>O(1)</td> 
  241. <td>(最大堆,有序区)。从堆顶把根卸出来放在有序区之前,再恢复堆。</td> 
  242. </tr> 
  243. <tr> 
  244. <td>归并排序</td> 
  245. <td>数组、链表</td> 
  246. <td>√</td> 
  247. <td colSpan="2">O(nlogn)</td> 
  248. <td>O(n) +O(logn) , 如果不是从下到上</td> 
  249. <td>把数据分为两段,从两段中逐个选最小的元素移入新数据段的末尾。可从上到下或从下到上进行。</td> 
  250. </tr> 
  251. <tr> 
  252. <td>快速排序</td> 
  253. <td>数组</td> 
  254. <td>×</td> 
  255. <td>O(nlogn)</td> 
  256. <td><span dir="ltr" class="texhtml"><em>O</em>(<em>n</em><sup>2</sup>)</span></td> 
  257. <td>O(logn) ,O(n)</td> 
  258. <td>(小数,枢纽元,大数)。</td> 
  259. </tr> 
  260. <tr> 
  261. <td>Accum qsort</td> 
  262. <td>链表</td> 
  263. <td>√</td> 
  264. <td>O(nlogn)</td> 
  265. <td><span dir="ltr" class="texhtml"><em>O</em>(<em>n</em><sup>2</sup>)</span></td> 
  266. <td>O(logn) ,O(n)</td> 
  267. <td>(无序区,有序区)。把无序区分为(小数,枢纽元,大数),从后到前压入有序区。</td> 
  268. </tr> 
  269. <tr> 
  270. <td colSpan="7"> </td> 
  271. <td> </td> 
  272. </tr> 
  273. <tr> 
  274. <td>决策树排序</td> 
  275. <td> </td> 
  276. <td>√</td> 
  277. <td colSpan="2">O(logn!)</td> 
  278. <td>O(n!)</td> 
  279. <td>O(n) <O(logn!) <O(nlogn)</td> 
  280. </tr> 
  281. <tr> 
  282. <td colSpan="7"> </td> 
  283. <td> </td> 
  284. </tr> 
  285. <tr> 
  286. <td>计数排序</td> 
  287. <td>数组、链表</td> 
  288. <td>√</td> 
  289. <td colSpan="2">O(n)</td> 
  290. <td>O(n+m)</td> 
  291. <td>统计小于等于该元素值的元素的个数 i,于是该元素就放在目标数组的索引 i位。(i≥0)</td> 
  292. </tr> 
  293. <tr> 
  294. <td>桶排序</td> 
  295. <td>数组、链表</td> 
  296. <td>√</td> 
  297. <td colSpan="2">O(n)</td> 
  298. <td>O(m)</td> 
  299. <td>将值为 i 的元素放入i 号桶,最后依次把桶里的元素倒出来。</td> 
  300. </tr> 
  301. <tr> 
  302. <td>基数排序</td> 
  303. <td>数组、链表</td> 
  304. <td>√</td> 
  305. <td colSpan="2"> </td> 
  306. <td> </td> 
  307. <td>一种多关键字的排序算法,可用桶排序实现。</td> 
  308. </tr> 
  309. </tbody> 
  310. </table> 
  311. <p></p> 
  312. <ul> 
  313. <li>均按从小到大排列 </li><li>n 代表数据规模 </li><li>m 代表数据的最大值减最小值 </li></ul> 
  314. <div><pre class="cpp" name="code"></pre></div><div></div><pre></pre> 
  315. <pre></pre> 
  316. <pre></pre> 
  317. <pre></pre> 
  318. <pre></pre> 
  319. <pre></pre> 
  320. <pre></pre> 
  321. <pre></pre> 
  322. </pre> 
原文地址:https://www.cnblogs.com/wuyida/p/6301190.html