【C语言】选择排序、堆排序详解

前言

在本篇博客中,作者将会你理解和实现选择排序堆排序

一.选择排序

1.排序思想

 选择排序的思想是在一组数中选出最大(或最小)的值,然后把它放到最后一个(或第一个)位置,接着选出次大(或次小)的值,把它放到倒数第二个(或第二个)位置,以此类推。

如下图所示:

 

2.单趟排序

 绝大部分排序都可以分为单趟排序多趟排序,在我们写排序时,可以先写单趟排序再写多趟排序,这可以使得写起来更加简单易懂

单趟排序如上图所示。

①单趟排序伪代码实现
void Swap(int* num1, int* num2)//用于交换数组中的两个数
{
	int tmp = *num1;
	*num1 = *num2;
	*num2 = tmp;
}	


    int max = 0;//需要找的最大值
	int begin = 0;//待排数组的起始位置
	int end = sz - 1;//待排数组的终止位置

	for (int i = begin; i < end; i++)//找最大值
	{
		if (arr[i] > arr[max])
		{
			max = i;
		}
	}

	Swap(&arr[end], &arr[max]);//将最大值换到末尾

3.多趟排序

在完成单趟排序后,只是将一个最大值排到了最后,接下来需要将剩余的数也进行排序,所以需要在单趟排序的外层嵌套一层循环控制end的值。 

①多趟排序代码实现
void Swap(int* num1, int* num2)//用于交换数组中的两个数
{
	int tmp = *num1;
	*num1 = *num2;
	*num2 = tmp;
}

void SelectSort(int* arr, int sz)
{
	for (int i = sz - 1; i > 0; i--)//外层循环控制end的位置
	{
		int max = 0;
		int begin = 0;
		int end = i;

		for (int i = begin; i < end; i++)//内层循环用于单趟排序
		{
			if (arr[i] > arr[max])
			{
				max = i;
			}
		}

		Swap(&arr[end], &arr[max]);
	}
}

4.时间复杂度和空间复杂度

时间复杂度:看的是最坏的情况,选择排序不管是已经有序还是完全逆序,依然需要比较,所以它的时间复杂度为1+2+3+4+……+(n-1)为O(n²)

空间复杂度:在进行排序时,只用到一些临时变量的空间,没有额外开辟空间,所以空间复杂度为:O(1)

二.堆排序

在博主的下面这篇博客中,有详细的讲到堆,其中也讲了堆排序,如果有需要看堆排序详解的可以看看下面这篇博客。

堆排序的要点是需要建堆,所以看的时候,要先看建堆部分

【C语言】堆的实现(建堆、堆的基本操作、堆排序、TOK问题)详解-CSDN博客

三.稳定性分析

什么是稳定性?

稳定性是,如果一组数里面有两个相同的数,则排序完成后,如果不会改变他们的相对顺序,则这个排序算法是稳定的,否则是不稳定的。

结论

选择排序是不稳定

堆排序也是不稳定的 

四.所有源代码

#include<stdio.h>

void Print(int* arr, int sz)//打印数组
{
	for (int i = 0; i < sz; i++)
	{
		printf("%d ", arr[i]);
	}
	printf("\n");
}

void Swap(int* num1, int* num2)//交换数组中的两个数
{
	int tmp = *num1;
	*num1 = *num2;
	*num2 = tmp;
}

void SelectSort(int* arr, int sz)//选择排序
{
	for (int i = sz - 1; i > 0; i--)
	{
		int max = 0;
		int begin = 0;
		int end = i;

		for (int i = begin; i < end; i++)
		{
			if (arr[i] > arr[max])
			{
				max = i;
			}
		}

		Swap(&arr[end], &arr[max]);
	}
}

void AdjustDown(int* arr, int sz, int root)//向下调整算法,用于堆排序
{
	int parent = root;
	int child = 2 * parent + 1;

	while (child < sz)
	{
		if ((child + 1) < sz && arr[child + 1] > arr[child])
		{
			child++;
		}

		if (arr[child] > arr[parent])
		{
			Swap(&arr[child], &arr[parent]);
			parent = child;
			child = 2 * parent + 1;
		}
		else
		{
			break;
		}
	}
}

void HeapSort(int* arr, int sz)//堆排序
{
	for (int i = (sz - 1 - 1) / 2; i >= 0; i--)
	{
		AdjustDown(arr, sz, i);
	}

	for (int i = sz - 1; i > 0; i--)
	{
		Swap(&arr[0], &arr[i]);
		AdjustDown(arr, i, 0);
	}
}

int main()
{
	int arr1[] = { 15,48,96,20,13,5,74,18,2 };
	int arr2[] = { 51,14,2,3,5,4,9,78 };

	SelectSort(arr1, sizeof(arr1) / sizeof(int));
	HeapSort(arr2, sizeof(arr2) / sizeof(int));

	Print(arr1, sizeof(arr1) / sizeof(int));
	Print(arr2, sizeof(arr2) / sizeof(int));

	return 0;
}

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值