[C++]最大HBLT

堆在数组中是隐式存储的,在时间和空间上都具有极大的优势。但是若要进行两个堆的合并操作,数组描述的堆就难已完成,于是引入链式描述的左高树。左高树分为高度优先的左高树HBLT和重量优先的左高树WBLT,本文只涉及HBLT。
对于一棵二叉树,引入概念外部节点,它表示树中的所有空子树。引入函数s(x),它表示根节点x到达其子节点的外部节点的最短距离。由该定义可知,如果根节点x的左子树或右子树为空,说明x直接与外部节点相连,则s(x)=1;而若s(x)=k,则说明x之下的(k-1)层都是不存在任何外部节点,即都被内部节点所填满。
HBLT要求对于树中的所有节点都满足其左子树的s()大于等于其右子树的s()。而最大HBLT还要求树满足大根数的性质,即根节点的数据值大于等于所有子节点的数据值。
最大HBLT最重要的函数是合并,其插入和删除操作都可以转化为两棵最大HBLT的合并。合并利用递归来完成,首先比较两树根节点的大小,将根节点小的树并入到根节点大的树,此时转化为将根节点小的树与根节点大的树的右子树进行合并,从而产生递归。合并结束之后需要自下而上维护整棵树,使之保持最大HBLT的性质,即如果某节点的左子树的s()小于右子树的s(),则需要交换左右子树,然后重新计算该节点的s()。
插入则相当于一个最大HBLT与一个只有一个节点的最大HBLT进行合并;删除则相当于把当前树的根节点的左右子树进行合并。

代码

#include<iostream>
#include<queue>
using namespace std;
template<class T>
struct binaryTreeNode//定义二叉树节点
{
	T element;//当前节点数值
	binaryTreeNode<T>* leftChild;//左子节点指针
	binaryTreeNode<T>* rightChild;//右子节点指针
	binaryTreeNode()
	{
		leftChild = NULL;
		rightChild = NULL;
	}
	binaryTreeNode(const T& theElement)
	{
		element = theElement;
		leftChild = NULL;
		rightChild = NULL;
	}
	binaryTreeNode(const T& theElement, binaryTreeNode<T>* LEFT, binaryTreeNode<T>* RIGHT)
	{
		element = theElement;
		leftChild = LEFT;
		rightChild = RIGHT;
	}
};

template<class T>
class maxHBLT//最大HBLT类
{
private:
	void meld(binaryTreeNode<pair<int, T>>*& x, binaryTreeNode<pair<int, T>>*& y)//递归合并两个左高树,合并结果为x,此函数需要封装
	{
		//递归终点
		if (y == nullptr)
			return;
		if (x == nullptr)
		{
			x = y;
			return;
		}

		//保证x根节点所存数据值比y大
		if (x->element.second < y->element.second)
			swap(x, y);

		//x与y的合并转化为x的右子树与y的合并,从而进行递归
		meld(x->rightChild, y);

		//递归结束之后需要对左高树的形状以及各个节点的s()进行维护
		if (x->leftChild == nullptr)//x的左子树为空,则交换左右子树
		{
			x->leftChild = x->rightChild;
			x->rightChild = nullptr;
			x->element.first = 1;
		}
		else
		{
			if (x->leftChild->element.first < x->rightChild->element.first)//x的左子树的s()小于右子树的s(),两者交换,并重新计算x的s()
				swap(x->leftChild, x->rightChild);
			x->element.first = x->rightChild->element.first + 1;//左高树根节点的s()就是从根节点一直向右走到达外部节点的距离
		}
	}
	binaryTreeNode<pair<int, T>>* root;//根节点,其元素为一个数对,前项表示根节点的s(),后项表示根节点存储的数据
	int treeSize;//节点总个数

public:
	maxHBLT()//空树
	{
		root = nullptr;
		treeSize = 0;
	}
	T front()//获取最大值(根节点的数据值)
	{
		return root->element.second;
	}

	//插入:相当于原树与一个只有一个元素的最大HBLT树合并
	void push(const T& theElement)
	{
		binaryTreeNode<pair<int, T>>* newNode = new binaryTreeNode<pair<int, T>>(pair<int, T>(1, theElement));
		meld(root, newNode);
		treeSize++;
	}

	//删除:相当于根节点的左右子树合并
	void pop()
	{
		if (treeSize == 0)
		{
			cout << "树为空" << endl;
			return;
		}
		binaryTreeNode<pair<int, T>>* left = root->leftChild;
		binaryTreeNode<pair<int, T>>* right = root->rightChild;
		delete root;
		root = left;
		meld(root, right);
		treeSize--;
	}

	//合并两个最大HBLT树
	void meld(maxHBLT<T>& theHBLT)
	{
		meld(root, theHBLT.root);
		treeSize += theHBLT.treeSize;
		theHBLT.root = nullptr;
		theHBLT.treeSize = 0;
	}

	//将一个数组转化为最大HBLT树
	void initialize(T* theElements,int theSize)
	{
		if (theSize < 1)
		{
			cout << "初始化无效" << endl;
			return;
		}
		queue<binaryTreeNode<pair<int, T>>*> queue;
		delete root;
		for (int i = 1; i <= theSize; i++)//先将数组中的元素转化为孤立的树的节点,存入队列中
			queue.push(new binaryTreeNode<pair<int, T>>(pair<int, T>(1, theElements[i])));
		for (int i = 1; i <= theSize - 1; i++)//然后循环取出两个节点,合并,然后再存入队列中
		{
			binaryTreeNode<pair<int, T>>* node1 = queue.front();
			queue.pop();
			binaryTreeNode<pair<int, T>>* node2 = queue.front();
			queue.pop();
			meld(node1, node2);
			queue.push(node1);
		}
		root = queue.front();//最终所有节点合并成一个最大HBLT树
		treeSize = theSize;
	}

	//输出树(检查用)
	void print()
	{
		int size = treeSize;
		for (int i = 0; i < size; i++)
		{
			cout << front() << " ";
			pop();
		}
		cout << endl;
	}
};
  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值