排序算法(一) —— 选择排序

原创文章,转载请注明出处。

本文是排序算法系列文章的第一篇,主要讲述 “选择排序” 算法。

一、原理:

       每一趟排序(例如第 i 趟,其中 i = 0, 1, …, n - 2),在后面 n - i 个待排记录中选出关键字最小的元素(下标为 index),与第 i 个记录交换,直至全部待排序的数据元素排完。由于排到 n - 1 趟时,前 n - 1 个元素已然有序,则剩余的一个元素自然也有序,因此一共需要排 n - 1 趟(外层循环 n - 1 次)。设整个待排记录序列有 n 个记录,则第 i 趟选择具有最小数据元素时所需的比较次数总是 n - i - 1 次,因为第 i 趟排序时,前 i 个数据已经排好序,不需要再进行比较,只需与后 n - i - 1 个元素进行比较(内层循环从 i + 1 到 n - 1)。

二、代码及注释:

void selectSort(int n, int *arr)
{
	// 选择排序每一趟,例如第i‘i = 0、1、2、...、n - 2’趟,在后面的 n - i 个待排数据中选择最小的一个,与第 i 个数据交换
	int i, j;
	for (i = 0; i < n - 1; i++)				// 第 i 趟,只需排 n - 1 趟
	{
		int temp;					// 用于交换的临时变量
		int index = i;					// 记录待排数据中最小值的下标,初始化默认为下标 i
		for (j = i + 1; j < n; j++)			// 从下标为 i + 1 的数据开始,一共循环 n - i 次
		{
			if (arr[j] < arr[index])		// 比较得出较小值
			{
				index = j;			// 记录较小值的下标,循环结束后所得记录值即为待排数据中最小值下标
			}
		}
		// 将最小值与下标为 i 的数据进行交换
		temp = arr[i];
		arr[i] = arr[index];
		arr[index] = temp;
	}
}

三、算法性能分析:

       当输入规模为 n = 10000、20000、30000、40000、50000 时,执行程序,可以得到在不同输入规模下,20 组随机样本数据执行选择排序的单组执行时间及平均执行时间为:


       理论上来说,选择排序的时间复杂度为 O(n^2)。同时,由上图可以看出,当 n = 10000 时,20 组样本排序的平均执行为 33.5927 ms。以输入规模为 10000 的数据运行时间为基准点,则理论上的平均执行时间为:t = k * n^2 ,(k 为常数),带入 t = 33.5927ms、n = 10000,可得:k = t / n2 = 33.5927 / 100002

       所以,在相应输入规模下,选择排序的理论执行时间为:


       根据上表,可以作出选择排序理论效率曲线和实测效率曲线如下:


       如上图表,是选择排序的理论效率曲线和实测效率曲线,其中位于上方的数据标签是实测效率曲线的标注,位于下方的数据标签是理论效率曲线的标注。由图表我们可以看出,两条折线仅存在细小差异。

       首先,不管是理论效率曲线还是实测效率曲线,都满足抛物线 y = k * n^2 在某个定义域的一段曲线(其中 k 为系数)。这与我们的理论认知也是相一致的。

       我们知道,在选择排序过程中,所需进行记录移动的操作次数较少,其最小值为 0,即序列本来就有序,1 次都不需移动;移动操作次数最大值为 3 (n - 1)。然而,无论记录的初始排列如何,所需进行的关键字间的比较次数相同,均为 n (n - 1) / 2。因此,总的时间复杂度是 O(n^2),这也是理论效率曲线所反映出来的。而实测效率曲线与理论效率曲线基本相符,随着输入规模的增大,实际消耗时间略高于理论消耗时间。原因可能有两个,其一是随着规模的增大,移动操作(赋值操作)对时间消耗的影响也随之扩大;其二是与程序运行时电脑的 CPU 利用率有关,若程序运行时有其他程序占用 CPU 资源,也会影响到排序的时间。



评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值