当前位置:   article > 正文

选择排序(直接选择排序与堆排序的比较)

选择排序(直接选择排序与堆排序的比较)

选择排序

选择排序时间复杂度

1. 直接选择排序思考⾮常好理解,但是效率不是很好。实际中很少使用,思路是先进行遍历找到元最小的元素,然后与第一个进行交换     

2. 时间复杂度:O(n^{2}

3. 空间复杂度:O(1)

选择排序源码

  1. void SelectSort(int* arr, int n)
  2. {
  3. for (int i = 0; i < n; i++)
  4. {
  5. int min = i;
  6. for (int j = i + 1; j < n; j++)
  7. {
  8. if (arr[min] > arr[j])
  9. {
  10. min = j;
  11. }
  12. }
  13. swap(&arr[i], &arr[min]);
  14. }
  15. }

上述代码的时间复杂度为:O(n^{2}),但是不是最完美的所以我们进行优化一下,但是优化后时间复杂度还是O(n^{2})。 这时就可以看出选择排序和冒泡排序的差别,冒泡排序优化后时间复杂度会进行改变但是选择排序就并不会改变。

优化后的选择排序

堆排序

堆排序的分析

堆排序分为大根堆和小根堆两种方法,这两种方法主要区别的是升序还是降序。升序大根堆因为我们知道大根堆中最大位于堆顶的,经过最后一个与堆顶进行替换后最大元素会被换到后面,堆排序是基于数组的所以数值是逐渐增大的。同理分析(降序是小根堆)。

堆排序的时间复杂度

堆排序的时间复杂度要计算建堆的时间与置换的时间,以向下建堆排序为准:O(n + n ∗ log n) ,即O(n log n)。

向上建堆时间复杂度为:O(n ∗ log2 n)

向上调整的证明分析

向下建堆的时间复杂度为:O(n)

向下调整证明的分析

源代码

HeadSort.c

  1. void swap(int* n, int* m)
  2. {
  3. int tmp = *n;
  4. *n = *m;
  5. *m = tmp;
  6. }
  7. //向下调整
  8. void HeapDown(int* arr, int parent, int n)
  9. {
  10. //向下排序要注意是父节点与子节点两个中最小的进行比较
  11. //要限制child+1<n
  12. int child = 2 * parent + 1;
  13. //小堆排序
  14. //用child小于
  15. while (child < n)
  16. {
  17. if (child + 1 < n && arr[child] > arr[child + 1])
  18. {
  19. //找到最小的节点,从而和父节点进行交换
  20. child++;
  21. }
  22. if (arr[child] < arr[parent])
  23. {
  24. swap(&arr[child], &arr[parent]);
  25. parent = child;
  26. child = 2 * parent + 1;
  27. }
  28. else
  29. {
  30. break;
  31. }
  32. }
  33. }

 test.c

  1. #include"HeapSort.h"
  2. void HeapSort(int* arr, int n)
  3. {
  4. //建堆
  5. // a数组直接建堆 O(N)
  6. for (int i = (n-1-1)/2; i >= 0; --i)
  7. {
  8. HeapDown(arr, i, n);
  9. }
  10. // O(N*logN)
  11. //升序---大堆
  12. //降序----小堆
  13. //循环将堆顶数据跟最后位置(会变化,每次减少一个数据)的数据进行交换
  14. int end = n - 1;
  15. //取堆顶返回的是堆的数据结构,而不是数组,其次也是用堆顶进行覆盖原来数据
  16. //所以使用了堆顶与堆尾的向下调整,并且每次让end--
  17. while (end > 0)
  18. {
  19. swap(&arr[0], &arr[end]);
  20. HeapDown(arr, 0, end);
  21. end--;
  22. }
  23. //打印
  24. for (int i = 0; i < n; i++)
  25. {
  26. {
  27. printf("%d ", arr[i]);
  28. }
  29. }
  30. }
  31. int main()
  32. {
  33. int arr[] = { 1,2,3,4,5,6 };
  34. HeapSort(arr, 6);
  35. }

快速排序

快速排序是Hoare于1962年提出的⼀种⼆叉树结构的交换排序⽅法,其基本思想为:任取待排序元素 序列中的某元素作为基准值,按照该排序码将待排序集合分割成两⼦序列,左⼦序列中所有元素均⼩ 于基准值,右⼦序列中所有元素均⼤于基准值,然后最左右⼦序列重复该过程,直到所有元素都排列 在相应位置上为⽌

快排的示意图
快排的解题思路

快速排序中部分细节分析

快速排序的细节较多主要在一下两个部分。

1.left <= right?这种情况是为了预防相遇值的精度大于精准值,这样若进行替换就会造成错误的交换方式。

2.arr[right] > arr[base]?

 这种情况主要是为了防止,出现相同数据造成时间复杂多过高,最好就是在递归是把一个大的队列分为大小相同的两个,然后在进行递归。

递归时的判断条件

快排特性

时间复杂度为 0(n log n)、自适应排序:在平均情况下,哨兵划分的递归层数为 log n ,每层中的总循 环数为n ,总体使用0(n log n)时间。在最差情况下,每轮哨兵划分操作都将长度为n 的数组划分为 长度为 0 和 n−1 的两个子数组,此时递归层数达到 n ,每层中的循环数为 n ,总体使用 0(n^{2}) 时间。

空间复杂度为 0(n )、原地排序:在输入数组完全倒序的情况下,达到最差递归深度 n,使用 0(n )栈 帧空间。排序操作是在原数组上进行的,未借助额外数组。

非稳定排序:在哨兵划分的最后一步,基准数可能会被交换至相等元素的右侧。

快排的优点

从名称上就能看出,快速排序在效率方面应该具有一定的优势。尽管快速排序的平均时间复杂度与“归并排 序”和“堆排序”相同,但通常快速排序的效率更高,主要有以下原因。

出现最差情况的概率很低:虽然快速排序的最差时间复杂度为 0(n^{2}) ,没有归并排序稳定,但在绝大 多数情况下,快速排序能在 0(n log n) 的时间复杂度下运行。

缓存使用效率高:在执行哨兵划分操作时,系统可将整个子数组加载到缓存,因此访问元素的效率较 高。而像“堆排序”这类算法需要跳跃式访问元素,从而缺乏这一特性。

复杂度的常数系数小:在上述三种算法中,快速排序的比较、赋值、交换等操作的总数量最少。这与 “插入排序”比“冒泡排序”更快的原因类似。

快排源码

  1. //快速排序
  2. void swap(int* n, int* m)
  3. {
  4. int temp = *n;
  5. *n = *m;
  6. *m = temp;
  7. }
  8. int _QuickSort(int* arr, int left, int right)
  9. {
  10. int base = left;
  11. left++;
  12. while (left<=right)
  13. {
  14. while (left <= right && arr[right] > arr[base])
  15. {
  16. right--;
  17. }
  18. while (left <= right && arr[left] < arr[base])
  19. {
  20. left++;
  21. }
  22. if (left <= right)
  23. {
  24. //隐藏细节
  25. swap(&arr[left++], &arr[right--]);
  26. }
  27. }
  28. //此时已经不满足,left<=right这时候把right和关键值进行置换
  29. swap(&arr[base], &arr[right]);
  30. return right;
  31. }
  32. void QuickSort(int* arr, int left, int right)
  33. {
  34. if (left >= right)
  35. {
  36. return;
  37. }
  38. //[left,right]--->找基准值mid
  39. int keyi = _QuickSort(arr, left, right);
  40. //左子序列:[left,keyi-1]
  41. QuickSort(arr, left, keyi - 1);
  42. //右子序列:[keyi+1,right]
  43. QuickSort(arr, keyi + 1, right);
  44. }

总结

以上就是本次总结,其中快排的坑还是较多的,需要认真分析一下,最后创作不易,希望各位大佬能一键三连(点赞,收藏,关注)。

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

闽ICP备14008679号