【数据结构】常见的排序算法 -- 选择排序

🫧个人主页: 小年糕是糕手

💫个人专栏:《数据结构(初阶)》** 《C/C++刷题集》 《C语言》**

🎨你不能左右天气,但你可以改变心情;你不能改变过去,但你可以决定未来!



目录

一、直接选择排序

1.1、算法思想

1.2、代码实现

二、堆排序

2.1、算法思想

2.2、代码实现


一、直接选择排序

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

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

1.2、代码实现
cpp 复制代码
void SelectSort(int* arr, int n)
{
	int begin = 0, end = n - 1;
	while (begin < end)
	{
		int mini = begin;
		int maxi = begin;
		for (int i = begin + 1; i <= end; i++)
		{
			if (arr[i] < arr[mini])
			{
				mini = i;
			}
			if (arr[i] > arr[maxi])
			{
				maxi = i;
			}
		}

		if (maxi == begin)
		{
			maxi = mini;
		}
		Swap(&arr[begin], &arr[mini]);
		Swap(&arr[end], &arr[maxi]);

		begin++;
		end--;
	}
}

直接选择排序的特性总结:

  1. 直接选择排序思考非常好理解,但是效率不是很好,实际中很少使用(我们主要是通过这个例子去了解更多的排序算法,锻炼自己的代码能力)
  2. 时间复杂度:O(N^2)
  3. 空间复杂度:O(1)

二、堆排序

2.1、算法思想

堆排序的算法思想基于堆这种数据结构(完全二叉树),核心步骤如下:

  1. 构建初始堆:将待排序的数组视为一棵完全二叉树,调整其结构为大顶堆(或小顶堆,取决于排序需求)。大顶堆的特性是:每个父节点的值都大于或等于其左右子节点的值。

  2. 交换与调整堆:

    • 将堆顶元素(最大值,对应大顶堆)与堆的最后一个元素交换,此时最大值被放置到数组末尾(即已排序位置)。
    • 排除已排序的最后一个元素,将剩余元素重新调整为大顶堆(此时堆的规模减 1)。
  3. 重复操作:不断重复 "交换堆顶与当前堆的最后一个元素" 和 "调整剩余元素为大顶堆" 的步骤,直到堆的规模缩减为 1,此时整个数组完成排序。

通过堆的特性,每次能高效地选出剩余元素中的最大值(或最小值),最终实现整个数组的有序排列。堆排序的时间复杂度为O(n*logn),空间复杂度为O(1)。

大家要是想进一步详细了解可以参考:小年糕是糕手博客 -- 顺序结构二叉树详解

2.2、代码实现
cpp 复制代码
void Swap(int* x, int* y)
{
	int tmp = *x;
	*x = *y;
	*y = tmp;
}


//向上调整算法
void AdjustUp(int* arr, int child)
{
	int parent = (child - 1) / 2;
	while (child > 0)
	{
		//建大堆: >
		//建小堆: <
		if (arr[child] > arr[parent])
		{
			Swap(&arr[child], &arr[parent]);
			child = parent;
			parent = (child - 1) / 2;
		}
		else
		{
			//不用调整符合情况
			break;
		}
	}
}

//向下调整算法
//n是堆里面的结点个数,如果越界了就不需要调整了
void AdjustDown(int* arr, int parent, int n)
{
	int child = parent * 2 + 1;
	while (child < n)
	{
		//建大堆: <
		//建小堆: >
		if (child + 1 < n && arr[child] < arr[child + 1])
		{
			child++;
		}

		//孩子和父亲比较
		//建大堆: >
		//建小堆: <
		if (arr[child] > arr[parent])
		{
			Swap(&arr[child], &arr[parent]);
			parent = child;
			child = parent * 2 + 1;
		}
		else
		{
			break;
		}
	}
}

//堆排序
void HeapSort(int* arr, int n)
{
	//向下调整算法 -- 建堆n
	for (int i = (n - 1 - 1) / 2; i >= 0; i--)
	{
		AdjustDown(arr, i, n);
	}

	////向上调整算法 -- 建堆n*logn
	//for (int i = 0; i < n; i++)
	//{
	//	AdjustUp(arr, i);
	//}

	//n*logn
	int end = n - 1;
	while (end > 0)
	{
		Swap(&arr[0], &arr[end]);
		AdjustDown(arr, 0, end);
		end--;
	}
}

堆排序的特性总结如下:

  1. 时间复杂度:O(n*logn)。构建初始堆的时间复杂度为O(n),后续每次调整堆的时间复杂度为O(logn),共需调整n−1次,整体复杂度稳定为O(n*logn),不受数据分布影响。

  2. 空间复杂度:O(1)。堆排序是原地排序算法,仅需常数级别的额外空间用于临时变量交换。

  3. 稳定性:不稳定。在交换堆顶元素与末尾元素时,可能会改变相同元素的相对顺序。

  4. 适用场景:适用于数据量较大的场景,对空间复杂度要求严格时表现较好,但由于交换和调整操作较频繁,实际应用中对小规模数据的效率可能不如快速排序。

  5. 其他特性:基于堆结构实现,排序过程中需要频繁进行堆的调整(下沉操作),逻辑相对直接选择排序更复杂,但效率更高。

相关推荐
老黄编程7 分钟前
点云NARF关键点原理、算法描述及参数详细描述
算法·点云·narf特征点
源梦想9 分钟前
绝地幸存者H5割草网页小游戏Linux部署演示
linux·运维·服务器
CoovallyAIHub12 分钟前
NeurIPS 2025时间检验奖:10年之后再谈Faster R-CNN
深度学习·算法·计算机视觉
天下·第二14 分钟前
python处理【orc】下载压缩的.zip文件,windows和linux同时适配
linux·windows·python
凑齐六个字吧17 分钟前
单细胞LIANA受配体分析框架学习
linux·服务器·windows
CoovallyAIHub25 分钟前
1024层网络让强化学习性能飙升50倍,NeurIPS 2025最佳论文揭示深度scaling的力量
深度学习·算法·计算机视觉
nianniannnn26 分钟前
Eigen 矩阵操作笔记
c++·笔记·线性代数·矩阵
adfass26 分钟前
桌面挂件时钟/多功能时钟C++
开发语言·c++·算法
全栈视界师34 分钟前
《机器人实践开发②:Foxglove 嵌入式移植 + CMake 集成》
c++·机器人·数据可视化