现在的位置: 首页 > 综合 > 正文

二叉树的线索化

2018年01月16日 ⁄ 综合 ⁄ 共 1374字 ⁄ 字号 评论关闭

当二叉树使用链表表示时,用左右两个孩子指针可以找到左右孩子信息。我们可以用先序、中序、后序遍历二叉树,不同的遍历得到不同排列顺序的结点信息。只有在遍历的过程中才能得到某一结点的前驱与后继结点。
在n个结点的二叉树中,有2n个指针域,根节点不用指针域,其他(n-1)个结点只用了(n-1)个指针域,还有(n+1)个指针域空着没用,我们可以利用者空着的指针域来记录某种遍历下结点的前驱与后继。为了区分某个结点的指针域是指向孩子还是指向前驱/后继,要给结点添加的两个指针域添加标志,定义如下:

struct Node{  
    Node(int d):data(d),left(NULL),right(NULL),ltag(false),rtag(false){}   
    int data;  
    Node *left;  
    Node *right;
	bool ltag;
	bool rtag;
};

当ltag=false时,left指向左孩子;当ltag=true时,left指向其前驱
当rtag=false是,right指向其右孩子;当rtag=true时,right指向其后继。
将一颗二叉树n+1个空指针域添加前驱或后继的过程就是线索话二叉树的过程。显然结点的前驱与后继只有在遍历的过程中才能得到,线索话二叉树的过程也就是遍历二叉树的过程。二叉树线索后,就可以通过左右孩子指针直接找到其前驱与后继,以中序线索话为例,当二叉树中序线索话后,
1、找某结点的前驱:
如果该结点的ltag=true,那么left指向的结点就是其前驱结点
如果该结点的ltag=false,那么该结点左子树最右边的结点就是其前驱结点。
2、找某结点后继
如果该结点的rtag=true,那么rtag指向的结点就是其后继结点
如果该结点的rtag=false,那个该结点的右子树的最左边的结点就是其后继结点。
二叉树线索话过程就是遍历过程,递归线索话时,需要一个全局变量来指向上一次遍历的结点(前驱结点)

Node *pre=NULL;//全局变量 ,刚刚遍历的结点 
void BinTree::inorderThreading(Node *r)//中序线索话 
{
	if(r==NULL)
		return;
	inorderThreading(r->left);//递归线索话左子树 
	if(r->left==NULL)//如果左子树为空,则定义其前驱 
	{
		r->ltag=true;
		r->left=pre;
	}
	if(r->right==NULL)//右子树为空,先标记其指向后继,后继结点在下一次遍历才能得到,这里只是先标记 
		r->rtag=true; 
	if(pre!=NULL&&pre->rtag==true)//上次遍历的结点右子树指针被标记了,这次遍历的就是其后继 
		pre->right=r;
	pre=r;//相当于遍历当前结点
	inorderThreading(r->right);//线索话其右子树 
}

线索话后,如果要销毁二叉树,destroy函数要做点修改,当左右指针指向左右孩子时才可以递归销毁

//销毁树 
void BinTree::destroy(Node *r)
{
	if(r==NULL)
		return;
	if(r->ltag==false)
		destroy(r->left);
	if(r->rtag==false)
		destroy(r->right);
 	delete r;
 	r=NULL;
}

抱歉!评论已关闭.