• <排序及模拟实现>——《Data Structure in C Train》


     目录

    详细实现链接:

    <排序>《数据结构(C语言版)》

    <堆及堆排序>《数据结构(C语言版)》

    1.分析实现逻辑,学习不同实现思想及写法:

    1.1插入排序(直接插入):

    1.2 希尔排序:

    1.3 堆排序:

    1.4 直接选择排序:

    1.5 冒泡排序:

     1.6 快速排序:

    1.6.1 单趟时间复杂度:O(N)

     1.6.2 快速排序——挖坑法:

     1.6.3 快速排序——挖坑法优化(三数取中)

     1.6.4 快速排序——挖坑法优化(三数取中+小区间优化)

     1.6.5  快速排序——左右指针法

     1.6.6 快速排序——前后指针法

     1.6.7 快速排序——非递归版(排序可复用挖坑法、左右指针法、前后指针法)

     1.7 归并排序

    1.7.1   归并排序——递归版:

     1.7.2  归并排序——非递归版:

    1.8计数排序

    2. 完整源码:

    3. 各大排序性能对比分析:

    后记:●由于作者水平有限,文章难免存在谬误之处,敬请读者斧正,俚语成篇,恳望指教!

                                                                               ——By 作者:新晓·故知


    详细实现链接:

    <排序>《数据结构(C语言版)》

    <堆及堆排序>《数据结构(C语言版)》

    1.分析实现逻辑,学习不同实现思想及写法:

    1.1插入排序(直接插入):

    • 时间复杂度:O(N^2)
    • 最坏情况:逆序O(N^2)
    • 最好情况:全部顺序 O(N)
    • 空间复杂度:O(1)

    • 稳定

    1.2 希尔排序

    • 时间复杂度:O(N*logN)~ O(N^2)
    • 最好情况:O(N^1.3)
    • 最坏情况:O(N^2)
    • 空间复杂度:O(1)
    • 不稳定

    在直接插入排序的基础上优化:

    • 1.先进行预排序(分组排序),让数据接近有序
    • 2.再直接插入排序,

    多组间隔为gap的预排序,gap由大变小,

    • gap越大(以升序举例),大的数可以越快的到后面,小的数可以越快的到前面。但预排后越不接近有序
    • gap越小,越接近有序

    时间复杂度:O(N*logN)~O(N^2)

    • gap很大时,下面预排序为O(N)
    • gap很小时,数据已接近有序,近似为O(N)

     

    1.3 堆排序

    • 时间复杂度:O(N*logN)
    • 最好情况:O(N*logN)
    • 最坏情况:O(N*logN)
    • 空间复杂度:O(1)
    • 不稳定

    给一组数据(假设存储在动态数组里),若要进行堆排序(若打印为升序),且采用向下调整,那么就把这组数据建大堆,再进行调整!然后根据下标遍历数组,即可打印为升序!

    • 大堆:堆顶数据是最大的。
    • 小堆:堆顶元素是最小的。

    建堆:

    • 倒数第一个非叶子结点(即叶子父亲的结点)开始调整。
    • 建堆的时间复杂度:O(N)

    调整方法:

    • 向上调整法:
    • 向下调整算法:
      • 前提:左右子树必须是小堆。
      • 最多调整高度次:logN次

    这里注意:

    调整分为:向上调整法、向下调整法。

    建堆分为:建大堆、建小堆。

    注意:

    若将最后的数据按照升序打印,若采用向下调整法,则选择建成大堆(只保证了父结点与子节点的相对大小,相邻没关系,这里只是建堆,而非调整后的最终形态),再从倒数第一个非叶子结点(即叶子父亲的结点)开始调整,最终调整后,再每次输出堆顶元素,打印(因为存储在数组,遍历下标打印,类似于层序遍历的操作)的就是升序!

    其实:有4种情况:

    (1)建小堆,向上调整,最终为大堆-----用于堆排降序(可以实现,但多此一举!)

    (2)建大堆,向上调整,最终为小堆-----用于堆排升序

    (3)建小堆,向下调整,最终为大堆-----用于堆排降序(可以实现,但多此一举!)

    (4)建大堆,向下调整,最终为小堆-----用于堆排升序

    在进行堆排序时,若想数据为升序,则建大堆,采用向下调整法。当把最大的换到最后,就不再将其作为接下来的调整对象。

    由于向上调整法的时间复杂度比向下调整法的时间复杂度高,因此一般采用向下调整法。

    时间复杂度:

     关于堆的选择题快速判断:

     

    (1)建小堆,向上调整,最终为大堆-----用于堆排降序(可以实现,但多此一举!)

    (2)建大堆,向上调整,最终为小堆-----用于堆排升序

    (3)建小堆,向下调整,最终为大堆-----用于堆排降序(可以实现,但多此一举!)

    (4)建大堆,向下调整,最终为小堆-----用于堆排升序

    1.4 直接选择排序:

    • 时间复杂度:O(N^2)
    • 最好情况:O(N^2)
    • 最坏情况:O(N^2)
    • 空间复杂度:O(1)
    • 不稳定

    1.5 冒泡排序:

    • 时间复杂度:O(N^2)
    • 最好情况:O(N)
    • 最坏情况:O(N^2)
    • 空间复杂度:O(1)
    • 稳定

     1.6 快速排序:

    • 时间复杂度:O(N*logN)
    • 最好情况:O(N*logN)
    • 最坏情况:O(N^2)
    • 空间复杂度:O(logN)~ O(N)
    • 不稳定

    1.6.1 单趟时间复杂度:O(N)

     1.6.2 快速排序——挖坑法:

    时间复杂度:

     

     1.6.3 快速排序——挖坑法优化(三数取中)

    时间复杂度:

     

     1.6.4 快速排序——挖坑法优化(三数取中+小区间优化)

    时间复杂度:

     

     1.6.5  快速排序——左右指针法

    时间复杂度:

     1.6.6 快速排序——前后指针法

    时间复杂度:

     

     1.6.7 快速排序——非递归版(排序可复用挖坑法、左右指针法、前后指针法)

    时间复杂度:

     

     1.7 归并排序

    • 时间复杂度:O(N*logN)
    • 最好情况:O(N*logN)
    • 最坏情况:O(N*logN)
    • 空间复杂度:O(N)
    • 稳定

    1.7.1   归并排序——递归版:

    时间复杂度:

     1.7.2  归并排序——非递归版:

    时间复杂度:

     

    1.8计数排序

    时间复杂度:O(range+N)

    空间复杂度:O(range)

     

    2. 完整源码:

    Sort.h:

    1. #pragma once
    2. #include
    3. #include
    4. void PrintArray(int* a, int n); //打印
    5. void InsertSort(int* a, int n); //插入排序
    6. void ShellSort(int* a, int n); //希尔排序
    7. void HeapSort(int* a, int n); //堆排序
    8. void SelectSort(int* a, int n); //选择排序
    9. void BubbleSort(int* a, int n); //冒泡排序
    10. //void QuickSort(int* a, int n); //快速排序——写法1:挖坑法(单趟分析版)
    11. void QuickSort(int* a, int left, int right); //快速排序——写法1:挖坑法(实现排序版)
    12. void MergeSort(int* a, int n); //归并排序
    13. void QuickSortNonR(int* a, int n); //快速排序(非递归版)
    14. void MergeSortNonR(int* a, int n); //归并排序(非递归版)
    15. void CountSort(int* a, int n); //计数排序

    Sort.c:

    1. #include"Sort.h"
    2. #include"Stack.h"
    3. //这里采用升序讲解
    4. //打印
    5. void PrintArray(int* a, int n)
    6. {
    7. for (int i = 0; i < n; i++)
    8. {
    9. printf("%d ", a[i]);
    10. }
    11. printf("\n");
    12. }
    13. ///
    14. //插入排序
    15. //时间复杂度:O(N^2)
    16. //最坏情况:逆序
    17. //最好情况:全部顺序 O(N)
    18. void InsertSort(int* a, int n)
    19. {
    20. //假设[0,end]有序,将end+1位置的值插入进去,让[0,end+1]有序
    21. for (int i = 0; i < n - 1; i++)
    22. {
    23. int end = i;
    24. int tmp = a[end + 1];
    25. while (end >= 0)
    26. {
    27. if (a[end] > tmp) //升序
    28. //if (a[end] < tmp) //降序
    29. {
    30. a[end + 1] = a[end];
    31. --end;
    32. }
    33. else
    34. {
    35. break;
    36. }
    37. }
    38. a[end + 1] = tmp;
    39. }
    40. }
    41. //
    42. //希尔排序
    43. //在直接插入排序的基础上优化
    44. //1.先进行预排序(分组排序),让数据接近有序
    45. //2.再直接插入排序,
    46. //多组间隔为gap的预排序,gap由大变小,
    47. //gap越大(以升序举例),大的数可以越快的到后面,小的数可以越快的到前面。但预排后越不接近有序
    48. //gap越小,越接近有序
    49. //时间复杂度:O(logN*N)或者O(log3N*N)
    50. //gap很大时,下面预排序为O(N)
    51. //gap很小时,数据已接近有序,近似为ON)
    52. //平均时间复杂度:O(N^1.3)
    53. void ShellSort(int* a, int n)
    54. {
    55. int gap = n; //可以自行设置,但不会给固定的值
    56. //把间隔为gap的多组数据同时排序(注意:理解这个多组的含义)
    57. //end最终位置:n-gap-1
    58. //gap的设置方式之一:
    59. while(gap > 1)
    60. {
    61. //gap=gap/2; //一定会保证最后一次为1 //运行了logN次
    62. gap = gap / 3 + 1; //但要保证最后一次为1 //运行了log3N次
    63. //gap>1时都是预排序,排序后接近有序
    64. //gap==1时,就是直接插入排序
    65. for (int i = 0; i < n - gap; i++)
    66. {
    67. int end = i;
    68. int tmp = a[end + gap];
    69. while (end >= 0)
    70. {
    71. if (a[end] > tmp)
    72. {
    73. a[end + gap] = a[end];
    74. end -= gap;
    75. }
    76. else
    77. {
    78. break;
    79. }
    80. }
    81. a[end + gap] = tmp;
    82. }
    83. }
    84. }
    85. /
    86. //堆排序
    87. void Swap(int* p1, int* p2)
    88. {
    89. int tmp = *p1;
    90. *p1 = *p2;
    91. *p2 = tmp;
    92. }
    93. //(1)建小堆,向上调整,最终为大堆---- - 用于堆排降序
    94. //(2)建大堆,向上调整,最终为小堆---- - 用于堆排升序
    95. //(3)建小堆,向下调整,最终为大堆---- - 用于堆排降序(可以实现,多此一举)
    96. //(4)建大堆,向下调整,最终为小堆---- - 用于堆排升序
    97. //注:由于向上调整法的时间复杂度比向下调整法的时间复杂度高,因此一般采用向下调整法。
    98. //堆排序,采用数组存储,操作下标。但逻辑要是二叉树
    99. //把数据建成堆
    100. //1.堆排序调整-向下调整法
    101. void AdjustDwon(int* a, int n, int root)
    102. {
    103. int parent = root;
    104. int child = parent * 2 + 1; // 默认是左孩子
    105. //1.建大堆,再调整
    106. while (child < n)
    107. {
    108. // 1、选出左右孩子中大的那一个
    109. if (child + 1 < n && a[child + 1] > a[child])
    110. {
    111. child += 1;
    112. }
    113. if (a[child] > a[parent])
    114. {
    115. Swap(&a[child], &a[parent]);
    116. parent = child;
    117. child = parent * 2 + 1;
    118. }
    119. else
    120. {
    121. break;
    122. }
    123. }
    124. 2.建小堆,再调整
    125. //while (child < n)
    126. //{
    127. // // 1、选出左右孩子中小的那一个
    128. // if (child + 1 < n && a[child + 1] < a[child])
    129. // {
    130. // child += 1;
    131. // }
    132. // if (a[child] < a[parent])
    133. // {
    134. // Swap(&a[child], &a[parent]);
    135. // parent = child;
    136. // child = parent * 2 + 1;
    137. // }
    138. // else
    139. // {
    140. // break;
    141. // }
    142. //}
    143. }
    144. //2.堆排序调整-向上调整法
    145. void AdjustUp(int* a, int child)
    146. {
    147. int parent = (child - 1) / 2;
    148. //1.建大堆,再调整
    149. while (child > 0)
    150. {
    151. if (a[child] > a[parent])
    152. {
    153. Swap(&a[child], &a[parent]);
    154. child = parent;
    155. parent = (child - 1) / 2;
    156. }
    157. else
    158. {
    159. break;
    160. }
    161. }
    162. 2.建小堆,再调整
    163. //while (child > 0)
    164. //{
    165. // if (a[child] < a[parent])
    166. // {
    167. // Swap(&a[child], &a[parent]);
    168. // child = parent;
    169. // parent = (child - 1) / 2;
    170. // }
    171. // else
    172. // {
    173. // break;
    174. // }
    175. //}
    176. }
    177. //堆排序(建堆)
    178. // 升序,建小堆?还是大堆? -> 大堆
    179. // 建堆只是第一步,并非最终形态,还要进行调整(一般选择向下调整)
    180. // 整体时间复杂度O(N*logN)
    181. void HeapSort(int* a, int n)
    182. {
    183. // 建堆 时间复杂度:O(N)
    184. //调整
    185. 1.向上调整法
    186. //for (int i = 1; i < n; ++i)
    187. //{
    188. // AdjustUp(a, i);
    189. //}
    190. //2.向下调整法
    191. for (int i = (n - 1 - 1) / 2; i >= 0; --i)
    192. {
    193. AdjustDwon(a, n, i);
    194. }
    195. // 排升序,采用向下调整法,那么,建大堆还是小堆? -->建大堆
    196. int end = n - 1;
    197. while (end > 0)
    198. {
    199. Swap(&a[0], &a[end]);
    200. AdjustDwon(a, end, 0);
    201. --end;
    202. }
    203. }
    204. /
    205. //直接选择排序,时间复杂度O(N*N)
    206. // 很差,因为最好情况也是O(N*N)
    207. // N
    208. // N-2
    209. // N-4
    210. // ...
    211. void SelectSort(int* a, int n)
    212. {
    213. int begin = 0, end = n - 1;
    214. while (begin < end)
    215. {
    216. int mini = begin, maxi = begin;
    217. for (int i = begin; i <= end; ++i)
    218. {
    219. if (a[i] < a[mini])
    220. {
    221. mini = i;
    222. }
    223. if (a[i] > a[maxi])
    224. {
    225. maxi = i;
    226. }
    227. }
    228. Swap(&a[begin], &a[mini]);
    229. // 如果begin跟maxi重叠,需要修正一下maxi的位置
    230. if (begin == maxi)
    231. {
    232. maxi = mini;
    233. }
    234. Swap(&a[maxi], &a[end]);
    235. ++begin;
    236. --end;
    237. }
    238. }
    239. /
    240. //冒泡排序
    241. // 时间复杂度:O(N*N)
    242. // 最好情况:O(N)
    243. // N-1
    244. // N-2
    245. // ...
    246. // 跟直接插入排序相比?谁更好 -> 直接插排序入更好
    247. void BubbleSort(int* a, int n)
    248. {
    249. //写法1:
    250. for (int j = 0; j < n; ++j)
    251. {
    252. int exchange = 0;
    253. for (int i = 1; i < n - j; ++i)
    254. {
    255. if (a[i - 1] > a[i])
    256. {
    257. Swap(&a[i - 1], &a[i]);
    258. exchange = 1;
    259. }
    260. }
    261. if (exchange == 0)
    262. {
    263. break;
    264. }
    265. }
    266. 写法2
    267. //int end = n;
    268. //while (end > 0)
    269. //{
    270. // for (int i = 1; i < end; ++i)
    271. // {
    272. // if (a[i - 1] > a[i])
    273. // {
    274. // Swap(&a[i - 1], &a[i]);
    275. // }
    276. // }
    277. // --end;
    278. //}
    279. }
    280. /
    281. 快速排序——写法1:挖坑法(单趟分析版)
    282. 单趟排序时间复杂度:O(N)
    283. //void QuickSort(int* a, int n)
    284. //{
    285. // int begin = 0, end = n - 1;
    286. // int pivot = begin;
    287. // int key = a[begin]; //指定了第一次关键字为begin
    288. //
    289. // while (begin < end)
    290. // {
    291. // //右边找小,放到左边
    292. // while (begin < end && a[end] >= key)
    293. // {
    294. // --end;
    295. // }
    296. // //小的放到左边的坑里,自己形成新的坑位
    297. // a[pivot] = a[end];
    298. // pivot = end;
    299. // //左边找大
    300. // while (begin < end && a[begin] <= key)
    301. // {
    302. // ++begin;
    303. // }
    304. // //大的放到左边的坑里,自己形成新的坑位
    305. // a[pivot] = a[begin];
    306. // pivot = begin;
    307. //
    308. // }
    309. // pivot = begin;
    310. // a[pivot] = key;
    311. //}
    312. 快速排序——写法1:挖坑法(实现排序版)
    313. 时间复杂度:
    314. 最坏情况:有序-->O O(N^2) ,性能相当于插入排序。 解决:“三数取中法”,使其取得key不是最大或最小
    315. //void QuickSort(int* a, int left, int right)
    316. //{
    317. // if (left >= right)
    318. // return;
    319. // int begin = left, end = right;
    320. // int pivot = begin;
    321. // int key = a[begin]; //指定了第一次关键字为begin
    322. //
    323. // while (begin < end) //单趟排序
    324. // {
    325. // //右边找小,放到左边
    326. // while (begin < end && a[end] >= key)
    327. // {
    328. // --end;
    329. // }
    330. // //小的放到左边的坑里,自己形成新的坑位
    331. // a[pivot] = a[end];
    332. // pivot = end;
    333. // //左边找大
    334. // while (begin < end && a[begin] <= key)
    335. // {
    336. // ++begin;
    337. // }
    338. // //大的放到左边的坑里,自己形成新的坑位
    339. // a[pivot] = a[begin];
    340. // pivot = begin;
    341. //
    342. // }
    343. // pivot = begin;
    344. // a[pivot] = key;
    345. //
    346. // // [left, right]
    347. // // [left, pivot-1] pivot [pivot+1, right]
    348. // // 左子区间和右子区间有序,我们就有序了,如果让他们有序呢? 分治递归
    349. // QuickSort(a, left, pivot - 1);
    350. // QuickSort(a, pivot + 1, right);
    351. //}
    352. //
    353. 快速排序——写法2:挖坑法优化--->(三数取中,解决原始数据有序情况)
    354. 三数取中
    355. //int GetMidIndex(int* a, int left, int right)
    356. //{
    357. // int mid = (left + right) >> 1;
    358. // if (a[left] < a[mid])
    359. // {
    360. // if (a[mid] < a[right])
    361. // {
    362. // return mid;
    363. // }
    364. // else if (a[left] > a[right])
    365. // {
    366. // return left;
    367. // }
    368. // else
    369. // {
    370. // return right;
    371. // }
    372. // }
    373. // else // a[left] > a[mid]
    374. // {
    375. // if (a[mid] > a[right])
    376. // {
    377. // return mid;
    378. // }
    379. // else if (a[left] < a[right])
    380. // {
    381. // return left;
    382. // }
    383. // else
    384. // {
    385. // return right;
    386. // }
    387. // }
    388. //}
    389. //void QuickSort(int* a, int left, int right)
    390. //{
    391. // if (left >= right)
    392. // return;
    393. // int keyIndex = GetMidIndex(a, left, right); //三数取中,解决原始数据有序的性能下降
    394. // Swap(&a[left], &a[keyIndex]);
    395. //
    396. // int begin = left, end = right;
    397. // int pivot = begin;
    398. // int key = a[begin];
    399. //
    400. // while (begin < end) //单趟排序 O(N)
    401. // {
    402. // // 右边找小,放到左边
    403. // while (begin < end && a[end] >= key)
    404. // --end;
    405. //
    406. // // 小的放到左边的坑里,自己形成新的坑位
    407. // a[pivot] = a[end];
    408. // pivot = end;
    409. //
    410. // // 左边找大
    411. // while (begin < end && a[begin] <= key)
    412. // ++begin;
    413. //
    414. // // 大的放到左边的坑里,自己形成新的坑位
    415. // a[pivot] = a[begin];
    416. // pivot = begin;
    417. // }
    418. //
    419. // pivot = begin;
    420. // a[pivot] = key;
    421. //
    422. // // [left, right]
    423. // // [left, pivot-1] pivot [pivot+1, right]
    424. // // 左子区间和右子区间有序,我们就有序了,如果让他们有序呢? 分治递归
    425. // QuickSort(a, left, pivot - 1);
    426. // QuickSort(a, pivot + 1, right);
    427. //}
    428. 快速排序——写法3:挖坑法优化--->(三数取中,解决原始数据有序情况),再根据处理量分情况排序(小区间优化)
    429. 三数取中
    430. //int GetMidIndex(int* a, int left, int right)
    431. //{
    432. // int mid = (left + right) >> 1;
    433. // if (a[left] < a[mid])
    434. // {
    435. // if (a[mid] < a[right])
    436. // {
    437. // return mid;
    438. // }
    439. // else if (a[left] > a[right])
    440. // {
    441. // return left;
    442. // }
    443. // else
    444. // {
    445. // return right;
    446. // }
    447. // }
    448. // else // a[left] > a[mid]
    449. // {
    450. // if (a[mid] > a[right])
    451. // {
    452. // return mid;
    453. // }
    454. // else if (a[left] < a[right])
    455. // {
    456. // return left;
    457. // }
    458. // else
    459. // {
    460. // return right;
    461. // }
    462. // }
    463. //}
    464. //void QuickSort(int* a, int left, int right)
    465. //{
    466. // if (left >= right)
    467. // return;
    468. // int keyIndex = GetMidIndex(a, left, right);
    469. // Swap(&a[left], &a[keyIndex]);
    470. //
    471. // int begin = left, end = right;
    472. // int pivot = begin;
    473. // int key = a[begin];
    474. //
    475. // // O(N)
    476. // while (begin < end)
    477. // {
    478. // // 右边找小,放到左边
    479. // while (begin < end && a[end] >= key)
    480. // --end;
    481. //
    482. // // 小的放到左边的坑里,自己形成新的坑位
    483. // a[pivot] = a[end];
    484. // pivot = end;
    485. //
    486. // // 左边找大
    487. // while (begin < end && a[begin] <= key)
    488. // ++begin;
    489. //
    490. // // 大的放到左边的坑里,自己形成新的坑位
    491. // a[pivot] = a[begin];
    492. // pivot = begin;
    493. // }
    494. //
    495. // pivot = begin;
    496. // a[pivot] = key;
    497. //
    498. // // 小区间优化
    499. // //这个值会随原始数据量改变,而官方给13左右
    500. // if (pivot - 1 - left > 10) //官方给13左右
    501. // {
    502. // QuickSort(a, left, pivot - 1);
    503. // }
    504. // else
    505. // {
    506. // //InsertSort(int* a, int n)
    507. // InsertSort(a + left, pivot - 1 - left + 1); //left不一定从0开始,传数据个数
    508. // }
    509. //
    510. // if (right - (pivot + 1) > 10)
    511. // {
    512. // QuickSort(a, pivot + 1, right);
    513. // }
    514. // else
    515. // {
    516. // InsertSort(a + pivot + 1, right - (pivot + 1) + 1);
    517. // }
    518. //}
    519. 快速排序——写法4:左右指针法:找小找大交换
    520. 三数取中
    521. //int GetMidIndex(int* a, int left, int right)
    522. //{
    523. // int mid = (left + right) >> 1;
    524. // if (a[left] < a[mid])
    525. // {
    526. // if (a[mid] < a[right])
    527. // {
    528. // return mid;
    529. // }
    530. // else if (a[left] > a[right])
    531. // {
    532. // return left;
    533. // }
    534. // else
    535. // {
    536. // return right;
    537. // }
    538. // }
    539. // else // a[left] > a[mid]
    540. // {
    541. // if (a[mid] > a[right])
    542. // {
    543. // return mid;
    544. // }
    545. // else if (a[left] < a[right])
    546. // {
    547. // return left;
    548. // }
    549. // else
    550. // {
    551. // return right;
    552. // }
    553. // }
    554. //}
    555. 左右指针法:找小找大交换
    556. //void QuickSort(int* a, int left, int right)
    557. //{
    558. // if (left >= right)
    559. // return;
    560. //
    561. // int index = GetMidIndex(a, left, right);
    562. // Swap(&a[left], &a[index]);
    563. //
    564. // int begin = left, end = right;
    565. // int keyi = begin;
    566. //
    567. // while (begin < end)
    568. // {
    569. // // 找小
    570. // while (begin < end && a[end] >= a[keyi])
    571. // {
    572. // --end;
    573. // }
    574. //
    575. // // 找大
    576. // while (begin < end && a[begin] <= a[keyi])
    577. // {
    578. // ++begin;
    579. // }
    580. //
    581. // Swap(&a[begin], &a[end]);
    582. // }
    583. //
    584. // Swap(&a[begin], &a[keyi]);
    585. // int key = begin;
    586. //
    587. // // 小区间优化
    588. // //这个值会随原始数据量改变,而官方给13左右
    589. // if (key - 1 - left > 10) //官方给13左右
    590. // {
    591. // QuickSort(a, left, key - 1);
    592. // }
    593. // else
    594. // {
    595. // //InsertSort(int* a, int n)
    596. // InsertSort(a + left, key - 1 - left + 1); //left不一定从0开始,传数据个数
    597. // }
    598. //
    599. // if (right - (key + 1) > 10)
    600. // {
    601. // QuickSort(a, key + 1, right);
    602. // }
    603. // else
    604. // {
    605. // InsertSort(a + key + 1, right - (key + 1) + 1);
    606. // }
    607. //}
    608. //快速排序——写法5:前后指针法:cur找小,每次找到比keyi小额值,就++prev,然后交换prev与cur的位置交换
    609. //1.会有自己与自己交换的情况,2.也有异步交换,3.最后实现左边全为小于key,右边全为大于key
    610. // 三数取中
    611. int GetMidIndex(int* a, int left, int right)
    612. {
    613. int mid = (left + right) >> 1;
    614. if (a[left] < a[mid])
    615. {
    616. if (a[mid] < a[right])
    617. {
    618. return mid;
    619. }
    620. else if (a[left] > a[right])
    621. {
    622. return left;
    623. }
    624. else
    625. {
    626. return right;
    627. }
    628. }
    629. else // a[left] > a[mid]
    630. {
    631. if (a[mid] > a[right])
    632. {
    633. return mid;
    634. }
    635. else if (a[left] < a[right])
    636. {
    637. return left;
    638. }
    639. else
    640. {
    641. return right;
    642. }
    643. }
    644. }
    645. //前后指针法
    646. void QuickSort(int* a, int left, int right)
    647. {
    648. if (left >= right)
    649. return;
    650. int index = GetMidIndex(a, left, right);
    651. Swap(&a[left], &a[index]);
    652. int keyi = left;
    653. int prev = left, cur = left + 1;
    654. while (cur <= right)
    655. {
    656. if (a[cur] < a[keyi]
    657. && ++prev != cur) //++prev != cur:优化自己与自己交换的情况
    658. {
    659. Swap(&a[prev], &a[cur]);
    660. }
    661. ++cur;
    662. }
    663. Swap(&a[keyi], &a[prev]);
    664. int key = prev;
    665. // 小区间优化
    666. //这个值会随原始数据量改变,而官方给13左右
    667. if (key - 1 - left > 10) //官方给13左右
    668. {
    669. QuickSort(a, left, key - 1);
    670. }
    671. else
    672. {
    673. //InsertSort(int* a, int n)
    674. InsertSort(a + left, key - 1 - left + 1); //left不一定从0开始,传数据个数
    675. }
    676. if (right - (key + 1) > 10)
    677. {
    678. QuickSort(a, key + 1, right);
    679. }
    680. else
    681. {
    682. InsertSort(a + key + 1, right - (key + 1) + 1);
    683. }
    684. }
    685. //递归的缺陷:若递归的深度太深,程序没错,但是栈的空间不够用,会导致溢出
    686. //递归改非递归:方法1:(简单的)可以直接改循环 2.(复杂一点)使用数据结构的栈进行模拟递归过程
    687. //快速排序——非递归版
    688. //(复杂一点)使用数据结构的栈进行模拟递归过程:不会再有栈溢出问题,也会有空间消耗
    689. //但数据结构中的栈是malloc出来的,开辟在堆(操作系统对内存的划分),而堆的空间比栈大
    690. void QuickSortNonR(int* a, int n)
    691. {
    692. ST st;
    693. StackInit(&st);
    694. StackPush(&st, n - 1);
    695. StackPush(&st, 0);
    696. while (!StackEmpty(&st))
    697. {
    698. int left = StackTop(&st);
    699. StackPop(&st);
    700. int right = StackTop(&st);
    701. StackPop(&st);
    702. //调用单趟排序
    703. int index = GetMidIndex(a, left, right);
    704. //Swap(&a[left], &a[index]);
    705. int keyi = left;
    706. int prev = left, cur = left + 1;
    707. while (cur <= right)
    708. {
    709. if (a[cur] < a[keyi]
    710. && ++prev != cur) //++prev != cur:优化自己与自己交换的情况
    711. {
    712. Swap(&a[prev], &a[cur]);
    713. }
    714. ++cur;
    715. }
    716. Swap(&a[keyi], &a[prev]);
    717. int keyIndex = prev;
    718. //栈里面的就需要单趟分割排序
    719. //[left,keyIndex-1] keyIndex [keyIndex+1,right]
    720. if (keyIndex + 1 < right)
    721. {
    722. StackPush(&st, right);
    723. StackPush(&st, keyIndex+1);
    724. }
    725. if (left < keyIndex - 1)
    726. {
    727. StackPush(&st, keyIndex - 1);
    728. StackPush(&st, left);
    729. }
    730. }
    731. StackDestory(&st);
    732. }
    733. ///
    734. //归并排序
    735. //1.假设左半区间、右半区间有序,依次对比取小的放到新的临时数组
    736. //2.若左半区间、右半区间没有序,则递归进行
    737. void _MergeSort(int* a, int left, int right, int* tmp)
    738. {
    739. if (left >= right)
    740. return;
    741. int mid = (left + right) >> 1;
    742. //假设 [left, mid] [mid+1, right]有序,那么我们就可以归并了
    743. _MergeSort(a, left, mid, tmp);
    744. _MergeSort(a, mid + 1, right, tmp);
    745. // 归并
    746. int begin1 = left, end1 = mid;
    747. int begin2 = mid + 1, end2 = right;
    748. int index = left;
    749. while (begin1 <= end1 && begin2 <= end2)
    750. {
    751. if (a[begin1] < a[begin2])
    752. {
    753. tmp[index++] = a[begin1++];
    754. }
    755. else
    756. {
    757. tmp[index++] = a[begin2++];
    758. }
    759. }
    760. while (begin1 <= end1)
    761. {
    762. tmp[index++] = a[begin1++];
    763. }
    764. while (begin2 <= end2)
    765. {
    766. tmp[index++] = a[begin2++];
    767. }
    768. // 拷贝回去
    769. for (int i = left; i <= right; ++i)
    770. {
    771. a[i] = tmp[i];
    772. }
    773. }
    774. void MergeSort(int* a, int n)
    775. {
    776. int* tmp = (int*)malloc(sizeof(int) * n); //空间复杂度为O(N)
    777. _MergeSort(a, 0, n - 1, tmp);
    778. free(tmp);
    779. }
    780. //归并排序——非递归版
    781. //(复杂一点)使用数据结构的栈进行模拟递归过程
    782. //归并排序的非递归:先相邻两两归并,再四四归并,依次扩大
    783. void MergeSortNonR(int* a, int n)
    784. {
    785. int* tmp = (int*)malloc(sizeof(int) * n);
    786. int gap = 1; //每组数据个数
    787. while (gap < n)
    788. {
    789. for (int i = 0; i < n; i += 2 * gap)
    790. {
    791. //[i,i+gap-1] [i+gap,i+2*gap-1]
    792. // 归并
    793. int begin1 = i, end1 = i + gap - 1;
    794. int begin2 = i + gap, end2 = i + 2 * gap - 1;
    795. //归并过程中右半区间可能就不存在
    796. if (begin2 >= n)
    797. break;
    798. //归并过程中右半区间算多了,修正
    799. if (end2 >= n)
    800. {
    801. end2 = n - 1;
    802. }
    803. int index = i;
    804. while (begin1 <= end1 && begin2 <= end2)
    805. {
    806. if (a[begin1] < a[begin2])
    807. {
    808. tmp[index++] = a[begin1++];
    809. }
    810. else
    811. {
    812. tmp[index++] = a[begin2++];
    813. }
    814. }
    815. while (begin1 <= end1)
    816. {
    817. tmp[index++] = a[begin1++];
    818. }
    819. while (begin2 <= end2)
    820. {
    821. tmp[index++] = a[begin2++];
    822. }
    823. // 拷贝回去
    824. for (int j = i; j < end2; ++j)
    825. {
    826. a[j] = tmp[j];
    827. }
    828. }
    829. gap *= 2;
    830. }
    831. free(tmp);
    832. }
    833. //归并排序,也叫外排序,还可以对文件中数据进行排序
    834. //假设10G的数据放到硬盘中,要排序可能内存不够,假设有1G内存可以用,如何排序?
    835. //依次读文件,每次读1G到内存中放到一个数组,用快排对其进行排序,再写到一个文件,2G、4G、8G归并需要借助在磁盘归并
    836. //磁盘只能依次读数据
    837. //非比较排序
    838. //
    839. //基数排序(桶排序)实际中运用少,只对整数排序
    840. //
    841. //计数排序
    842. //统计数据个数,不进行比较
    843. //时间复杂度:O(range+N)
    844. //空间复杂度:O(range)
    845. //说明计数排序适用于范围集中的数据
    846. //使用相对映射,也可对负数进行排序
    847. //字符串、浮点数等等不行
    848. void CountSort(int* a, int n)
    849. {
    850. int min = a[0], max = a[0];
    851. for (int i = 1; i < n; ++i)
    852. {
    853. if (a[i] < min)
    854. min = a[i];
    855. if (a[i] > max)
    856. max = a[i];
    857. }
    858. int range = max - min + 1;
    859. int* countA = (int*)malloc(sizeof(int) * range);
    860. assert(countA);
    861. memset(countA, 0, sizeof(int) * range);
    862. //计数
    863. for (int i = 0; i < n; ++i)
    864. countA[a[i] - min]++;
    865. //排序
    866. int j = 0;
    867. for (int i = 0; i < range; ++i)
    868. {
    869. while (countA[i]--)
    870. {
    871. a[j++] = i + min;
    872. }
    873. }
    874. }

    Test.c:

    1. #include"Sort.h"
    2. #include"Stack.h"
    3. void TestInsertSort()
    4. {
    5. int a[] = { 3, 5, 2, 7, 8, 6, 1, 9, 4, 0 };
    6. PrintArray(a, sizeof(a) / sizeof(int));
    7. InsertSort(a, sizeof(a) / sizeof(int));
    8. PrintArray(a, sizeof(a) / sizeof(int));
    9. }
    10. void TestShellSort()
    11. {
    12. int a[] = { 3, 5, 2, 7, 8, 6, 1, 9, 4, 0 };
    13. PrintArray(a, sizeof(a) / sizeof(int));
    14. ShellSort(a, sizeof(a) / sizeof(int));
    15. PrintArray(a, sizeof(a) / sizeof(int));
    16. }
    17. void TestHeapSort()
    18. {
    19. int a[] = { 3, 5, 2, 7, 8, 6, 1, 9, 4, 0 };
    20. PrintArray(a, sizeof(a) / sizeof(int));
    21. HeapSort(a, sizeof(a) / sizeof(int));
    22. PrintArray(a, sizeof(a) / sizeof(int));
    23. }
    24. void TestSelectSort()
    25. {
    26. int a[] = { 9, 3, 5, 2, 7, 8, 6, -1, 9, 4, 0 };
    27. PrintArray(a, sizeof(a) / sizeof(int));
    28. SelectSort(a, sizeof(a) / sizeof(int));
    29. PrintArray(a, sizeof(a) / sizeof(int));
    30. }
    31. void TestBubbleSort()
    32. {
    33. int a[] = { 9, 3, 5, 2, 7, 8, 6, -1, 9, 4, 0 };
    34. PrintArray(a, sizeof(a) / sizeof(int));
    35. BubbleSort(a, sizeof(a) / sizeof(int));
    36. PrintArray(a, sizeof(a) / sizeof(int));
    37. }
    38. void TestQuickSort()
    39. {
    40. int a[] = { 6, 3, 5, 2, 7, 8, 9, 4, 1 };
    41. //int a[] = { 49, 38, 65, 97, 76, 13, 27, 49};
    42. //int a[] = { 49, 38, 65, 97, 76, 13, 27, 49, 13, 27, 49 };
    43. PrintArray(a, sizeof(a) / sizeof(int));
    44. //QuickSort(a, sizeof(a) / sizeof(int) ); //快速排序——写法1:挖坑法(单趟分析版)
    45. QuickSort(a, 0, sizeof(a) / sizeof(int)-1); //快速排序——写法1:挖坑法(实现排序版)
    46. PrintArray(a, sizeof(a) / sizeof(int));
    47. }
    48. void TestMergeSort()
    49. {
    50. //int a[] = { 10, 6, 7 ,1, 3, 9, 4, 2 };
    51. int a[] = { 49, 38, 65, 97, 76, 13, 27, 49, 13, 27, 49 };
    52. PrintArray(a, sizeof(a) / sizeof(int));
    53. MergeSort(a, sizeof(a) / sizeof(int));
    54. PrintArray(a, sizeof(a) / sizeof(int));
    55. }
    56. void TestQuickSortNonR()
    57. {
    58. //int a[] = { 6, 3, 5, 2, 7, 8, 9, 4, 1 };
    59. //int a[] = { 49, 38, 65, 97, 76, 13, 27, 49};
    60. int a[] = { 49, 38, 65, 97, 76, 13, 27, 49, 13, 27, 49 };
    61. PrintArray(a, sizeof(a) / sizeof(int));
    62. QuickSortNonR(a, sizeof(a) / sizeof(int));
    63. PrintArray(a, sizeof(a) / sizeof(int));
    64. }
    65. void TestMergeSortNonR()
    66. {
    67. //int a[] = { 10, 6, 7 ,1, 3, 9, 4, 2 };
    68. int a[] = { 49, 38, 65, 97, 76, 13, 27, 49, 13, 27, 49 };
    69. PrintArray(a, sizeof(a) / sizeof(int));
    70. MergeSortNonR(a, sizeof(a) / sizeof(int));
    71. PrintArray(a, sizeof(a) / sizeof(int));
    72. }
    73. void TestCountSort()
    74. {
    75. //int a[] = { 10, 6, 7 ,1, 3, 9, 4, 2 };
    76. int a[] = { 49, 38, 65, 97, 76, 13, 27, 49, 13, 27, 49 };
    77. PrintArray(a, sizeof(a) / sizeof(int));
    78. CountSort(a, sizeof(a) / sizeof(int));
    79. PrintArray(a, sizeof(a) / sizeof(int));
    80. }
    81. int main()
    82. {
    83. //TestInsertSort();
    84. //TestShellSort();
    85. //TestHeapSort();
    86. //TestSelectSort();
    87. //TestBubbleSort();
    88. //TestQuickSort();
    89. //TestMergeSort();
    90. //TestQuickSortNonR();
    91. //TestMergeSortNonR();
    92. TestCountSort();
    93. return 0;
    94. }

     注:

    由于这里的快速排序——非递归版,使用数据结构的栈进行模拟递归过程。因此要附用栈的实现代码。这里将栈的代码给出,使用时包含头文件,再复用即可!

    Stack.h:

    1. #pragma once
    2. #include
    3. #include
    4. #include
    5. #include
    6. typedef char STDataType;
    7. typedef struct Stack
    8. {
    9. STDataType* a; //通过数组实现栈的结构
    10. int top;
    11. int capacity;
    12. }ST;
    13. //初始化
    14. void StackInit(ST* ps);
    15. //释放内存、销毁空间
    16. void StackDestory(ST* ps);
    17. // 入栈
    18. void StackPush(ST* ps, STDataType x);
    19. // 出栈
    20. void StackPop(ST* ps);
    21. //取栈顶数据
    22. STDataType StackTop(ST* ps);
    23. //栈的大小
    24. int StackSize(ST* ps);
    25. //判空
    26. bool StackEmpty(ST* ps);

    Stack.c:

    1. #include"Stack.h"
    2. //初始化
    3. void StackInit(ST* ps)
    4. {
    5. assert(ps);
    6. ps->a = (STDataType*)malloc(sizeof(STDataType) * 4);
    7. if (ps->a == NULL)
    8. {
    9. printf("malloc fail!\n");
    10. exit(-1);
    11. }
    12. ps->capacity = 4;
    13. ps->top = 0; //这使得top最终指向的是栈顶的后一个位置。若top=-1,则最终指向的是栈顶。
    14. }
    15. //释放内存、销毁空间
    16. void StackDestory(ST* ps)
    17. {
    18. assert(ps);
    19. free(ps->a);
    20. ps->a = NULL;
    21. ps->top = ps->capacity = 0;
    22. }
    23. // 入栈
    24. void StackPush(ST* ps, STDataType x)
    25. {
    26. assert(ps);
    27. // 满了->增容
    28. if (ps->top == ps->capacity)
    29. {
    30. STDataType* tmp = (STDataType*)realloc(ps->a, ps->capacity * 2 * sizeof(STDataType));
    31. if (tmp == NULL)
    32. {
    33. printf("realloc fail!\n");
    34. exit(-1);
    35. }
    36. else
    37. {
    38. ps->a = tmp;
    39. ps->capacity *= 2;
    40. }
    41. }
    42. ps->a[ps->top] = x;
    43. ps->top++;
    44. }
    45. // 出栈
    46. void StackPop(ST* ps)
    47. {
    48. assert(ps);
    49. // 栈空了,再调用Pop,就会直接中止程序报错
    50. assert(ps->top > 0);
    51. //ps->a[ps->top - 1] = 0; //置为0只考虑了int型等,若为char、double等就不适用了。
    52. ps->top--;
    53. }
    54. //取栈顶数据
    55. STDataType StackTop(ST* ps)
    56. {
    57. assert(ps);
    58. // 栈空了,再调用Top,就会直接中止程序报错
    59. assert(ps->top > 0);
    60. return ps->a[ps->top - 1];
    61. }
    62. //求栈大小
    63. int StackSize(ST* ps)
    64. {
    65. assert(ps);
    66. return ps->top;
    67. }
    68. //判空
    69. bool StackEmpty(ST* ps)
    70. {
    71. assert(ps);
    72. return ps->top == 0;
    73. }
    74. //判断括号是否匹配算法
    75. bool isValid(char* s) {
    76. ST st;
    77. StackInit(&st);
    78. while (*s != '\0')
    79. {
    80. switch (*s)
    81. {
    82. case '{':
    83. case '[':
    84. case '(':
    85. {
    86. StackPush(&st, *s);
    87. ++s;
    88. break;
    89. }
    90. case '}':
    91. case ']':
    92. case ')':
    93. {
    94. if (StackEmpty(&st))
    95. {
    96. StackDestory(&st);
    97. return false;
    98. }
    99. char top = StackTop(&st);
    100. StackPop(&st);
    101. // 不匹配
    102. if ((*s == '}' && top != '{')
    103. || (*s == ']' && top != '[')
    104. || (*s == ')' && top != '('))
    105. {
    106. StackDestory(&st);
    107. return false;
    108. }
    109. else // 匹配
    110. {
    111. ++s;
    112. }
    113. break;
    114. }
    115. default:
    116. break;
    117. }
    118. }
    119. bool ret = StackEmpty(&st);
    120. StackDestory(&st);
    121. return ret;
    122. }

    3. 各大排序性能对比分析:

     1. 堆排序性能对比测试:

    测试代码:

    1. #pragma once
    2. #include
    3. #include
    4. /
    5. //堆排序对比测试:
    6. void Swap(int* p1, int* p2)
    7. {
    8. int tmp = *p1;
    9. *p1 = *p2;
    10. *p2 = tmp;
    11. }
    12. //(1)建小堆,向上调整,最终为大堆---- - 用于堆排降序
    13. //1.堆排序调整-向下调整法
    14. void AdjustDwon1(int* a, int n, int root)
    15. {
    16. int parent = root;
    17. int child = parent * 2 + 1; // 默认是左孩子
    18. //建小堆,再调整
    19. while (child < n)
    20. {
    21. // 1、选出左右孩子中小的那一个
    22. if (child + 1 < n && a[child + 1] < a[child])
    23. {
    24. child += 1;
    25. }
    26. if (a[child] < a[parent])
    27. {
    28. Swap(&a[child], &a[parent]);
    29. parent = child;
    30. child = parent * 2 + 1;
    31. }
    32. else
    33. {
    34. break;
    35. }
    36. }
    37. }
    38. //2.堆排序调整-向上调整法
    39. void AdjustUp1(int* a, int child)
    40. {
    41. int parent = (child - 1) / 2;
    42. //建小堆,再调整
    43. while (child > 0)
    44. {
    45. if (a[child] < a[parent])
    46. {
    47. Swap(&a[child], &a[parent]);
    48. child = parent;
    49. parent = (child - 1) / 2;
    50. }
    51. else
    52. {
    53. break;
    54. }
    55. }
    56. }
    57. //堆排序(建堆)
    58. void HeapSort1(int* a, int n)
    59. {
    60. //建堆 调整
    61. //向上调整法
    62. for (int i = 1; i < n; ++i)
    63. {
    64. AdjustUp1(a, i);
    65. }
    66. int end = n - 1;
    67. while (end > 0)
    68. {
    69. Swap(&a[0], &a[end]);
    70. AdjustDwon1(a, end, 0);
    71. --end;
    72. }
    73. }
    74. //(2)建大堆,向上调整,最终为小堆---- - 用于堆排升序
    75. //1.堆排序调整-向下调整法
    76. void AdjustDwon2(int* a, int n, int root)
    77. {
    78. int parent = root;
    79. int child = parent * 2 + 1; // 默认是左孩子
    80. //建大堆,再调整
    81. while (child < n)
    82. {
    83. // 1、选出左右孩子中大的那一个
    84. if (child + 1 < n && a[child + 1] > a[child])
    85. {
    86. child += 1;
    87. }
    88. if (a[child] > a[parent])
    89. {
    90. Swap(&a[child], &a[parent]);
    91. parent = child;
    92. child = parent * 2 + 1;
    93. }
    94. else
    95. {
    96. break;
    97. }
    98. }
    99. }
    100. //2.堆排序调整-向上调整法
    101. void AdjustUp2(int* a, int child)
    102. {
    103. int parent = (child - 1) / 2;
    104. //1.建大堆,再调整
    105. while (child > 0)
    106. {
    107. if (a[child] > a[parent])
    108. {
    109. Swap(&a[child], &a[parent]);
    110. child = parent;
    111. parent = (child - 1) / 2;
    112. }
    113. else
    114. {
    115. break;
    116. }
    117. }
    118. }
    119. //堆排序(建堆)
    120. void HeapSort2(int* a, int n)
    121. {
    122. // 建堆 调整
    123. //向上调整法
    124. for (int i = 1; i < n; ++i)
    125. {
    126. AdjustUp2(a, i);
    127. }
    128. int end = n - 1;
    129. while (end > 0)
    130. {
    131. Swap(&a[0], &a[end]);
    132. AdjustDwon2(a, end, 0);
    133. --end;
    134. }
    135. }
    136. //(3)建小堆,向下调整,最终为大堆---- - 用于堆排降序(可以实现,多此一举)
    137. //1.堆排序调整-向下调整法
    138. void AdjustDwon3(int* a, int n, int root)
    139. {
    140. int parent = root;
    141. int child = parent * 2 + 1; // 默认是左孩子
    142. //建小堆,再调整
    143. while (child < n)
    144. {
    145. // 1、选出左右孩子中小的那一个
    146. if (child + 1 < n && a[child + 1] < a[child])
    147. {
    148. child += 1;
    149. }
    150. if (a[child] < a[parent])
    151. {
    152. Swap(&a[child], &a[parent]);
    153. parent = child;
    154. child = parent * 2 + 1;
    155. }
    156. else
    157. {
    158. break;
    159. }
    160. }
    161. }
    162. //2.堆排序调整-向上调整法
    163. void AdjustUp3(int* a, int child)
    164. {
    165. int parent = (child - 1) / 2;
    166. //建小堆,再调整
    167. while (child > 0)
    168. {
    169. if (a[child] < a[parent])
    170. {
    171. Swap(&a[child], &a[parent]);
    172. child = parent;
    173. parent = (child - 1) / 2;
    174. }
    175. else
    176. {
    177. break;
    178. }
    179. }
    180. }
    181. //堆排序(建堆)
    182. void HeapSort3(int* a, int n)
    183. {
    184. // 建堆 调整
    185. //向下调整法
    186. for (int i = (n - 1 - 1) / 2; i >= 0; --i)
    187. {
    188. AdjustDwon3(a, n, i);
    189. }
    190. int end = n - 1;
    191. while (end > 0)
    192. {
    193. Swap(&a[0], &a[end]);
    194. AdjustDwon3(a, end, 0);
    195. --end;
    196. }
    197. }
    198. //(4)建大堆,向下调整,最终为小堆---- - 用于堆排升序
    199. //1.堆排序调整-向下调整法
    200. void AdjustDwon4(int* a, int n, int root)
    201. {
    202. int parent = root;
    203. int child = parent * 2 + 1; // 默认是左孩子
    204. //建大堆,再调整
    205. while (child < n)
    206. {
    207. // 1、选出左右孩子中大的那一个
    208. if (child + 1 < n && a[child + 1] > a[child])
    209. {
    210. child += 1;
    211. }
    212. if (a[child] > a[parent])
    213. {
    214. Swap(&a[child], &a[parent]);
    215. parent = child;
    216. child = parent * 2 + 1;
    217. }
    218. else
    219. {
    220. break;
    221. }
    222. }
    223. }
    224. //2.堆排序调整-向上调整法
    225. void AdjustUp4(int* a, int child)
    226. {
    227. int parent = (child - 1) / 2;
    228. //建大堆,再调整
    229. while (child > 0)
    230. {
    231. if (a[child] > a[parent])
    232. {
    233. Swap(&a[child], &a[parent]);
    234. child = parent;
    235. parent = (child - 1) / 2;
    236. }
    237. else
    238. {
    239. break;
    240. }
    241. }
    242. }
    243. //堆排序(建堆)
    244. void HeapSort4(int* a, int n)
    245. {
    246. // 建堆 调整
    247. //向下调整法
    248. for (int i = (n - 1 - 1) / 2; i >= 0; --i)
    249. {
    250. AdjustDwon4(a, n, i);
    251. }
    252. int end = n - 1;
    253. while (end > 0)
    254. {
    255. Swap(&a[0], &a[end]);
    256. AdjustDwon4(a, end, 0);
    257. --end;
    258. }
    259. }
    260. void TestOP()
    261. {
    262. srand(time(0));
    263. const int N = 100000;
    264. int* a1 = (int*)malloc(sizeof(int) * N);
    265. int* a2 = (int*)malloc(sizeof(int) * N);
    266. int* a3 = (int*)malloc(sizeof(int) * N);
    267. int* a4 = (int*)malloc(sizeof(int) * N);
    268. for (int i = 0; i < N; ++i)
    269. {
    270. a1[i] = rand();
    271. //a1[i] = i;
    272. a2[i] = a1[i];
    273. a3[i] = a1[i];
    274. a4[i] = a1[i];
    275. }
    276. int begin1 = clock();
    277. HeapSort1(a1, N);
    278. int end1 = clock();
    279. int begin2 = clock();
    280. HeapSort2(a2, N);
    281. int end2 = clock();
    282. int begin3 = clock();
    283. HeapSort3(a3, N);
    284. int end3 = clock();
    285. int begin4 = clock();
    286. HeapSort4(a4, N);
    287. int end4 = clock();
    288. printf("建小堆-向上调整-降序:%d\n", end1 - begin1);
    289. printf("建大堆-向上调整-升序:%d\n", end2 - begin2);
    290. printf("建小堆-向下调整-降序:%d\n", end3 - begin3);
    291. printf("建大堆-向下调整-升序:%d\n", end4 - begin4);
    292. free(a1);
    293. free(a2);
    294. free(a3);
    295. free(a4);
    296. }
    297. int main()
    298. {
    299. TestOP();
    300. return 0;
    301. }

     2.快速排序(递归版)性能对比测试:

     3.各大排序测试对比代码

    1. #pragma once
    2. #include
    3. #include
    4. #include
    5. #include"Stack.h"
    6. /
    7. //堆排序对比测试:
    8. void Swap(int* p1, int* p2)
    9. {
    10. int tmp = *p1;
    11. *p1 = *p2;
    12. *p2 = tmp;
    13. }
    14. //(1)建小堆,向上调整,最终为大堆---- - 用于堆排降序
    15. //1.堆排序调整-向下调整法
    16. void AdjustDwon1(int* a, int n, int root)
    17. {
    18. int parent = root;
    19. int child = parent * 2 + 1; // 默认是左孩子
    20. //建小堆,再调整
    21. while (child < n)
    22. {
    23. // 1、选出左右孩子中小的那一个
    24. if (child + 1 < n && a[child + 1] < a[child])
    25. {
    26. child += 1;
    27. }
    28. if (a[child] < a[parent])
    29. {
    30. Swap(&a[child], &a[parent]);
    31. parent = child;
    32. child = parent * 2 + 1;
    33. }
    34. else
    35. {
    36. break;
    37. }
    38. }
    39. }
    40. //2.堆排序调整-向上调整法
    41. void AdjustUp1(int* a, int child)
    42. {
    43. int parent = (child - 1) / 2;
    44. //建小堆,再调整
    45. while (child > 0)
    46. {
    47. if (a[child] < a[parent])
    48. {
    49. Swap(&a[child], &a[parent]);
    50. child = parent;
    51. parent = (child - 1) / 2;
    52. }
    53. else
    54. {
    55. break;
    56. }
    57. }
    58. }
    59. //堆排序(建堆)
    60. void HeapSort1(int* a, int n)
    61. {
    62. //建堆 调整
    63. //向上调整法
    64. for (int i = 1; i < n; ++i)
    65. {
    66. AdjustUp1(a, i);
    67. }
    68. int end = n - 1;
    69. while (end > 0)
    70. {
    71. Swap(&a[0], &a[end]);
    72. AdjustDwon1(a, end, 0);
    73. --end;
    74. }
    75. }
    76. //(2)建大堆,向上调整,最终为小堆---- - 用于堆排升序
    77. //1.堆排序调整-向下调整法
    78. void AdjustDwon2(int* a, int n, int root)
    79. {
    80. int parent = root;
    81. int child = parent * 2 + 1; // 默认是左孩子
    82. //建大堆,再调整
    83. while (child < n)
    84. {
    85. // 1、选出左右孩子中大的那一个
    86. if (child + 1 < n && a[child + 1] > a[child])
    87. {
    88. child += 1;
    89. }
    90. if (a[child] > a[parent])
    91. {
    92. Swap(&a[child], &a[parent]);
    93. parent = child;
    94. child = parent * 2 + 1;
    95. }
    96. else
    97. {
    98. break;
    99. }
    100. }
    101. }
    102. //2.堆排序调整-向上调整法
    103. void AdjustUp2(int* a, int child)
    104. {
    105. int parent = (child - 1) / 2;
    106. //1.建大堆,再调整
    107. while (child > 0)
    108. {
    109. if (a[child] > a[parent])
    110. {
    111. Swap(&a[child], &a[parent]);
    112. child = parent;
    113. parent = (child - 1) / 2;
    114. }
    115. else
    116. {
    117. break;
    118. }
    119. }
    120. }
    121. //堆排序(建堆)
    122. void HeapSort2(int* a, int n)
    123. {
    124. // 建堆 调整
    125. //向上调整法
    126. for (int i = 1; i < n; ++i)
    127. {
    128. AdjustUp2(a, i);
    129. }
    130. int end = n - 1;
    131. while (end > 0)
    132. {
    133. Swap(&a[0], &a[end]);
    134. AdjustDwon2(a, end, 0);
    135. --end;
    136. }
    137. }
    138. //(3)建小堆,向下调整,最终为大堆---- - 用于堆排降序(可以实现,多此一举)
    139. //1.堆排序调整-向下调整法
    140. void AdjustDwon3(int* a, int n, int root)
    141. {
    142. int parent = root;
    143. int child = parent * 2 + 1; // 默认是左孩子
    144. //建小堆,再调整
    145. while (child < n)
    146. {
    147. // 1、选出左右孩子中小的那一个
    148. if (child + 1 < n && a[child + 1] < a[child])
    149. {
    150. child += 1;
    151. }
    152. if (a[child] < a[parent])
    153. {
    154. Swap(&a[child], &a[parent]);
    155. parent = child;
    156. child = parent * 2 + 1;
    157. }
    158. else
    159. {
    160. break;
    161. }
    162. }
    163. }
    164. //2.堆排序调整-向上调整法
    165. void AdjustUp3(int* a, int child)
    166. {
    167. int parent = (child - 1) / 2;
    168. //建小堆,再调整
    169. while (child > 0)
    170. {
    171. if (a[child] < a[parent])
    172. {
    173. Swap(&a[child], &a[parent]);
    174. child = parent;
    175. parent = (child - 1) / 2;
    176. }
    177. else
    178. {
    179. break;
    180. }
    181. }
    182. }
    183. //堆排序(建堆)
    184. void HeapSort3(int* a, int n)
    185. {
    186. // 建堆 调整
    187. //向下调整法
    188. for (int i = (n - 1 - 1) / 2; i >= 0; --i)
    189. {
    190. AdjustDwon3(a, n, i);
    191. }
    192. int end = n - 1;
    193. while (end > 0)
    194. {
    195. Swap(&a[0], &a[end]);
    196. AdjustDwon3(a, end, 0);
    197. --end;
    198. }
    199. }
    200. //(4)建大堆,向下调整,最终为小堆---- - 用于堆排升序
    201. //1.堆排序调整-向下调整法
    202. void AdjustDwon4(int* a, int n, int root)
    203. {
    204. int parent = root;
    205. int child = parent * 2 + 1; // 默认是左孩子
    206. //建大堆,再调整
    207. while (child < n)
    208. {
    209. // 1、选出左右孩子中大的那一个
    210. if (child + 1 < n && a[child + 1] > a[child])
    211. {
    212. child += 1;
    213. }
    214. if (a[child] > a[parent])
    215. {
    216. Swap(&a[child], &a[parent]);
    217. parent = child;
    218. child = parent * 2 + 1;
    219. }
    220. else
    221. {
    222. break;
    223. }
    224. }
    225. }
    226. //2.堆排序调整-向上调整法
    227. void AdjustUp4(int* a, int child)
    228. {
    229. int parent = (child - 1) / 2;
    230. //建大堆,再调整
    231. while (child > 0)
    232. {
    233. if (a[child] > a[parent])
    234. {
    235. Swap(&a[child], &a[parent]);
    236. child = parent;
    237. parent = (child - 1) / 2;
    238. }
    239. else
    240. {
    241. break;
    242. }
    243. }
    244. }
    245. //堆排序(建堆)
    246. void HeapSort4(int* a, int n)
    247. {
    248. // 建堆 调整
    249. //向下调整法
    250. for (int i = (n - 1 - 1) / 2; i >= 0; --i)
    251. {
    252. AdjustDwon4(a, n, i);
    253. }
    254. int end = n - 1;
    255. while (end > 0)
    256. {
    257. Swap(&a[0], &a[end]);
    258. AdjustDwon4(a, end, 0);
    259. --end;
    260. }
    261. }
    262. //插入排序
    263. //时间复杂度:O(N^2)
    264. //最坏情况:逆序
    265. //最好情况:全部顺序 O(N)
    266. void InsertSort(int* a, int n)
    267. {
    268. //假设[0,end]有序,将end+1位置的值插入进去,让[0,end+1]有序
    269. for (int i = 0; i < n - 1; i++)
    270. {
    271. int end = i;
    272. int tmp = a[end + 1];
    273. while (end >= 0)
    274. {
    275. if (a[end] > tmp) //升序
    276. //if (a[end] < tmp) //降序
    277. {
    278. a[end + 1] = a[end];
    279. --end;
    280. }
    281. else
    282. {
    283. break;
    284. }
    285. }
    286. a[end + 1] = tmp;
    287. }
    288. }
    289. //快速排序——写法1:挖坑法(实现排序版)
    290. void QuickSort1(int* a, int left, int right)
    291. {
    292. if (left >= right)
    293. return;
    294. int begin = left, end = right;
    295. int pivot = begin;
    296. int key = a[begin]; //指定了第一次关键字为begin
    297. while (begin < end) //单趟排序
    298. {
    299. //右边找小,放到左边
    300. while (begin < end && a[end] >= key)
    301. {
    302. --end;
    303. }
    304. //小的放到左边的坑里,自己形成新的坑位
    305. a[pivot] = a[end];
    306. pivot = end;
    307. //左边找大
    308. while (begin < end && a[begin] <= key)
    309. {
    310. ++begin;
    311. }
    312. //大的放到左边的坑里,自己形成新的坑位
    313. a[pivot] = a[begin];
    314. pivot = begin;
    315. }
    316. pivot = begin;
    317. a[pivot] = key;
    318. // [left, right]
    319. // [left, pivot-1] pivot [pivot+1, right]
    320. // 左子区间和右子区间有序,我们就有序了,如果让他们有序呢? 分治递归
    321. QuickSort1(a, left, pivot - 1);
    322. QuickSort1(a, pivot + 1, right);
    323. }
    324. //快速排序——写法2:挖坑法优化--->(三数取中,解决原始数据有序情况),再根据处理量分情况排序(小区间优化)
    325. // 三数取中
    326. int GetMidIndex(int* a, int left, int right)
    327. {
    328. int mid = (left + right) >> 1;
    329. if (a[left] < a[mid])
    330. {
    331. if (a[mid] < a[right])
    332. {
    333. return mid;
    334. }
    335. else if (a[left] > a[right])
    336. {
    337. return left;
    338. }
    339. else
    340. {
    341. return right;
    342. }
    343. }
    344. else // a[left] > a[mid]
    345. {
    346. if (a[mid] > a[right])
    347. {
    348. return mid;
    349. }
    350. else if (a[left] < a[right])
    351. {
    352. return left;
    353. }
    354. else
    355. {
    356. return right;
    357. }
    358. }
    359. }
    360. void QuickSort2(int* a, int left, int right)
    361. {
    362. if (left >= right)
    363. return;
    364. int keyIndex = GetMidIndex(a, left, right);
    365. Swap(&a[left], &a[keyIndex]);
    366. int begin = left, end = right;
    367. int pivot = begin;
    368. int key = a[begin];
    369. // O(N)
    370. while (begin < end)
    371. {
    372. // 右边找小,放到左边
    373. while (begin < end && a[end] >= key)
    374. --end;
    375. // 小的放到左边的坑里,自己形成新的坑位
    376. a[pivot] = a[end];
    377. pivot = end;
    378. // 左边找大
    379. while (begin < end && a[begin] <= key)
    380. ++begin;
    381. // 大的放到左边的坑里,自己形成新的坑位
    382. a[pivot] = a[begin];
    383. pivot = begin;
    384. }
    385. pivot = begin;
    386. a[pivot] = key;
    387. // 小区间优化
    388. //这个值会随原始数据量改变,而官方给13左右
    389. if (pivot - 1 - left > 10) //官方给13左右
    390. {
    391. QuickSort2(a, left, pivot - 1);
    392. }
    393. else
    394. {
    395. //InsertSort(int* a, int n)
    396. InsertSort(a + left, pivot - 1 - left + 1); //left不一定从0开始,传数据个数
    397. }
    398. if (right - (pivot + 1) > 10)
    399. {
    400. QuickSort2(a, pivot + 1, right);
    401. }
    402. else
    403. {
    404. InsertSort(a + pivot + 1, right - (pivot + 1) + 1);
    405. }
    406. }
    407. //快速排序——写法3:左右指针法:找小找大交换
    408. void QuickSort3(int* a, int left, int right)
    409. {
    410. if (left >= right)
    411. return;
    412. int index = GetMidIndex(a, left, right);
    413. Swap(&a[left], &a[index]);
    414. int begin = left, end = right;
    415. int keyi = begin;
    416. while (begin < end)
    417. {
    418. // 找小
    419. while (begin < end && a[end] >= a[keyi])
    420. {
    421. --end;
    422. }
    423. // 找大
    424. while (begin < end && a[begin] <= a[keyi])
    425. {
    426. ++begin;
    427. }
    428. Swap(&a[begin], &a[end]);
    429. }
    430. Swap(&a[begin], &a[keyi]);
    431. int key = begin;
    432. // 小区间优化
    433. //这个值会随原始数据量改变,而官方给13左右
    434. if (key - 1 - left > 10) //官方给13左右
    435. {
    436. QuickSort3(a, left, key - 1);
    437. }
    438. else
    439. {
    440. //InsertSort(int* a, int n)
    441. InsertSort(a + left, key - 1 - left + 1); //left不一定从0开始,传数据个数
    442. }
    443. if (right - (key + 1) > 10)
    444. {
    445. QuickSort3(a, key + 1, right);
    446. }
    447. else
    448. {
    449. InsertSort(a + key + 1, right - (key + 1) + 1);
    450. }
    451. }
    452. //快速排序——写法4:前后指针法:cur找小,每次找到比keyi小额值,就++prev,然后交换prev与cur的位置交换
    453. //1.会有自己与自己交换的情况,2.也有异步交换,3.最后实现左边全为小于key,右边全为大于key
    454. void QuickSort4(int* a, int left, int right)
    455. {
    456. if (left >= right)
    457. return;
    458. int index = GetMidIndex(a, left, right);
    459. Swap(&a[left], &a[index]);
    460. int keyi = left;
    461. int prev = left, cur = left + 1;
    462. while (cur <= right)
    463. {
    464. if (a[cur] < a[keyi]
    465. && ++prev != cur) //++prev != cur:优化自己与自己交换的情况
    466. {
    467. Swap(&a[prev], &a[cur]);
    468. }
    469. ++cur;
    470. }
    471. Swap(&a[keyi], &a[prev]);
    472. int key = prev;
    473. // 小区间优化
    474. //这个值会随原始数据量改变,而官方给13左右
    475. if (key - 1 - left > 10) //官方给13左右
    476. {
    477. QuickSort4(a, left, key - 1);
    478. }
    479. else
    480. {
    481. //InsertSort(int* a, int n)
    482. InsertSort(a + left, key - 1 - left + 1); //left不一定从0开始,传数据个数
    483. }
    484. if (right - (key + 1) > 10)
    485. {
    486. QuickSort4(a, key + 1, right);
    487. }
    488. else
    489. {
    490. InsertSort(a + key + 1, right - (key + 1) + 1);
    491. }
    492. }
    493. //快速排序——非递归版
    494. //(复杂一点)使用数据结构的栈进行模拟递归过程:不会再有栈溢出问题,也会有空间消耗
    495. //但数据结构中的栈是malloc出来的,开辟在堆(操作系统对内存的划分),而堆的空间比栈大
    496. void QuickSortNonR(int* a, int n)
    497. {
    498. ST st;
    499. StackInit(&st);
    500. StackPush(&st, n - 1);
    501. StackPush(&st, 0);
    502. while (!StackEmpty(&st))
    503. {
    504. int left = StackTop(&st);
    505. StackPop(&st);
    506. int right = StackTop(&st);
    507. StackPop(&st);
    508. //调用单趟排序
    509. int index = GetMidIndex(a, left, right);
    510. //Swap(&a[left], &a[index]);
    511. int keyi = left;
    512. int prev = left, cur = left + 1;
    513. while (cur <= right)
    514. {
    515. if (a[cur] < a[keyi]
    516. && ++prev != cur) //++prev != cur:优化自己与自己交换的情况
    517. {
    518. Swap(&a[prev], &a[cur]);
    519. }
    520. ++cur;
    521. }
    522. Swap(&a[keyi], &a[prev]);
    523. int keyIndex = prev;
    524. //栈里面的就需要单趟分割排序
    525. //[left,keyIndex-1] keyIndex [keyIndex+1,right]
    526. if (keyIndex + 1 < right)
    527. {
    528. StackPush(&st, right);
    529. StackPush(&st, keyIndex + 1);
    530. }
    531. if (left < keyIndex - 1)
    532. {
    533. StackPush(&st, keyIndex - 1);
    534. StackPush(&st, left);
    535. }
    536. }
    537. StackDestory(&st);
    538. }
    539. void ShellSort(int* a, int n)
    540. {
    541. int gap = n; //可以自行设置,但不会给固定的值
    542. //把间隔为gap的多组数据同时排序(注意:理解这个多组的含义)
    543. //end最终位置:n-gap-1
    544. //gap的设置方式之一:
    545. while (gap > 1)
    546. {
    547. //gap=gap/2; //一定会保证最后一次为1 //运行了logN次
    548. gap = gap / 3 + 1; //但要保证最后一次为1 //运行了log3N次
    549. //gap>1时都是预排序,排序后接近有序
    550. //gap==1时,就是直接插入排序
    551. for (int i = 0; i < n - gap; i++)
    552. {
    553. int end = i;
    554. int tmp = a[end + gap];
    555. while (end >= 0)
    556. {
    557. if (a[end] > tmp)
    558. {
    559. a[end + gap] = a[end];
    560. end -= gap;
    561. }
    562. else
    563. {
    564. break;
    565. }
    566. }
    567. a[end + gap] = tmp;
    568. }
    569. }
    570. }
    571. void BubbleSort(int* a, int n)
    572. {
    573. //写法1:
    574. for (int j = 0; j < n; ++j)
    575. {
    576. int exchange = 0;
    577. for (int i = 1; i < n - j; ++i)
    578. {
    579. if (a[i - 1] > a[i])
    580. {
    581. Swap(&a[i - 1], &a[i]);
    582. exchange = 1;
    583. }
    584. }
    585. if (exchange == 0)
    586. {
    587. break;
    588. }
    589. }
    590. 写法2
    591. //int end = n;
    592. //while (end > 0)
    593. //{
    594. // for (int i = 1; i < end; ++i)
    595. // {
    596. // if (a[i - 1] > a[i])
    597. // {
    598. // Swap(&a[i - 1], &a[i]);
    599. // }
    600. // }
    601. // --end;
    602. //}
    603. }
    604. void _MergeSort(int* a, int left, int right, int* tmp)
    605. {
    606. if (left >= right)
    607. return;
    608. int mid = (left + right) >> 1;
    609. //假设 [left, mid] [mid+1, right]有序,那么我们就可以归并了
    610. _MergeSort(a, left, mid, tmp);
    611. _MergeSort(a, mid + 1, right, tmp);
    612. // 归并
    613. int begin1 = left, end1 = mid;
    614. int begin2 = mid + 1, end2 = right;
    615. int index = left;
    616. while (begin1 <= end1 && begin2 <= end2)
    617. {
    618. if (a[begin1] < a[begin2])
    619. {
    620. tmp[index++] = a[begin1++];
    621. }
    622. else
    623. {
    624. tmp[index++] = a[begin2++];
    625. }
    626. }
    627. while (begin1 <= end1)
    628. {
    629. tmp[index++] = a[begin1++];
    630. }
    631. while (begin2 <= end2)
    632. {
    633. tmp[index++] = a[begin2++];
    634. }
    635. // 拷贝回去
    636. for (int i = left; i <= right; ++i)
    637. {
    638. a[i] = tmp[i];
    639. }
    640. }
    641. void MergeSort(int* a, int n)
    642. {
    643. int* tmp = (int*)malloc(sizeof(int) * n); //空间复杂度为O(N)
    644. _MergeSort(a, 0, n - 1, tmp);
    645. free(tmp);
    646. }
    647. void MergeSortNonR(int* a, int n)
    648. {
    649. int* tmp = (int*)malloc(sizeof(int) * n);
    650. int gap = 1; //每组数据个数
    651. while (gap < n)
    652. {
    653. for (int i = 0; i < n; i += 2 * gap)
    654. {
    655. //[i,i+gap-1] [i+gap,i+2*gap-1]
    656. // 归并
    657. int begin1 = i, end1 = i + gap - 1;
    658. int begin2 = i + gap, end2 = i + 2 * gap - 1;
    659. //归并过程中右半区间可能就不存在
    660. if (begin2 >= n)
    661. break;
    662. //归并过程中右半区间算多了,修正
    663. if (end2 >= n)
    664. {
    665. end2 = n - 1;
    666. }
    667. int index = i;
    668. while (begin1 <= end1 && begin2 <= end2)
    669. {
    670. if (a[begin1] < a[begin2])
    671. {
    672. tmp[index++] = a[begin1++];
    673. }
    674. else
    675. {
    676. tmp[index++] = a[begin2++];
    677. }
    678. }
    679. while (begin1 <= end1)
    680. {
    681. tmp[index++] = a[begin1++];
    682. }
    683. while (begin2 <= end2)
    684. {
    685. tmp[index++] = a[begin2++];
    686. }
    687. // 拷贝回去
    688. for (int j = i; j < end2; ++j)
    689. {
    690. a[j] = tmp[j];
    691. }
    692. }
    693. gap *= 2;
    694. }
    695. free(tmp);
    696. }
    697. void CountSort(int* a, int n)
    698. {
    699. int min = a[0], max = a[0];
    700. for (int i = 1; i < n; ++i)
    701. {
    702. if (a[i] < min)
    703. min = a[i];
    704. if (a[i] > max)
    705. max = a[i];
    706. }
    707. int range = max - min + 1;
    708. int* countA = (int*)malloc(sizeof(int) * range);
    709. assert(countA);
    710. memset(countA, 0, sizeof(int) * range);
    711. //计数
    712. for (int i = 0; i < n; ++i)
    713. countA[a[i] - min]++;
    714. //排序
    715. int j = 0;
    716. for (int i = 0; i < range; ++i)
    717. {
    718. while (countA[i]--)
    719. {
    720. a[j++] = i + min;
    721. }
    722. }
    723. }
    724. void TestOP()
    725. {
    726. srand(time(0));
    727. const int N = 1000000;
    728. int* a1 = (int*)malloc(sizeof(int) * N);
    729. int* a2 = (int*)malloc(sizeof(int) * N);
    730. int* a3 = (int*)malloc(sizeof(int) * N);
    731. int* a4 = (int*)malloc(sizeof(int) * N);
    732. int* a5 = (int*)malloc(sizeof(int) * N);
    733. int* a6 = (int*)malloc(sizeof(int) * N);
    734. int* a7 = (int*)malloc(sizeof(int) * N);
    735. int* a8 = (int*)malloc(sizeof(int) * N);
    736. int* a9 = (int*)malloc(sizeof(int) * N);
    737. int* a10 = (int*)malloc(sizeof(int) * N);
    738. int* a11 = (int*)malloc(sizeof(int) * N);
    739. int* a12 = (int*)malloc(sizeof(int) * N);
    740. int* a13 = (int*)malloc(sizeof(int) * N);
    741. int* a14 = (int*)malloc(sizeof(int) * N);
    742. for (int i = 0; i < N; ++i)
    743. {
    744. a1[i] = rand();
    745. //a1[i] = i;
    746. a2[i] = a1[i];
    747. a3[i] = a1[i];
    748. a4[i] = a1[i];
    749. a5[i] = a1[i];
    750. a6[i] = a1[i];
    751. a7[i] = a1[i];
    752. a8[i] = a1[i];
    753. a9[i] = a1[i];
    754. a10[i] = a1[i];
    755. a11[i] = a1[i];
    756. a12[i] = a1[i];
    757. a13[i] = a1[i];
    758. a14[i] = a1[i];
    759. }
    760. int begin1 = clock();
    761. //HeapSort1(a1, N);
    762. int end1 = clock();
    763. int begin2 = clock();
    764. //HeapSort2(a2, N);
    765. int end2 = clock();
    766. int begin3 = clock();
    767. //HeapSort3(a3, N);
    768. int end3 = clock();
    769. int begin4 = clock();
    770. //HeapSort4(a4, N);
    771. int end4 = clock();
    772. int begin5 = clock();
    773. QuickSort1(a5, 0, N - 1);
    774. int end5 = clock();
    775. int begin6 = clock();
    776. QuickSort2(a6, 0, N - 1);
    777. int end6 = clock();
    778. int begin7 = clock();
    779. QuickSort3(a7, 0, N - 1);
    780. int end7 = clock();
    781. int begin8 = clock();
    782. QuickSort4(a8, 0, N - 1);
    783. int end8 = clock();
    784. int begin9 = clock();
    785. QuickSortNonR(a9, N);
    786. int end9 = clock();
    787. int begin10 = clock();
    788. //ShellSort(a10, N);
    789. int end10 = clock();
    790. int begin11 = clock();
    791. //BubbleSort(a11, N);
    792. int end11 = clock();
    793. int begin12 = clock();
    794. //MergeSort(a12, N);
    795. int end12 = clock();
    796. int begin13= clock();
    797. //MergeSortNonR(a13, N);
    798. int end13 = clock();
    799. int begin14 = clock();
    800. //CountSort(a14, N);
    801. int end14 = clock();
    802. printf("给定%d个随机数进行排序,测试对比各大排序性能(单位:ms):\n", N);
    803. printf("建小堆-向上调整-降序:\t%d\n", end1 - begin1);
    804. printf("建大堆-向上调整-升序:\t%d\n", end2 - begin2);
    805. printf("建小堆-向下调整-降序:\t%d\n", end3 - begin3);
    806. printf("建大堆-向下调整-升序:\t%d\n", end4 - begin4);
    807. printf("快速排序-挖坑法: \t%d\n", end5 - begin5);
    808. printf("快速排序-挖坑法优化:\t%d\n", end6 - begin6);
    809. printf("快速排序-左右指针法:\t%d\n", end7 - begin7);
    810. printf("快速排序-前后指针法:\t%d\n", end8 - begin8);
    811. printf("快速排序-非递归: \t%d\n", end9 - begin9);
    812. printf("希尔排序: \t%d\n", end10 - begin10);
    813. printf("冒泡排序: \t%d\n", end11 - begin11);
    814. printf("归并排序: \t%d\n", end12 - begin12);
    815. printf("归并排序-非递归: \t%d\n", end13 - begin13);
    816. printf("计数排序: \t%d\n", end14 - begin14);
    817. free(a1);
    818. free(a2);
    819. free(a3);
    820. free(a4);
    821. free(a5);
    822. free(a6);
    823. free(a7);
    824. free(a8);
    825. free(a9);
    826. free(a10);
    827. free(a11);
    828. free(a12);
    829. free(a13);
    830. free(a14);
    831. }
    832. int main()
    833. {
    834. TestOP();
    835. return 0;
    836. }

    后记:
    ●由于作者水平有限,文章难免存在谬误之处,敬请读者斧正,俚语成篇,恳望指教!

                                                                               ——By 作者:新晓·故知

  • 相关阅读:
    SQL 和 NoSQL 有什么区别?
    混合IT基础设施的安全挑战与缓解策略
    电脑重装系统后usbcleaner怎么格式化u盘
    Linux 装机必备
    隐马尔科夫模型(HMM)学习笔记
    【WSN通信】基于最佳簇半径的无线传感器网络分簇路由算法附matlab代码
    “咕”了 73 天,何同学终于回归:最喜欢 3D 打印机,但不要买
    NumPy中einsum使用笔记
    后端老项目迁移方法
    利用datafaker批量生成测试数据
  • 原文地址:https://blog.csdn.net/m0_57859086/article/details/126631517