C++ 堆排序

基础

1.完全二叉树:若设二叉树的深度为h,除第h层外,其他各层(1~h-1)的结点数都达到最大节点个数,第h层所有的结点都连续集中在最左边并且中间不能有缺省节点,只能从最下面一层从右往左缺省节点,该算法下面的用到的就是完全二叉树。

2.最大堆结构:是一个完全二叉树,堆中每个节点的值总是不大于其父亲节点的值(即根节点总是最大的元素)

3.创建最大堆:二叉树的终端节点度为0的节点,也就是叶子节点。把所有非终端结点检查一遍,看是否满足最大堆的要求,如果不满足,则进行调整(检查当前结点是否满足:根>=左、右,若有不满足,则将当前结点与更大的一个孩子进行交换,若元素互换破坏了下一级的堆,则采用相同的方式继续往下调整,直至符合最大堆要求),我们以数组{53,17,78,9,45,65,87,32}为例,第一次调整我们从最下面一个有子节点的节点开始调整也就是9逐一向上调整,这里逐一向上调整的意思是下一个调整以78位根节点的子树,下一个调整以17为根节点的子树,最后调整以53位根节点的树,注意:在整个流程中我们调整上面的节点可能会破坏下面子树的最大堆结构具体流程如下图:

在这里插入图片描述

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

4.基于最大堆进行排序过程:每趟将堆顶元素加入有序子序列(这里我们可以将整个数组看成两个数组一个是末尾已经有序的,一部分是前面待排序的,与待排序序列最后一个元素交换,并将待排序序列再次调整最大堆,下面图中绿色节点为有序部分),再次重新调整为大根堆的过程只需要从整棵树的根节点向下调整即可过程如图所示:
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
![在这里插入图片描述](https://img-blog.csdnimg.cn/6ce60cc59d574787b640e0c4b6740665.png?x-oss-process=image/watermark,type_d3F5LXplbmhlaQ,shadow_50,text_Q1NETiBARFHmjIfpkog=,size_20,color_FFFFFF,t_70,g_se,x_16#pic_center
![在这里插入图片描述](https://img-blog.csdnimg.cn/15e858b04b4e4b5e8e24994343867780.png?x-oss-process=image/watermark,type_d3F5LXplbmhlaQ,shadow_50,text_Q1NETiBARFHmjIfpkog=,size_20,color_FFFFFF,t_70,g_se,x_16#pic_center
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

思想:

1.将待排序数组形象成一个最大堆结构,从最后一个父节点(n/2-1)开始将其调整为最大堆 (父节点下标为i,则左孩子下标为2i+1,右孩子下标为2i+2)

2.将堆顶元素与待排序数组最后一个元素进行交换

3.待排序数组数量减少一个,将待排序数组重新调整成最大堆结构,重复2、3操作n-1 次,将所以数据排序完成。

#include<iostream>
#include<vector>
using namespace std;
//start 调整最大堆的起始位置,end 调整最大堆的结束位置
void adjustHeap(vector<int>&vec, int strat, int end)
{
	int father = strat; // 根节点
	int child = 2 * father + 1; //左子树
        //while 循环是为了在调整最大堆的过程中破坏子树的结构,继续向下调整
	while (child < end) 
	{    
          //因为child是左子树,根节点要大于左右子树,所以要在子树中找到最大的再与根节点比较,所以要防止右子树越界就是在数组中下标为child+1的元素,child就是子树中最大的元素。
		if (child + 1 < end && vec[child + 1] > vec[child]) child++;
        //如果根节点大于子树就交换
		if (vec[child] > vec[father])
		{
			swap(vec[child], vec[father]);
        //如果发生交换就继续向下调整,因为可能破坏子树最大堆结构
			father = child;
			child = 2 * father + 1;
		}
        //如果没发生交换就退出该函数
		else return; 
	}
}
void HeapSort(vector<int>&vec)
{
	//从最后一个有子节点的节点开始调整
	for (int i = vec.size() / 2 - 1; i >= 0; i--)
	{
		adjustHeap(vec, i, vec.size());
	}
	for (int i = vec.size() - 1; i >= 1; i--)
	{
		swap(vec[0], vec[i]);
		//只有下标为0的元素被打乱,从根节点开始向下调整;
		adjustHeap(vec, 0, i);
	}
}
int main()
{
	vector<int>vec = { 53,17,78,9,45,65,87,32};
	HeapSort(vec);
	for (auto it : vec)
	{
		cout << it << " ";
	}
	return 0;
}

时间复杂度:

n个节点的完全二叉树有log 2(n+1)层。创建最大堆过程中,两两元素相互比较共比较n-1次,在交换过程中可能破坏某个最大堆结构,我们可以假设共调整k次可以恢复最大堆结构,故建堆过程时间复杂度为O(n+k)=O(n)。每个在无序数组部分最后一个节点交换过来的根节点最大下降log(n+1)-1层,每下降一层需比较两次,假设每个根节点都下降到最底层,则下降一个根节点的时间复杂度为O(2*(log(n+1)-1)),共有n-1个根节点需要下降,则下降过程的时间复杂度为O((n-1)2(log(n+1)-1))=O(nlogn)。
综上所述,堆排序时间复杂度为O(n)+O(n
logn)=O(n*logn)。

空间复杂度:O(1)

投稿来自 东北石油大学 - 大数据 201 - 金树正

  • 4
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值