【数据结构1.0】选择排序

鼠鼠前面的博客介绍过选择排序是常见的排序算法,选择排序有但不限于直接选择排序和堆排序!那么鼠鼠今天浅谈一下选择排序!

鼠鼠本博客用排升序来介绍选择排序!

目录

1.直接选择排序

1.1.直接选择排序

 1.2.直接选择排序特性

2.堆排序

2.1.堆排序

2.2.堆排序特性

3.效率比较


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

1.直接选择排序

1.1.直接选择排序

1.在元素集合array[i]--array[n-1]中选择关键码最大(小)的数据元素。

2.若它不是这组元素中的最后一个(第一个)元素,则将它与这组元素中的最后一个(第一个)元素交换。

3.在剩余的array[i]到array[n-2](array[i+1]到array[n-1])集合中,重复上述步骤,直到集合剩余1个元素。

其实说简单点,拿排升序来说:“单趟” 就是遍历需排序数组找出最小的数据与第一个数据交换。循环”多趟“在剩余的数据集合中找最小的数据与剩余数据集合的第一个数据交换,直到剩余数据集合数为1停止。

思想很简单,就算鼠鼠解释的不好,相信读者老爷也能明白的,看代码:

1.”单趟“代码(不是直接选择排序完整代码)

int i = begin;
		int mini = i;
		while (i <= end)
		{
			if (a[mini] > a[i])
			{
				mini = i;
			}
			i++;
		}
		Swap(&a[mini], &a[begin]);

2.循环控制好begin就能很好控制好数据集合范围,直接选择排序完整代码如下:

void SelectSort(int* a, int begin, int end)
{
	while (begin < end)
	{
		int i = begin;
		int mini = i;
		while (i <= end)
		{
			if (a[mini] > a[i])
			{
				mini = i;
			}
			i++;
		}
		Swap(&a[mini], &a[begin]);
		begin++;
	}
}

我们拉出来试试能不能排好:

#include<stdio.h>

void Swap(int* a, int* b)
{
	int tmp = *a;
	*a = *b;
	*b = tmp;
}

void SelectSort(int* a, int begin, int end)
{
	while (begin < end)
	{
		int i = begin;
		int mini = i;
		while (i <= end)
		{
			if (a[mini] > a[i])
			{
				mini = i;
			}
			i++;
		}
		Swap(&a[mini], &a[begin]);
		begin++;
	}
}

void PrintArrar(int* a, int n)
{
	for (int i = 0; i < n; i++)
	{
		printf("%d ", a[i]);
	}
	printf("\n");
}

int main()
{
	int a[] = { 7,5,6,1,3,4,2,2 };
	PrintArrar(a, sizeof(a) / sizeof(a[0]));
	SelectSort(a, 0, sizeof(a) / sizeof(a[0]) - 1);
	PrintArrar(a, sizeof(a) / sizeof(a[0]));
	return 0;
}

 没啥问题!

 1.2.直接选择排序特性

 1. 直接选择排序思考非常好理解,但是效率不是很好。实际中很少使用。

2. 时间复杂度很明显是O(N^2)。

3. 空间复杂度很明显是O(1)。

4.直接选择排序是不稳定的,因为每次“单趟”中的最后一步交换可能就将相同数据的相对位置打乱。例如9,9,9,5,5;排升序。

2.堆排序

2.1.堆排序

堆排序鼠鼠之前浅浅介绍过了,这篇博客介绍过,这里就不介绍了。唯一要注意:排升序要建大堆,排降序建小堆。

我们用堆排序排个升序看看:

#include<stdio.h>

void Swap(int* a, int* b)
{
	int tmp = *a;
	*a = *b;
	*b = tmp;
}

//向下调整(大堆)
void AdjustDown(int* a, int parentcoordinate, int HeapSize)
{
	int childcoordinate = parentcoordinate * 2 + 1;
	while (childcoordinate < HeapSize)
	{
		if (a[childcoordinate] < a[childcoordinate + 1] && childcoordinate + 1 < HeapSize)
		{
			childcoordinate++;
		}
		if (a[parentcoordinate] < a[childcoordinate])
		{
			Swap(&a[parentcoordinate], &a[childcoordinate]);
			parentcoordinate = childcoordinate;
			childcoordinate = childcoordinate * 2 + 1;
		}
		else
		{
			break;
		}
	}
}

