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. 代码解释

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

三选择排序的优化方案 

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

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. 代码解释

void SelectSort(int* a, int n) 
{
    int left = 0;      // left指针,指向当前未排序部分的开始
    int right = n - 1; // right指针,指向当前未排序部分的结束
    while (left < right) // 当左指针小于右指针时,继续排序
    { 
        int minIndex = left;  // 初始化最小值索引为当前左边界
        int maxIndex = left;  // 初始化最大值索引为当前左边界
        int i = 0;
        // 遍历当前未排序的部分,从left到right
        for (i = left; i <= right; i++) 
        {
            if (a[i] < a[minIndex]) // 如果当前元素小于已知的最小值
                minIndex = i;       // 更新最小值索引
            if (a[i] > a[maxIndex]) // 如果当前元素大于已知的最大值
                maxIndex = i;       // 更新最大值索引
        }
        // 交换最小值到当前未排序部分的开始位置
        Swap(&a[minIndex], &a[left]);
        // 如果最大值在最小值的初始位置,更新最大值索引
        if (left == maxIndex) 
        {
            maxIndex = minIndex; // 因为最小值已经被交换到left位置
        }
        // 交换最大值到当前未排序部分的结束位置
        Swap(&a[maxIndex], &a[right]);
        // 缩小未排序的范围
        left++;   // 移动左边界向右
        right--;  // 移动右边界向左
    }
}

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

时间复杂度

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

最好情况:O(n²):

  • 即使数组已经是排序好的,选择排序仍然会执行 𝑛−1n−1 轮比较来确认每个元素已经处于其正确的位置。

最坏情况:O(n²):

  • 当数组是反序时,每一轮选择中找最小元素的过程也是需要完整的比较。

平均情况:O(n²):

  • 对于随机顺序的输入数组,选择排序的平均性能和最好、最坏情况相同,因为它始终执行完全的比较和交换过程。

选择排序的这种性能表现源于它的选择机制:每次都要遍历剩余未排序的部分来找到最小元素,这个过程不受输入数据状态的影响。

空间复杂度

选择排序是一个原地排序算法

空间复杂度:O(1)

  • 选择排序不需要额外的存储空间,因为它通过交换操作在原数组上进行排序。它只需要一个临时变量来存储每次找到的最小(或最大)元素的索引。

总结

选择排序因其简单和原地排序的特性,在小规模数据或内存使用受限的情况下还是有一定用途的。但由于其较差的时间效率,它通常不适用于处理大量数据。在需要处理大数据集时,更高效的排序算法如快速排序、归并排序或堆排序更为适宜。

评论 9
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值