[数据结构] 基于选择的排序 选择排序&&堆排序

标题:[数据结构] 基于选择的排序 选择排序&&堆排序

@水墨不写bug


(图片来源于网络)


目录

(一)选择排序

实现:(默认从小到大排序)

优化后实现方法:

(二)堆排序

[实现: (从小到大排序)](#实现: (从小到大排序))


正文开始:

(一)选择排序

时间复杂度:O(N^2)

空间复杂度:O (1)

稳定性:不稳定

基本思想:

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

实现:(默认从小到大排序)

cpp 复制代码
void SelectSort(vector<int>& nums)
{
	int n = nums.size();
	int begin = 0, end = n - 1;
	
	for (int j = 0; j < n-1; ++j)
	{
		int maxi = 0;
		for (int i = 0; i < n-j; ++i)
		{
			if (nums[maxi] < nums[i])
			{
				maxi = i;
			}
		}
		swap(nums[end--], nums[maxi]);
	}
}

选择排序仍然有一种优化方法:

每次选择的时候,可以同时选择两个数,这样就可以减少遍历的次数,提高效率。

优化后实现方法:

cpp 复制代码
void SelectSort(vector<int>& nums)
{
	int n = nums.size();
	int begin = 0, end = n - 1;

	while(begin < end)
	{
		int maxi = begin, mini = begin;
		for (int i = begin; i <= end; ++i)
		{
			if (nums[maxi] < nums[i])
			{
				maxi = i;
			}
			if (nums[mini] > nums[i])
			{
				mini = i;
			}
		}
		swap(nums[mini], nums[begin]);
		if (maxi == begin)
		{
			maxi = mini;
		}
		swap(nums[maxi], nums[end]);

		begin++;
		end--;
	}
}

但是这种实现方法会导致一个问题:

由于每次选两个值,当最大值下标就是区间左端点时,由于需要将最小值放在左端点,这样会使最大值下标失效于是就需要修正最大值下标:

当最小值下标与区间左端点begin交换后,判断最大值下标是否指向区间左端点,如果是,则将其修正为交换后的最小值下标的位置。

下标交换只有四种情况:

其实这个问题的本质是:

将最小值交换到最前面的操作是先进行的,先进行的过程会对后进行的过程产生干扰。

最小值下标与区间左端点交换导致的最大值下标失效的问题,需要修正最大值下标。

(二)堆排序

堆排序实现过程:默认排升序

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

空间复杂度:O(1)

稳定性:不稳定

特点:小堆排降序,大堆拍升序。

小堆可以得到最小的数,然后将最小的数排除,在剩余的数中再次找到最小的数,依次类推;大堆类似。

实现原理:

用到了向下调整法建堆的过程:以大堆排升序为例

一般堆是由连续的数组模拟实现的逻辑结构,每次将堆顶最大的数移动到数组末尾后,需要向下调整来保持堆的特性。在向下调整之后,最大值就到了数组的末尾,堆也保持了其特性,接下来继续重复即可。

实现: (从小到大排序)

cpp 复制代码
void AdgustDown(vector<int>& nums,int pos,int size)
//排序的过程size是变化的,动态的,每完成一个数据,size要动态减小
{
	int n = size;
	int parent = pos;
	//find max child
	int child = pos * 2 + 1;
	
	while (child < n)
	{
		//假设左孩子大
		if (child + 1 < n && nums[child] < nums[child + 1])
		{
			child++;
		}
		if (nums[parent] < nums[child])
		{
			swap(nums[parent], nums[child]);
			parent = child;
			child = parent * 2 + 1;
		}
		else
		{
			break;
		}
	}
}
//大堆排升序
void HeapSort(vector<int>& nums)
{
	int n = nums.size();
	//建堆过程
	for(int i = (n-1-1)/2;i >= 0;--i)
	{ 
		AdgustDown(nums, i,n);
	}
	Print(nums);

	//排序过程
	for(int j = 0; j < n;++j)
	{
		int size = n - 1 - j;
		swap(nums[0], nums[size]);
		AdgustDown(nums, 0, size);
	}
}
int main()
{
	vector<int> nums = { 99,0,7,5,44,3,78,653,90,81 };
	Print(nums);

	HeapSort(nums);
	Print(nums);

	return 0;
}

完~

未经作者同意禁止转载

相关推荐
健康有益科技20 分钟前
慢病管理重构药店价值:数字化平台与物联网技术如何驱动行业升级?
大数据·人工智能·算法·软件工程·健康医疗·零售
野犬寒鸦1 小时前
力扣hot100:缺失的第一个正数(哈希思想)(41)
java·数据结构·后端·算法·leetcode·哈希算法
津津有味道2 小时前
15693协议ICODE SLI 系列标签应用场景说明及读、写、密钥认证操作Qt c++源码,支持统信、麒麟等国产Linux系统
linux·c++·qt·icode·sli·15693
闪电麦坤952 小时前
数据结构:开放散列(Open Hashing)
数据结构·算法·哈希算法·散列表
一枝小雨3 小时前
【C++】编写通用模板代码的重要技巧:T()
开发语言·c++·笔记·学习笔记
技术小泽5 小时前
Redis-底层数据结构篇
数据结构·数据库·redis·后端·性能优化
白菜帮张同学5 小时前
LP嵌入式软件/驱动开发笔试/面试总结
数据结构·驱动开发·经验分享·笔记·学习·算法·面试
蒹葭玉树5 小时前
【C++上岸】C++常见面试题目--数据结构篇(第十七期)
数据结构·c++·面试
熊大与iOS5 小时前
iOS 长截图的完美实现方案 - 附Demo源码
android·算法·ios
nonono5 小时前
数据结构——树(04二叉树,二叉搜索树专项,代码练习)
数据结构