当前位置:   article > 正文

【深圳大学算法设计与分析】实验一 算法性能分析(十大排序算法)

深圳大学算法设计与分析

实验目的

1.掌握选择排序、冒泡排序、合并排序、快速排序、插入排序算法原理。

2.掌握不同排序算法时间效率的经验分析方法,验证理论分析与经验分析的一致性。

实验内容与结果

实现选择排序、冒泡排序、合并排序、快速排序、插入排序算法;

(1)选择排序

原理:从未排序的数据元素中选出最小的一个元素,放在序列的起始位置,然后再从剩余的未排序元素中寻找到最小元素,继续放在起始位置,直到未排序元素个数为0。

算法分析:整个算法是双重循环:

外循环控制排序的趟数,对n个记录进行排序的趟数为n-1趟;

内循环控制每一趟的排序,进行第i趟排序时,所需的比较次数总是n-i次,关键字比较次数KCN 与记录的初始排列无关。

总的关键字比较次数为

记录移动次数RMN与初始排列有关,最好的情况是,排列已经有序,则RMN=0;最坏情况是,每一趟都要进行交换,总的记录移动次数为 RMN = 3(n-1)。

时间复杂度是O(n2),空间复杂度是O(1)。

选择排序是一种不稳定的排序方法。

(2)冒泡排序

原理:对于n个待排序记录,从第1个记录起,依次比较相邻两个记录的关键字,如果发生逆序,则交换之,直至第n-1个记录和第n个记录比较完,循环n-1次即可排列有序。

算法分析:

最好情况:在记录的初始序列正序时,只执行一趟起泡排序,做n-1次关键字比较,但是不移动记录。

最坏情况:记录的初始序列逆序时,要执行n-1趟冒泡,第i趟做n-i次关键字比较,执行n-i次记录交换,比较次数KCN和交换次数RCN为:

冒泡排序的时间复杂度为O(n2)。

冒泡排序是一种稳定的排序方法。

(3)合并排序

原理:归并是指将两个或两个以上的有序序列合并成一个有序序列。

2-路归并排序:

  1. 初始时,将每个记录看成一个单独的有序序列,则n个待排序记录就是n个长度为1的有序子序列;
  2. 将前后相邻的两个有序序列归并为一个有序序列(两两归并),得到(int)(n/2)个长度为2或1的有序子序列——一趟归并;
  3. 重复做两两归并操作,直到得到长度为n的有序序列为止。

其核心是如何将相邻的两个子序列归并成一个子序列。

算法分析:

(1)假设待归并的两个有序表长度分别为m和n,若是顺序存储,则归并后,都会利用一个长度为m+n的数组作为辅助数组用于保存合并序列,则空间复杂度为O(m+n)

(2)归并操作至多只需要m+n次移位和m+n次比较,因此归并的时间复杂度为O(m+n)

(3)如果待排序的记录为n个,则需要做(int)(log2n)趟2-路归并排序,每趟2-路归并排序的时间复杂度为O(n),因此2-路归并排序的时间复杂度为O(nlog n)。

(4)需要额外空间,大小与待排序记录空间相同,则空间复杂度为O(n)。

(5)归并排序是一种稳定的排序方法。

(4)快速排序

原理:任取待排序记录序列中的某个记录作为枢轴(也称为基准、锚点或支点记录,pivot), 通过一趟排序,将待排序记录以枢轴为界分割成两部分,其中,比枢轴关键字小的记录都在枢轴的前面,而枢轴后面的记录都比枢轴关键字大。然后,采用同样方法再分别对这两部分子序列进行排序,最后达到整个序列有序。

算法分析:时间复杂度是O(nlog n),空间复杂度是:S(n)=O(㏒n)。

快速排序是一种不稳定的排序方法。

(5)插入排序

原理:将待排序的记录依次插入到已排好序的序列中,得到一个新的、记录数增加1的有序表。 直到所有的记录都插入完为止。

算法分析:

关键字比较次数和记录移动次数与记录的初始排列有关。

时间复杂度为O(n2),空间复杂度为O(1)。

最大的优点是简单,在记录数较少时,是比较好的办法。

插入排序是一种稳定的排序方法。

当n=10000时

当n=20000时

当n=30000时

当n=40000时

当n=50000时

表格如下

图像如下

在大数据量进行排序时,冒泡排序需要耗费大量时间,选择排序和插入排序所耗费时间略少,合并排序和快速排序耗费时间最少。

(6)选择排序

在大数据量排序情况下,理论值大于实际值不少,原因是基准值n=10000时平均运行时间较长。

(7)冒泡排序

在大数据量排序情况下,理论值和实际值较为相似;理论值略小于实际值的原因是基准值n=10000时平均运行时间较少。

(8)合并排序

在大数据量排序情况下,理论值和实际值较为接近。

(9)快速排序

