当前位置:   article > 正文

5分钟帮你完全搞定!!![动画+注释详解] 数据结构 - 选择排序

5分钟帮你完全搞定!!![动画+注释详解] 数据结构 - 选择排序

 一、选择排序算法的实现

1. 基本思想

每一次从待排序的数据元素中选出最小(或最大)的一个元素,存放在序列的起始位置,直到全部待排序的 数据元素排完 。

二、排序过程

1. 动图分析

 2. 实例分析

定义一个数组 int a[4] = [3,2,8,4],要求利用选择排序的方法将数组从小到大排序。

第一趟排序:从4个元素里面找到最小的,与第一个元素进行交换,将最小元素存放在起始位置

排序后为:2 ,3,8,4

第二趟排序:从剩下的3个元素中找最小的,与待排序的第一个元素(3)进行交换,将最小元素存放在第二个位置。可以发现最小的元素就是3

排序后为:2 ,3,8,4

第三趟排序:从剩下的2个元素里面找最小的,与待排序的第一个元素(8)进行交换,将最小元素存放在第三个位置

排序后为:2 ,3,4,8

第四趟排序: 其实这一趟不用排序了,因为前面已经筛选好了,最后一个数肯定是最大的了

排序后为:2 ,3,4,8

3. 代码解释

  1. void SelectSort(int* a, int n)
  2. {
  3. int i = 0;
  4. for (i = 0; i < n-1; i++) //i代表参与该趟选择排序的第一个元素的下标
  5. {
  6. int start = i; // 初始化start为当前轮次的起始位置i
  7. int min = start; // 最小值索引初始化为start
  8. while (start < n)
  9. {
  10. // 从当前位置i开始,向右遍历至数组末尾
  11. if (a[start] < a[min])
  12. {
  13. min = start; // 如果发现更小的值,则更新最小值索引
  14. }
  15. start++; // 移动到下一个元素
  16. }
  17. Swap(&a[i], &a[min]); // 与当前位置i处的元素交换,确保最小元素位于其正确的位置
  18. }
  19. }

三选择排序的优化方案 

采用双向选择排序:传统的选择排序每次只确定了一个位置(最小值),而双向选择排序则同时确定两个位置——最小值和最大值。每一趟排序中,同时查找当前未排序部分的最小值和最大值,将最小值放在未排序部分的开始,最大值放在末尾。这样可以减少排序所需的总趟数,从而在一定程度上提高效率。

1. 实例分析

假设我们有一个未排序的数组:arr [1029,14,37,13],运用双向选择进行排序

第一趟排序:

  • 初始化left = 0,right = 4;
  • 寻找从 left 到 right 的最小值和最大值:
  • 最小值为 arr[1] = 10,位置在索引 1
  • 最大值为 arr[3] = 37,位置在索引 3
  • 交换最小值 10 和左边界值 29,得到 [10,29,14,37,13]
  • 交换最大值 37 和右边界值 13,得到 [10,29,14,13,37]
  • 缩小范围:left = 1,right = 3

第二趟排序

  • 继续排序,left = 1,right = 3
  • 寻找从 left 到 right 的最小值和最大值:
    • 最小值为 13,位置在索引 3
    • 最大值为 29,位置在索引 1
  • 交换最小值 13 和左边界值 29,得到 [10,13,14,29,37]
  • 由于最大值已经是 29 且在正确的位置(经由最小值交换到位),[10,13,14,29,37]
  • 缩小范围:left = 2,right = 2
  • 此时left = right,说明14的位置也是正确的,即[10,13,14,29,37]

结束条件

  • 当 left >= right时,排序完成

2. 代码解释

  1. void SelectSort(int* a, int n)
  2. {
  3. int left = 0; // left指针,指向当前未排序部分的开始
  4. int right = n - 1; // right指针,指向当前未排序部分的结束
  5. while (left < right) // 当左指针小于右指针时,继续排序
  6. {
  7. int minIndex = left; // 初始化最小值索引为当前左边界
  8. int maxIndex = left; // 初始化最大值索引为当前左边界
  9. int i = 0;
  10. // 遍历当前未排序的部分,从left到right
  11. for (i = left; i <= right; i++)
  12. {
  13. if (a[i] < a[minIndex]) // 如果当前元素小于已知的最小值
  14. minIndex = i; // 更新最小值索引
  15. if (a[i] > a[maxIndex]) // 如果当前元素大于已知的最大值
  16. maxIndex = i; // 更新最大值索引
  17. }
  18. // 交换最小值到当前未排序部分的开始位置
  19. Swap(&a[minIndex], &a[left]);
  20. // 如果最大值在最小值的初始位置,更新最大值索引
  21. if (left == maxIndex)
  22. {
  23. maxIndex = minIndex; // 因为最小值已经被交换到left位置
  24. }
  25. // 交换最大值到当前未排序部分的结束位置
  26. Swap(&a[maxIndex], &a[right]);
  27. // 缩小未排序的范围
  28. left++; // 移动左边界向右
  29. right--; // 移动右边界向左
  30. }
  31. }

四、选择排序的时间复杂度和空间复杂度 

时间复杂度

选择排序的时间复杂度在所有情况下都是一样的,因为它总是执行完整的比较过程,无论输入数据的初始状态如何。

最好情况:O(n²):

  • 即使数组已经是排序好的,选择排序仍然会执行
    声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/小丑西瓜9/article/detail/621025
推荐阅读
相关标签