最小堆

最大堆和最小堆是二叉堆的两种形式。

  1. 最大堆:根结点的键值是所有堆结点键值中最大者的堆。
  2. 最小堆:根结点的键值是所有堆结点键值中最小者的堆。

不失一般性,只讨论根结点为最小层的情况。

插入[编辑]

只需要将节点插在二叉树的最后一个叶子结点位置,然后比较它对它父亲节点的大小,如果大则停止;如果小则交换位置,然后对父亲节点递归该过程直至根节点。复杂度为O(log(n))。

一般来说,插入的位置可以不是最后一个叶子节点,可以作为任意中间节点的孩子节点插入,将这个叶子节点变为中间节点后,按上文所说的方法调整节点顺序以保证维持堆特性不变。

删除[编辑]

要从堆中删除一个节点,用最后一个节点替换掉根节点,然后调整节点顺序以维持堆特性。

堆定义文件:

#ifndef MINHEAP_H
#define MINHEAP_H
#include <iostream>
using std::cin;  
using std::cout;  
using std::endl;   
using std::ostream; 


template <typename T>
class MinHeap
{

	friend ostream& operator << (ostream& os,const MinHeap<T> &heap)
	{
		for(int i = 0; i < heap.currentSize; i++)
		{
			os << heap.heapArray[i] << "\t";
		}
		return os;
	}

private:
	T *heapArray;//存放堆数据的数组
	int maxSize;//堆所能容纳的最大元素数目
	int currentSize;//当前堆中元素数目

	void swap(int posx,int posy)//辅助函数,交换位置x和y的元素
	{
		T temp = heapArray[posx];
		heapArray[posx] = heapArray[posy];
		heapArray[posy] = temp;
	}

	void siftDown(int left)  //向下筛
	{
		int currentPos = left;					// 标识父结点
		int childPos = leftChild (currentPos);	// 标识关键值较小的子结点
		while (childPos < currentSize) 
		{       			    // 过筛
			if ((childPos < currentSize-1) && (heapArray[childPos] > heapArray[childPos + 1]))
			{
				childPos++;						// j指向右子结点,也就是元素最小的子节点
			}

			if (heapArray[currentPos] > heapArray[childPos]) 
			{
				swap(currentPos,childPos);
				currentPos = childPos;
				childPos = leftChild(childPos);						// 向下继续调整
			}
			else 
			{
				break; // 调整到位
			}
		}
	}

	void siftUp(int currentPos) //向上调整
	{

		int parentPos = parent(currentPos);//父节点位置
		while(currentPos > 0)//调整到0号位置则应停止
		{
			if(heapArray[currentPos] < heapArray[parentPos])//向上调整
			{
				swap(currentPos,parentPos);
				currentPos = parentPos;
				parentPos = parent(currentPos);
			}
			else
			{
				break;//已经到位
			}
		}
	}

	void buildHeap()
	{
		for(int i = currentSize/2 - 1; i >= 0; i--)
		{
			siftDown(i);//反复调用筛选函数
		}
	}

public:
	MinHeap(const int size) : maxSize(size)
	{
		if(size <= 0)
		{
			return;
		}
		heapArray = new T[maxSize];
		currentSize = 0;
/*

		//此处进行堆元素的赋值工作
		heapArray[0] = 19;                 //亦可以用插入的办法构造
		heapArray[1] = 8;
		heapArray[2] = 35;
		heapArray[3] = 65;
		heapArray[4] = 40;
		heapArray[5] = 3;
		heapArray[6] = 7;
		heapArray[7] = 45;
		currentSize = 8;

		buildHeap();*/
		
	}

	~MinHeap()
	{
		delete []heapArray;
	}
	bool isEmpty() const// 如果堆空,则返回真
	{
		return currentSize == 0;
	}

	bool isLeaf(int pos) const//是否叶子节点
	{
		return (pos >= currentSize/2) && (pos <= currentSize-1);
	}

	int leftChild(int pos) const//返回左孩子位置
	{
		return 2 * pos + 1;
	}

	int rightChild(int pos) const//返回右孩子位置
	{
		return 2 * pos + 2;
	}

	int parent(int pos) const//返回父节点位置
	{
		return (pos-1)/2;
	}

	bool insert(T &newNode)//向堆中插入新元素newNode
	{
		if(currentSize == maxSize)//堆空间已经满
		{
			return false;
		}
		else
		{
			heapArray[currentSize] = newNode;
			siftUp(currentSize);//向上调整
			currentSize++;
			return true;
		}
	}

	bool remove(int pos, T& node)    	// 删除给定下标的元素
	{
		if(pos < 0 || pos > currentSize - 1)
		{
			return false;
		}

		node = heapArray[pos];
		heapArray[pos] = heapArray[--currentSize];// 用最后的元素值替代删除位置的元素

		if(heapArray[pos] < heapArray[parent(pos)])// 当前元素小于父结点,需要上升调整
		{
			siftUp(pos);
		}
		else
		{
			siftDown(pos);//向下筛
		}

		return true;
	}

	bool removeMin(T& node)    	// 删除堆顶的元素
	{
		/*if(currentSize == 0)
		{
			cout << "堆为空,无法移除!" << endl;
			return false;
		}
		else
		{
			node = heapArray[0];
			swap(0,--currentSize);//交换堆顶和最后一个元素
			if(currentSize > 1)
			{
				siftDown(0);
			}			
			return true;
		}*/
		return remove(0,node);
	}
};
#endif

测试代码:

#include "MinHeap.h"


int main()
{
	MinHeap<int> minheap(8);
	cout << "初始化堆:" << minheap << endl;

	int Key[] = {19,8,35,65,40,3,7,45} ;  

	cout << "建堆前:" << endl;   
	for(int i = 0;i < 8; i++)  
	{          
		minheap.insert(Key[i]);
		cout<< Key[i] << "\t";
	}
	cout << endl;

	cout << "建堆后:" << endl;
	cout << minheap << endl;

	int elem;
	cout<< "删除给定下标(3)的元素:" << endl;
	minheap.remove(3,elem);
	cout<<  elem << " deleted." << endl;
	cout << "现在堆: " << endl;
	cout <<  minheap << endl;

	//插入45
	cout<< "插入45:" << endl;
	minheap.insert(elem);
	cout << "现在堆: " << endl;
	cout <<  minheap << endl;

	cout << "从堆顶删除最小值:" ;
	minheap.removeMin(elem);
	cout << elem << endl;
	cout << "现在堆: " << endl;
	cout <<  minheap << endl;

	system("pause");
	return 0;
}




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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值