`
lovnet
  • 浏览: 6710585 次
  • 性别: Icon_minigender_1
  • 来自: 武汉
文章分类
社区版块
存档分类
最新评论

C++排序算法总结

 
阅读更多

【1】插入排序:

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

代码:

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

数据测试:


上述代码可以改进的一个地方是:在查找插入位置的时候可以采用二分查找,但是这样依然不可以把时间复杂度降低为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. {
  5. if(low == high)
  6. {
  7. if(val > *(a + low))return (low + 1);
  8. else
  9. return low;
  10. }
  11. int mid = (low + high) / 2;
  12. if(val > *(a + mid) && val > *(a + mid + 1))
  13. return InsertLoc(a,mid + 1,high,val);
  14. else if(val < *(a + mid) && val < *(a + mid + 1))
  15. return InsertLoc(a,low,mid,val);
  16. else
  17. return mid;
  18. }
  19. void InsertionSort(int *a,int n)
  20. {
  21. int temp,insert_location;
  22. for(int i = 1;i < n;++i)
  23. {
  24. temp = *(a + i);
  25. int j = i - 1;
  26. insert_location = InsertLoc(a,0,j,temp);
  27. cout<<"insert_location:"<<insert_location<<endl;
  28. while(j >= insert_location)
  29. {
  30. *(a + j + 1) = *(a + j);
  31. --j;
  32. }
  33. *(a + insert_location) = temp;
  34. for(int m = 0;m <= i;++m)
  35. cout<<*(a + m)<<" ";
  36. cout<<endl;
  37. }
  38. }

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

代码:

  1. //选择排序
  2. #include <iostream>
  3. using namespace std;
  4. void ChoseSort(int* a,int n)
  5. {
  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. {
  30. int n,temp;
  31. cout<<"please input the number of the values that need to sort:"<<endl;
  32. cin>>n;
  33. int *a = (int*)malloc(n *sizeof(int));
  34. cout<<"please input each value:"<<endl;
  35. for(int i = 0;i < n;++i)
  36. {
  37. cin>>temp;
  38. *(a + i) = temp;
  39. }
  40. ChoseSort(a,n);
  41. cout<<"the values after sort:"<<endl;
  42. for(int i = 0;i < n;++i)
  43. cout<<*(a + i)<<" ";
  44. free(a);
  45. }

【3】合并排序

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

代码:

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

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

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

相关推荐

Global site tag (gtag.js) - Google Analytics