c++实现堆

目录

堆是什么

大顶堆和小顶堆

补充知识

堆实现

创建类

建堆heapify

上浮up&下潜down

堆的增删替换

测试案例


hello,各位baby🤗们,好久不见,甚是想念!好了,不多说废话了,接下来进入我们今天的学习

今天我们要学的是堆,使用自定义的方式实现堆。

在实现堆之前,我们先来了解一下什么是堆

堆是什么

先上一波概念,在计算机科学中,堆是一种基于数的数据结构,通常用完全二叉树来实现。(完全二叉树是除最后一层外,其他层都是填满的,当然最后一层填满的也是完全二叉树。完全二叉树添加新节点时必须要靠左添加!)

有可能概念不是那么好懂,接下来看一张图就能明白了

到这有可能有些小伙伴会疑惑了,为什么上面的这个堆叫大顶堆,别急,接下来就来讲讲什么是大顶堆和小顶堆

大顶堆和小顶堆

大顶堆符合任意节点与它的父节点符合父节点值大于等于子节点值

小顶堆符合任意节点与它的父节点符合父节点值小于等于子节点值

堆了解到这,还远远不够,为了能实现堆,这里还在多补充点知识

补充知识

1.最顶层的节点(没有父亲)的称之为root根节点

2.堆(底层是完全二叉树实现)是一种非线性结构,但存储时可以采用线性的数组结构来存储数据

3.用数组存储,如果从索引0开始存储节点数据

     1.节点i的父节点为(i-1)/2

      2.节点i的左子节点为2*i+1,右子节点为2*i+2

了解以上概念,自己实现堆就没什么大问题了,在这里我要实现的一个类既能实现大顶堆也能实现小顶堆(是不是有点高级(嘻嘻嘻))

堆实现
创建类

当为真(true)时为大顶堆,为假(false)时为小顶堆

class Heap
{
public:
	Heap(vector<int>& v1,bool max)
	{
		this->_V = v1;
		_size = v1.size();
		_max = max;
		heapify();
	}
public:
	vector<int> _V;
	int _size;
	bool _max;
};

在这申明一下,为了简单起见和方便再在力扣刷题,这里就不用泛型实现堆了,用int类型实现

细心的小伙伴可能会发现在构造方法中为什么多了一行代码,其实我们要自己实现堆功能的第一步就是要建堆,多的那行代码就是用来建堆的

建堆heapify

主流的建堆算法有两种,一种是威廉姆斯建堆算法,另一种是佛洛依德建堆算法。

威廉姆斯建堆算法就是从堆底添加节点不断上浮,这里就不细讲了(时间复杂度没有佛洛依德算法的好),时间复杂度为O(n*log(n))

佛洛依德建堆算法思路:

   1.找到最后一个非叶子节点

   2.从后向前,对每个节点执行下潜

时间复杂度为O(n)

void heapify()//建堆
	{
		int index = (_size >> 1) - 1;//找到最后一个非叶子节点
		for (int i = index; i >= 0; i--)
		{
			down(i);//下潜
		}
	}

上面讲两种建堆算法中有提到上浮和下潜,接下来就来实现上浮和下潜代码,可以说上浮和下潜是堆中最重要的,所有功能都是基于这两个代码上实现的

上浮up&下潜down

下潜:(以大顶堆为例)将parent索引处的元素下潜,与两个孩子较大者交换,直至没有孩子或孩子都没它大

void Heap::down(int parent)
{
	int left = 2 * parent + 1;
	int right = left + 1;
	int MaxorMin = parent;
	if (left<_size && (_max?_V[left]>_V[MaxorMin]:_V[left]<_V[MaxorMin]))
	{
		MaxorMin = left;
	}
	if (right<_size && (_max ? _V[right]>_V[MaxorMin]:_V[right] < _V[MaxorMin]))
	{
		MaxorMin = right;
	}
	if (MaxorMin != parent)
	{
		swap(_V[parent], _V[MaxorMin]);
		down(MaxorMin);//递归
	}
}

上浮:(以大顶堆为例)将插入的元素上浮,直至value小于父亲或到堆顶

上浮代码思想和插入排序思想相似

void Heap::up(int value)
{
	_V.push_back(-1);
	int child = _size;
	while (child > 0)
	{
		int parent = (child - 1) / 2;
		//三目操作符
		bool cmp = _max ? value > _V[parent]:value < _V[parent];
		if (cmp)
		{
			_V[child] = _V[parent];
		}
		else
		{
			break;
		}
		child = parent;
	}
	_V[child] = value;
}

实现完上浮和下潜接下来的代码就是易如反掌😏

堆的增删替换

增是往堆底加入节点

void myPush(int value)
	{//增
		up(value);
		_size++;
	}

删是删除堆顶节点并返回堆顶节点的值

int myPop()
	{
		int deleted = _V[0];
		swap(_V[0], _V[_size - 1]);
		_V.pop_back();
		_size--;
		down(0);
		return deleted;
	}

替换是替换堆顶节点

void myReplace(int replaced)
{
	_V[0] = replaced;
	down(0);
}

到这为止,堆的功能基本已经完全实现了🎉

测试案例
void test01()
{
	vector<int> v1 = { 2,4,6,5,1,3,7 };
	Heap minheap(v1, false);
	for (vector<int>::iterator it = minheap._V.begin(); it != minheap._V.end(); it++)
	{
		cout << *it << ' ';
	}
	cout << endl;
	Heap maxheap(v1, true);
	for (vector<int>::iterator it = maxheap._V.begin(); it != maxheap._V.end(); it++)
	{
		cout << *it << ' ';
	}
	cout << endl;
}

学习的时间总是短暂的,这篇blog到这里就结束了~

创作不易,还望各位小可爱🤗多多支持🌹🌹🌹

想要点赞收藏关注❤️❤️❤️

如有错,还望各位大佬指点一下😘

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值