排序算法-选择排序

目录

选择排序

一、直接选择排序

总结

二、堆排序

总结


选择排序

选择排序基本思想:

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

一、直接选择排序

1.在元素集合array[i]—array[n-1]中选择关键码最大(小)的数据元素
2.若它不是这组元素中的最后一个(第一个)元素,则将它与这组元素中的最后一个(第一个)元素交换
3.在剩余的array[i]--array[n-2](array[i+1]--array[n-1])集合中,重复上述步骤,直到集合剩余1个元素

排序过程图:

第一次选择排序

第二次选择排序

第三次选择排序

第四次选择排序

第五次选择排序

当start位置走到最后一个位置时则循环结束,不用继续找最小(最大)值了。

代码示例:

void SelectSort2(int* a, int n)
{
	int start = 0;
	int i = 0;
	//n为数组集合的个数,n-1为最后一个元素数组下标 当start走到最后一个元素循环结束
	for (start = 0; start < n - 1 ; start++)
	{
		int min = start;
		//在数组下标[start,n-1]的范围中寻找最小的数
		for (int j = start; j < n; j++)
		{
			//找最小值的数组下标
			if (a[j] < a[min])
			{
				min = j;
			}
		}
		//交换数据
		Swap(&a[start], &a[min]);
	}
}

直接选择排序优化版本

像图中所示,定义两个指针指向数组两边,遍历区间[left,right]的数找到最大值和最小值的数,随后最大的数与right交换,最小的数与left交换,循环结束后,再次重复此项步骤,当left==right时结束循环。

代码示例:

//选择排序  (头尾开始寻找)
void SelectSort1(int* a, int n)
{
	int left = 0;
	int right = n - 1;
	//从两边开始往中间找
	while (left < right)
	{
		int minIndex = left;
		int maxIndex = right;
		for (int i = left; i <= right; i++)
		{
			//找最小值
			if (a[i] < a[minIndex])
			{
				minIndex = i;
			}
			//找最大值
			if (a[i] > a[maxIndex])
			{
				maxIndex = i;
			}
		}
		Swap(&a[left], &a[minIndex]);
		//修正
		if (left == maxIndex)
		{
			maxIndex = minIndex;
		}
		Swap(&a[right], &a[maxIndex]);
		left++;
		right--;
	}
}

但是这个方法有个细节需要注意:

如果最大值的位置位于left直接交换会导致意想不到的后果如下图所示,所以要进行一步判断并且修正为:maxinedx=minindex

总结

直接选择排序的特性总结
1. 直接选择排序思考非常好理解,但是效率不是很好。实际中很少使用
2. 时间复杂度:O(N^2)
3. 空间复杂度:O(1)
4. 稳定性:不稳定

二、堆排序

在学习堆排序之前一定要知道什么是堆,如何构建堆,如果对此不是很清晰可以参考这篇文章来复习一下:

堆排序(Heapsort)是指利用堆积树(堆)这种数据结构所设计的一种排序算法,它是选择排序的一种。它是通过堆来进行选择数据。需要注意的是排升序要建大堆,排降序建小堆。

对于一个数组例如[20,17,4,16,5,3]排序过程如下

当排完序后对应的数组为[3,4,5,16,17,20],此处是升序所以在此之前我们建的是大堆。

代码示例

//堆排序
void HeapSort(int* a, int n)
{
	//构建大堆
	int parent = (n - 1 - 1)/2;
	for (parent; parent>=0; parent--)
	{
		AdjustDown(a, n, parent);
	}
	//交换 排序(大堆升序)
	int i = 0;
	for (i = n-1; i > 0; i--)
	{
		Swap(&a[0], &a[i]);
		AdjustDown(a, i, 0);
	}
}

向下调整建堆的代码:

//向下调整算法
void AdjustDown(int* a, int n,int parent)
{
	int child = parent * 2+1;
	while (child < n )
	{
		//判断左右孩子哪个最大,建大堆
		if (child + 1 < n && a[child + 1] > a[child])
		{
			child++;
		}
		if (a[parent] < a[child])
		{
			Swap(&a[child], &a[parent]);
			parent = child;
			child = parent * 2 + 1;
		}
		else
			break;
	}
}

总结

堆排序的特性总结
1. 堆排序使用堆来选数,效率就高了很多。
2. 时间复杂度:O(N*logN)
3. 空间复杂度:O(1)
4. 稳定性:不稳定

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值