//堆排序排升序
void HeapSort(int* a, int HeapSize)
{
	int i = 0;
	//排升序,建大堆(向下调整建堆法)
	for (i = (HeapSize - 1 - 1) / 2; i >= 0; i--)
	{
		AdjustDown(a, i, HeapSize);
	}
	int end = HeapSize - 1;
	while (end > 0)
	{
		Swap(&a[0], &a[end]);
		AdjustDown(a, 0, end);
		end--;
	}
}

int main()
{
	int a[] = { 90,80,60,20,40,70,60,30,30,110 };
	int Size = sizeof(a) / sizeof(a[0]);
	printf("堆排序前:");
	for (int i = 0; i < Size; i++)
	{
		printf("%d ", a[i]);
	}
	printf("\n");

	HeapSort(a, Size);
	printf("堆排序后:");
	for (int i = 0; i < Size; i++)
	{
		printf("%d ", a[i]);
	}
	return 0;
}

 确实排好了!

2.2.堆排序特性

1. 堆排序使用堆来选数,效率就高了很多。

2. 时间复杂度:O(N*logN)。

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

4.堆排序是不稳定的。因为建好堆后开始循环选数的过程中,如果有相同的数据,相同数据的相对顺序会被打乱。比如2,2,2,1,0;排升序。

3.效率比较

鼠鼠用这两排序来排10w个相同的随机数,大致能看出效率差距:

#include<stdio.h>
#include<time.h>
#include<stdlib.h>

void Swap(int* a, int* b)
{
	int tmp = *a;
	*a = *b;
	*b = tmp;
}

//直接选择排序
void SelectSort(int* a, int begin, int end)
{
	while (begin < end)
	{
		int i = begin;
		int mini = i;
		while (i <= end)
		{
			if (a[mini] > a[i])
			{
				mini = i;
			}
			i++;
		}
		Swap(&a[mini], &a[begin]);
		begin++;
	}
}

//向下调整(大堆)
void AdjustDown(int* a, int parentcoordinate, int HeapSize)
{
	int childcoordinate = parentcoordinate * 2 + 1;
	while (childcoordinate < HeapSize)
	{
		if (a[childcoordinate] < a[childcoordinate + 1] && childcoordinate + 1 < HeapSize)
		{
			childcoordinate++;
		}
		if (a[parentcoordinate] < a[childcoordinate])
		{
			Swap(&a[parentcoordinate], &a[childcoordinate]);
			parentcoordinate = childcoordinate;
			childcoordinate = childcoordinate * 2 + 1;
		}
		else
		{
			break;
		}
	}
}
//堆排序排升序
void HeapSort(int* a, int HeapSize)
{
	int i = 0;
	//排升序,建大堆(向下调整建堆法)
	for (i = (HeapSize - 1 - 1) / 2; i >= 0; i--)
	{
		AdjustDown(a, i, HeapSize);
	}
	int end = HeapSize - 1;
	while (end > 0)
	{
		Swap(&a[0], &a[end]);
		AdjustDown(a, 0, end);
		end--;
	}
}

int main()
{
	int n = 100000;
	int* a = (int*)malloc(sizeof(int) * n);
	int* b = (int*)malloc(sizeof(int) * n);
	srand((unsigned int)time(0));
	for (int i = 0; i < n; i++)
	{
		a[i] = rand() + i;
		b[i] = a[i];
	}
	int begin1 = clock();
	SelectSort(a, 0, n - 1);
	int end1 = clock();
	printf("SeleckSort:%d\n", end1 - begin1);
	int begin2 = clock();
	HeapSort(a, n);
	int end2 = clock();
	printf("HeapSort:%d\n", end2 - begin2);
	return 0;
}

我们可以看到在Debug版本下结果:

 感谢阅读!

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

X_chengonly

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值