【数据结构】排序(sort) -- 选择排序

发布于:2025-08-06 ⋅ 阅读:(13) ⋅ 点赞:(0)

目录

一、插入排序

二、简单选择排序(simple selection sort)

1. 基本思想

2. 思路介绍

3. 代码实现

4. 特性总结

三、堆排序(heap sort)

1. 基本思想

2. 思路介绍

3. 代码实现

4. 特性总结

四、总结


一、插入排序

常见的排序算法有:

而本篇文章要介绍的是选择排序。

插入排序可以分为 选择排序(simple selection sort) 和 堆排序(heap sort) 


二、简单选择排序(simple selection sort)

1. 基本思想

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

如果选的是最大的一个元素,则为排升序

如果选的是最小的一个元素,则为排降序

2. 思路介绍

思路:

  1. 将整个数据划分为有序区和无序区,初始时有序区为空,无序区含有待排序的所有数据。
  2. 在无序区中选取最小的数据,将其与无序区中的第一个数据交换,使得有序区增加一个数据,同时无序区减少一个数据。
  3. 不断重复步骤2,直到无序区只剩一个数据。

对于一组数据:3,44,38,5,47,15,36,26,27,2,46,4,19,50,48  它的排序个过程如下:

排序动图如下:

3. 代码实现

C语言代码实现:

void Swap(int* p1, int* p2)
{
	int tmp = *p1;
	*p1 = *p2;
	*p2 = tmp;
}
// 选择排序
void SelectSort(int* a, int n)
{
	int left = 0;// 无序区第一个的下标
	
	while(left < n - 1)
	{
		int mini = left + 1;// 无序区最小值的下标

		// 遍历除第一个无序区元素的其他元素
		for (int i = left + 1; i < n; i++)
		{
			// 寻找最小值下标
			if (a[i] < a[mini])
			{
				mini = i;
			}
		}
		if (mini != left)
		{
			Swap(&a[left], &a[mini]);
		}
		left++;
	}
}

可以发现上面的选择排序是一个一个的寻找,再排序。这样效率会很低。

所以,可以改进一下:

从左右两边同时开始选择,排升序的话,可以在左边选择最小值进行交换,在右边选择最大值进行交换。则C语言代码实现;

void Swap(int* p1, int* p2)
{
	int tmp = *p1;
	*p1 = *p2;
	*p2 = tmp;
}
void SelectSort(int* a, int n)
{
	int left = 0;//左边无序区第一个
	int right = n - 1;//右边无序区第一个

	while (left < right)
	{
		int mini = left;
		int maxi = right;

		for (int i = left; i <= right; i++)
		{
			//选最小值下标
			if (a[mini] > a[i])
			{
				mini = i;
			}
			//选择最大值下标
			if (a[maxi] < a[i])
			{
				maxi = i;
			}
		}
		Swap(&a[left], &a[mini]);
		// 如果left和maxi重叠,交换后修正一下
		if (left == maxi)
		{
			maxi = mini;
		}
		Swap(&a[right], &a[maxi]);
		++left;
		--right;
	}
}

4. 特性总结

简单选择排序的特性总结:

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

三、堆排序(heap sort)

1. 基本思想

        堆排序 是指利用(一种完全二叉树)这种数据结构所设计的一种排序算法,它是选择排序的一种。它是通过堆来进行选择数据 。

需要注意的是:

        排升序 要 建大堆排降序建小堆

        然后利用堆的删除思想,进行排序。

2. 思路介绍

思路:

  1. 建堆:从倒数的第一个非叶子节点的子树开始向下调整调整,一直调整到根节点的树,就可以调整成想要的堆
  2. 堆的删除:将堆顶的元素与最后一个元素进行交换,在对此时的堆顶元素进行向下调整。
  3. 重复次步骤2操作,直到堆中只有一个元素。

以建大堆排升序例:

3. 代码实现

C语言代码实现:

// 堆排序
//向下调整-建大堆
void AdjustDwon(int* a, int n, int parent)
{
	int child = 2 * parent + 1;
	while (child < n)
	{
		//选择两个孩子中较大的一个
		if (child + 1 < n && a[child] < a[child + 1])
		{
			child++;
		}
		if (a[child] > a[parent])
		{
			Swap(&a[child], &a[parent]);
			parent = child;
			child = 2 * parent + 1;
		}
		else
		{
			break;
		}
	}
}
void Swap(int* p1, int* p2)
{
	int tmp = *p1;
	*p1 = *p2;
	*p2 = tmp;
}
void HeapSort(int* a, int n)
{
	//建大堆
	for (int i = (n - 1 - 1) / 2; i >= 0; i--)
	{
		AdjustDwon(a, n, i);
	}
	//堆的删除
	int end = n - 1;
	while (end > 0)
	{
		Swap(&a[end], &a[0]);
		AdjustDwon(a, end, 0);
		end--;
	}
}

4. 特性总结

堆排序的特性总结:

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

四、总结

  • 简单选择排序通过每次选择最小(或最大)元素进行交换,逐步构建有序序列,其时间复杂度为O(N^2)。
  • 堆排序则利用堆的数据结构,通过建堆和堆删除操作实现排序,效率更高。
  • 时间复杂度为O(N*logN)。两种算法都具有空间复杂度O(1)的特点,但都不稳定。

感谢各位观看!希望能多多支持!


网站公告

今日签到

点亮在社区的每一天
去签到