【c++】模拟实现堆

这次我们来模拟实现堆,首先堆是一个完全二叉树,每个元素都有一个关键码,储存相应的数据,堆分为最大堆和最小堆。

最大堆:最大堆任意一个节点都大于它左右孩子的关键码,堆顶元素最大。

最小堆:最小堆任意一个节点都小于它左右孩子的关键码,堆顶元素最小。

因此我们得出以下结论:

堆存储在下标为0开始计数的数组中,因此在堆中给定小标为i的结点时:

1、如果i=0,结点i是根节点,没有双亲节点;否则结点i的双亲结点为结点(i-1)/2

2、如果2*i+1>n-1,则结点i无左孩子,否则结点i的左孩子为结点2*i+1

3、如果2*i+2>n-1,则结点i无右孩子,否则结点i的右孩子为结点2*i+2


 堆的创建:
最小堆与最大堆


首先我们来分析下堆所支持的操作:

template<class T, class Compare = Less<T>>//这里第二个参数是一个比较器,Less或者是Greater
class Heap
{
public:
	Heap();
	Heap(const T array[], size_t size);
	void Insert(const T& data);
	void Remove();                      //插入
	size_t Size()const;                 //移除
	bool Empty()const;                  //判断堆是否为空
	const T& Top()const;                //堆顶元素   
protected:
	void _AdjustDown(size_t parent);    //向下调整
	void _AdjustUp(size_t child);       //向上调整
private:
	vector<T> _heap;
};

代码如下:

template<class T>
struct Less//小堆的实现
{
	bool operator()(const T& left, const T& right)//重载()
	{
		return left < right;
	}
};

template<class T>
struct Greater//大堆的实现
{
	bool operator()(const T& left, const T& right)
	{
		return left > right;
	}
};


2、堆的生成

template<class T, class Compare = Less<T>>//这里第二个参数是一个比较器,Less或者是Greater
class Heap
{
public:
	Heap()
	{}

	Heap(const T array[], size_t size)
	{
		_heap.reserve(size);
		for (size_t i = 0; i < size; i++)
		{
			_heap.push_back(array[i]);
		}
		for (int j = (_heap.size() - 2) / 2; j >= 0; j--)
		{
			_AdjustDown(j);
		}
	}
};

3、向上向下调整操作

堆的向下调整算法和向上调整算法是堆的核心两个算法,它们的作用为:

堆的向下调整算法:用于建立堆,可以自行选择建立大堆或者建立小堆。

堆的向上调整算法:用于插入元素的时候使用。

void _AdjustDown(size_t parent)
{
	assert(parent);
	assert(!_heap.empty());
	size_t child = parent * 2 + 1;
	while (parent < _heap.size())
	{
		Compare com;
		if (child + 1<_heap.size()&& com(_heap[child + 1], _heap[child]))
		{
			++child;
		}
		if (child<_heap.size() && com(_heap[child], _heap[parent]))
		{
			swap(_heap[child], _heap[parent]);
			parent = child;
			child = parent * 2 + 1;
		}
		else
			break;
	}
}
void _AdjustUp(size_t child)
{
	assert(!_heap.empty());
	while(child)
	{
		Compare com;
		size_t parent = (child - 1) / 2;
		if (com(_heap[child], _heap[parent]))
		{
			swap(_heap[child], _heap[parent]);
			child = parent;
		}
		else
			break;
	}
}

下面给出完整代码:

#include <vector>
#include <assert.h>
using namespace std;
template<class T>
struct Less
{
	bool operator()(const T& left, const T& right)
	{
		return left < right;
	}
};

template<class T>
struct Greater
{
	bool operator()(const T& left, const T& right)
	{
		return left > right;
	}
};

// 小堆
template<class T, class Compare = Less<T>>
class Heap
{
public:
	Heap()
	{}

	Heap(const T array[], size_t size)
	{
		_heap.reserve(size);
		for (size_t i = 0; i < size; i++)
		{
			_heap.push_back(array[i]);
		}
		for (int j = (_heap.size() - 2) / 2; j >= 0; j--)
		{
			_AdjustDown(j);
		}
	}
	void Insert(const T& data)
	{
		assert(data);
		assert(!_heap.empty());
		_heap.push_back(data);
		_Adjustup(_heap.size() - 1);
	}
	void Remove()
	{
		assert(!_heap.empty());
		swap(_heap[0], _heap[size() - 1]);
		_heap.pop_back();
		_AdjustDown(0);
	}

	size_t Size()const
	{
		return _heap.size();
	}

	bool Empty()const
	{
		return _heap.empty();
	}

	const T& Top()const
	{
		assert(!_heap());
		return _heap[0];
	}

protected:
	//堆的插入
	void _AdjustDown(size_t parent)
	{
		assert(parent);
		assert(!_heap.empty());
		size_t child = parent * 2 + 1;
		while (parent < _heap.size())
		{
			Compare com;
			if (child + 1<_heap.size()&& com(_heap[child + 1], _heap[child]))
			{
				++child;
			}
			if (child<_heap.size() && com(_heap[child], _heap[parent]))
			{
				swap(_heap[child], _heap[parent]);
				parent = child;
				child = parent * 2 + 1;
			}
			else
				break;
		}
	}
	void _AdjustUp(size_t child)
	{
		assert(!_heap.empty());
		while(child)
		{
			Compare com;
			size_t parent = (child - 1) / 2;
			if (com(_heap[child], _heap[parent]))
			{
				swap(_heap[child], _heap[parent]);
				child = parent;
			}
			else
				break;
		}
	}
private:
	vector<T> _heap;
};






  • 2
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值