数据结构与算法之左高树

知识点来源于参考书籍《数据结构、算法与应用》,本人仅作整理与记录,方便日后复习查看。

左高树的定义:

      设x是扩充二叉树的一个结点,并令left_child(x)和right_child(x)分别表示内部结点的左、右儿子。定义shortest(x)为从x到一个外部结点的最短路程长度。

      令s (x)为从节点x到它的子树的外部节点的所有路径中最短的一条,根据s(x)的定义可知,

若x是外部节点,则s的值为0,若x为内部节点,则它的s值是:

其中L与R分别为x的左右孩子。

        左高树是一棵二叉树,且如果该二叉树不空,则对其中的每个内部结点x,都有:

                                       Shortest(left_child(x))>= Shortest(right_child(x))。

       一棵二叉树称为高度优先左高树,当且仅当其中任何一个内部节点的左孩子的s值都大于或等于右孩子的S值。如果一颗HBLT同时还是大根树,则称为最大HBLT。如果一棵HBLT同时还是小根树,则成为最小HBLT。

      一棵二叉树称为重量优先左高树,当且仅当其中任何一个内部节点的左孩子的W值都大于或等于右孩子的W值。(若x是内部节点,则他的重量是其孩子节点的重量之和加1).

        最大HBLT的插入: 最大HBLT的插入操作可利用最大HBLT的合并操作来实现,假定将元素x插入名为H的最大HBLT中。如果构建一棵仅有一个元素x的最大HBLT,然后将其与H进行合并,那么合并之后的最大HBLT将包括H的全部元素和元素x.。因此,要插入一个元素,可以先建立一棵新的只包含这个元素的HBLT,然后将这棵HBLT与原来的HBLT进行合并。

        最大HBLT的删除:最大元素在根中。如果根本删除,则剩下左右孩子,然后以左右孩子为最大HBLT进行合并,便是删除后的结果。

       两棵最大HBLT的合并(左高树中最重要的操作):合并策略最好采用递归来实现。令A、B为需要合并的两棵最大HBLT。若一个为空,则另一个便是合并后的结果。假设两者均不为空,为实现合并,先比较两个根元素,较大者作为合并后的根。假定A的根比较大,且左子树为L。令C是A的右子树与B合并而成的HBLT。A与B合并的结果是以A为根,以L和C为子树的最大HBLT。如果L的s值小于C的s值,则C为左子树,L为右子树。以下是合并两棵左高树的C++函数meld。该函数首先处理特殊情况:要合并的两棵树至少有一棵树为空。当两棵树都不为空时,要确保x的根元素大于y的根元素,否则x与y进行交换。接下来,通过递归,要将x的右子树与y进行合并。合并后,为保证结果是最大的HBLT,x的左右孩子可能需要交换,这时候需要计算s值。

template
void maxHblt::meld(binaryTreeNode> * &x, binaryTreeNode> * &y)
{
	//合并分别以*x,*y为根的两棵左高树
	//合并后的左高树以x为根,返回x的指针
	if(y== NULL)
		return ;
	if(x==NULL)
	{x = y;return;}
    //x和y均不为空,必要时交换x,y
	if(x->element < y->element)
	{
		swap(x,y);
	}
	//将x的右子树与y进行合并
	meld(x->rightChild,y);
	//为保证结果是最大HBLT,需要计算子树的S值大小
	if(x->leftChild == NULL)
	{
		//左子树为空,交换子树
		x->leftChild = x->rightChild;
		x->rightChild = NULL;
		x->element.first = 1;
	}
	else
	{
		if(x->leftChild->element.first < x->rightChild->element.first)
			swap(x->leftChild,x->rightChild);
                //右子树的s值小,故将右子树s值加一
		x->element.first = x->righChild->element.first+1; 
	}
	
}

 

       最大HBLT的初始化:初始化过程是将n个元素逐个插入最初为空的最大HBLT中,所需的时间为O(nlogn )。为得到具有线性时间的初始化算法,我们首先创建n个仅含一个元素的最大HBLT,这n棵树组成一个FIFO队列,然后从队列中依次成对删除HBLT,然后将其合并后再插入到队列末尾,直到只有一个HBLT为止。以下是最大HBLT的初始化,代码用一个基于数组的FIFO队列保存在初始化过程中产生的最大HBLT。在第一个for循环中,产生了n个只有一个元素的最大HBLT,并将其插入到初试为空的队列中。在第二个for循环中,每次从队列中删除两个最大的HBLT进行合并,然后将结果加入队列中。当for循环结束后,队列中仅含有一棵最大HBLT。

template
void maxHblt::initialize(T* theElements, int theSize)
{
	//用数组theElements[1:theSize]建立左高树
	arrayQueue>*> q(theSize);
	erase();                           //使*this为空
	//初始化树的队列
	for(int i=1;i<=theSize;i++)
	{
		//建立只有一个节点的树
		q.push(new binaryTreeNode>(pair(1,theElements[i])));
	}
	//从队列中重复取出两棵树进行合并
	for(int i=1;i<=theSize-1;i++)
	{
		//从队列中删除两棵树合并
		binaryTreeNode> *b = q.front();
		q.pop();
		binaryTreeNode> *c = q.front();
		q.pop();
		meld(b,c);
		//将合并后的树插入队列
		q.push(b);
	}
	if(theSize>0)
		root = q.front();
	treeSize = theSize;
}

    其他方法:说明:在一棵最大HBLT中,节点的数据类型是binaryTreeNode>;pair的第一个成员是节点的s值,第二个成员是优先级队列元素。

template
void maxHblt::meld(maxHblt & theHblt )
{
	//将左高树*this与theHblt合并
	meld(root,theHblt.root);
	treeSize  = treeSize+theHblt.treeSize;
	theHblt.root = NULL;
	theHblt.treeSize = 0;
}

template
void maxHblt::push(const T& theElement )
{
	//建立只有一个元素的左高树,其实就是建立一棵二叉树
	binaryTreeNode> *q = new binaryTreeNode>(pair(1,theElement));
	//将单元素左高树合并
	meld(root,q);
	treeSize ++;
}

template
void maxHblt::pop()
{
	if(root == NULL)
		throw queueEmpty();
	//树不空
	binaryTreeNode> *left = root->leftChild;
	binaryTreeNode> *right = root->rightChild;
	delete root;
	root = left;
	meld(root,right);
	treeSize--;
}

 

你可能感兴趣的:(数据结构与算法)