在大数据量排序情况下,理论值和实际值较为相似,且快速排序的平均运行时间少,效率高。

(10)插入排序

在大数据量排序情况下,理论值和实际值几乎一致。

从10亿数据中快速挑选出最大的10个数。

算法思想:将十亿分块,每个块为十万,用选择排序将每个块最大的十个数进入队列,最后再统一取出找出最大的十个数即为最终所求。

最终结果

实验总结

综合上述实验可得,当数据规模相当大时,选择排序、冒泡排序、插入排序耗费的时间相当多,该类算法虽然简单易懂,但是效率较低,不适合处理大量数据。合并排序和快速排序采用了分治、递归的思想,运行大量数据时效率仍然非常高,远胜于前面的几种排序算法。因此,当数据规模较大时,选择后面两种排序算法为佳。

实验代码

  1. #include<iostream>
  2. #include<algorithm>
  3. #include<stdlib.h>
  4. #include<queue>
  5. using namespace std;
  6. int n; //数据总数
  7. int* zu;
  8. queue<int> q;
  9. int select()//选择排序
  10. {
  11. int qi, zhi; //记录起止时间
  12. qi = clock();
  13. //
  14. for (int i = 0; i < n; i++)
  15. {
  16. int min = 99999,minpos;
  17. for (int j = i; j < n; j++)
  18. if (zu[j] < min)//找到最小值放到前面
  19. {
  20. min = zu[j];
  21. minpos = j;
  22. }
  23. if (i != minpos)
  24. swap(zu[i], zu[minpos]);//交换
  25. }
  26. //
  27. zhi = clock();
  28. return zhi - qi; //返回时间差
  29. }
  30. int bubble()//冒泡排序
  31. {
  32. int qi, zhi; //记录起止时间
  33. qi = clock();
  34. //
  35. int i, j;
  36. for (i = 0; i < n - 1; i++)
  37. for (j = 0; j < n-i-1; j++)
  38. if (zu[j] > zu[j + 1])
  39. swap(zu[j], zu[j + 1]);
  40. //
  41. zhi = clock();
  42. return zhi - qi; //返回时间差
  43. }
  44. void merge(int* a, int l, int mid, int r)//合并两序列
  45. {
  46. int* b = new int[r - l + 1];
  47. int i = l, j = mid + 1, k = 0;
  48. while (i <= mid && j <= r)
  49. {
  50. if (a[i] <= a[j])
  51. b[k++] = a[i++];
  52. else
  53. b[k++] = a[j++];
  54. }
  55. while (i <= mid)
  56. b[k++] = a[i++];
  57. while (j <= r)
  58. b[k++] = a[j++];
  59. for (i = l,k=0; i <= r; i++)//将排序好的序列传回去
  60. a[i] = b[k++];
  61. }
  62. void mergesort(int *a,int l,int r)//递归进行归并排序
  63. {
  64. if (l < r)
  65. {
  66. int mid = (l + r) / 2;
  67. mergesort(a, l, mid);
  68. mergesort(a, mid + 1, r);
  69. merge(a, l, mid, r);
  70. }
  71. }
  72. int guibing()//归并排序
  73. {
  74. int qi, zhi; //记录起止时间
  75. qi = clock();
  76. //
  77. mergesort(zu, 0, n - 1);
  78. //
  79. zhi = clock();
  80. return zhi - qi; //返回时间差
  81. }
  82. int part(int l,int r)//划分子表并返回轴的位置
  83. {
  84. int zhou = zu[l];//保存轴的值
  85. while (l < r)
  86. {
  87. while (l < r && zhou <= zu[r])//注意'='不能漏掉
  88. r--;
  89. zu[l] = zu[r];
  90. while (l < r && zhou >= zu[l])
  91. l++;
  92. zu[r] = zu[l];
  93. }// 循环结束的条件是l==r
  94. zu[l] = zhou;//将轴的值放入l==r的位置
  95. return l; //返回轴的位置
  96. }
  97. void qsort(int l, int r)
  98. {
  99. int zhoupos;
  100. if (l < r)
  101. {
  102. zhoupos = part(l, r);
  103. qsort(l, zhoupos - 1);
  104. qsort(zhoupos + 1, r);
  105. }
  106. }
  107. int quick()//快速排序
  108. {
  109. int qi, zhi; //记录起止时间
  110. qi = clock();
  111. //
  112. qsort(0, n - 1);
  113. //
  114. zhi = clock();
  115. return zhi - qi; //返回时间差
  116. }
  117. int insert()//插入排序
  118. {
  119. int qi, zhi; //记录起止时间
  120. qi = clock();
  121. //
  122. int i, j;
  123. for (i = 1; i < n; i++)//第一个数据不用插入
  124. {
  125. int temp = zu[i];
  126. for (j = i; j > 0; j--)
  127. {
  128. if (temp < zu[j - 1])
  129. zu[j] = zu[j - 1];
  130. else
  131. break;
  132. }
  133. zu[j] = temp;
  134. }
  135. //
  136. zhi = clock();
  137. return zhi - qi; //返回时间差
  138. }
  139. void show()//输出函数
  140. {
  141. for (int i = 0; i < n; i++)
  142. {
  143. cout << zu[i] << " ";
  144. }
  145. cout << endl;
  146. }
  147. void ceshi(int ci, int size)//测试次数和排序数组大小
  148. {
  149. n = size;
  150. zu=new int[size];//动态建立数组
  151. srand(time(0));
  152. int t1,t2,t3,t4,t5, i, j;
  153. t1 = t2 = t3 = t4 = t5 = 0;
  154. /*
  155. for (i = 0; i < ci; i++)
  156. {
  157. for (j = 0; j < size; j++)
  158. zu[j] = rand();
  159. //show();//1
  160. t1+= select();
  161. t2 += bubble();
  162. t3 += guibing(); 不能放一起,要分开!!!!!
  163. t4 += quick();
  164. t5 += insert();
  165. //show(); cout << endl;//2 语句1和2用来测试排序算法是否正确,此时n要取小值
  166. }
  167. */
  168. for (i = 0; i < ci; i++)
  169. {
  170. for (j = 0; j < size; j++)
  171. zu[j] = rand();
  172. t1 += select();
  173. }
  174. for (i = 0; i < ci; i++)
  175. {
  176. for (j = 0; j < size; j++)
  177. zu[j] = rand();
  178. t2 += bubble();
  179. }
  180. for (i = 0; i < ci; i++)
  181. {
  182. for (j = 0; j < size; j++)
  183. zu[j] = rand();
  184. t3 += guibing();
  185. }
  186. for (i = 0; i < ci; i++)
  187. {
  188. for (j = 0; j < size; j++)
  189. zu[j] = rand();
  190. t4 += quick();
  191. }
  192. for (i = 0; i < ci; i++)
  193. {
  194. for (j = 0; j < size; j++)
  195. zu[j] = rand();
  196. t5 += insert();
  197. }
  198. cout << "选择排序的平均运行时间为" << t1 / ci << "ms" << endl;
  199. cout << "冒泡排序的平均运行时间为" << t2 / ci << "ms" << endl;
  200. cout << "合并排序的平均运行时间为" << t3 / ci << "ms" << endl;
  201. cout << "快速排序的平均运行时间为" << t4 / ci << "ms" << endl;
  202. cout << "插入排序的平均运行时间为" << t5 / ci << "ms" << endl;
  203. }
  204. void selectshiyi()//选择排序从10亿中找最大的10个
  205. {
  206. int i,j,k,l;
  207. srand(time(0));
  208. zu = new int[100000];
  209. k = 0;
  210. n = 100000;
  211. for (i = 0; i < 1000000000; i++)//将十亿分块,每个块为十万,将每个块最大的十个数进入队列,最后再统一取出找出最大的十个数
  212. {
  213. zu[k++] = rand();
  214. if (k == 99999) //每次数组存满十万则进行操作
  215. {
  216. for (l = 0; l < 10; l++)
  217. {
  218. int max = -1, maxpos;
  219. for (j = 0; j < n; j++)
  220. if (zu[j] > max)//找到最大值
  221. {
  222. max = zu[j];
  223. maxpos = j;
  224. }
  225. q.push(zu[maxpos]);//进入队列
  226. zu[maxpos] = 0;
  227. }
  228. k = 0;
  229. }
  230. }
  231. n = 10000;
  232. for (i = 0; i < n; i++)//取出队列中的值
  233. {
  234. zu[i] = q.front();
  235. q.pop();
  236. }
  237. for (l = 0; l < 10; l++)//将最大的十个数存入队列
  238. {
  239. int max = -1, maxpos;
  240. for (j = 0; j < n; j++)
  241. if (zu[j] > max)
  242. {
  243. max = zu[j];
  244. maxpos = j;
  245. }
  246. q.push(zu[maxpos]);
  247. zu[maxpos] = 0;
  248. }
  249. for (i = 0; i < 10; i++)//输出
  250. {
  251. cout << q.front() << " ";
  252. q.pop();
  253. }
  254. cout << endl;
  255. }
  256. int main()
  257. {
  258. /*
  259. for (int i = 1; i <= 5; i++)
  260. {
  261. cout << endl << endl;
  262. int size = i*10000; //设置数组大小
  263. cout << "排序数组大小n=" << size << endl;
  264. ceshi(20, size); //测试20次
  265. }
  266. */
  267. selectshiyi();
  268. }

(by 归忆)

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/你好赵伟/article/detail/621341
推荐阅读
相关标签
  

闽ICP备14008679号