中序線索化二叉樹

/* 
 中序線索化二叉樹
 當用二叉樹鏈表作爲二叉樹的存儲結構時,因爲每個結點中只有指向其左右孩子結點的指針
 ,所以從任一結點出發只能直接找到該結點的左,右孩子。在一般的情況下靠它無法直接的
 找到該結點在某種遍歷次序下的前驅和後繼結點。如果在每個結點中增加指向其前驅和後繼
 結點的指針,將降低存儲空間的效率。
 與此同時,我們可以證明:在n個結點的二叉樹鏈表中含有n+1個空指針。因爲含n個結點的
 二叉樹鏈表中含有2n個指針,除了根節點,每個結點都一個從父結點指向該結點的指針,因此
 一共使用了n-1個指針,所以在n個結點的二叉樹鏈表中含有2n-(n-1)=n+1個空指針
 因此,可以利用這些空指針,存放指向在某種遍歷次序下的前驅和後繼結點的指針。這種附加
 的指針稱爲線索,加上線索的二叉樹稱爲線索二叉樹。爲了區分一個結點的指針是指向其孩子的
 指針,還是指向其前驅或者後繼結點的線索,可在每個結點中增加兩個線索標誌。這樣,線索
 二叉樹結點類型定義爲 
 ltag
 lchild
 data
 rchild
 rtag
 1.當ltag=0時,表示lchild指向該結點的左孩子;
 2.ltag=1時,表示lchild指向該結點的線性前驅結點;
 3.rtag=0時,表示rchild指向該結點的右孩子;
 4.rtag=1時,表示rchild指向該節點的線性後繼結點;
 以二叉樹鏈表結點數據結構所構成的二叉樹作爲二叉樹的存儲結構,叫做線性二叉樹鏈表;指向結 
 點的線性前驅或者線性後繼結點的指針叫做線索;加上線索的二叉樹稱爲線索二叉樹;對二叉樹以
 某種次序遍歷將其變爲線索二叉樹的過程叫做線索化。
 中序線索化是指用二叉樹鏈表結點數據結構建立二叉樹的二叉樹鏈表,然後按照中序遍歷的方法訪
 問結點時建立線索。
 */

#include<stdio.h>
#include<stdlib.h>
typedef enum ptag {link,thread};    //枚舉 link==0 指針    thread==1 線索
typedef struct bithrtree{
	char data;
	struct bithrtree *plchild,*prchild;
	ptag ltag,rtag;
}BITHRTREE,* PBITHRTREE;
PBITHRTREE pre;                        //設置爲全局變量 始終指向上一結點
PBITHRTREE init(void);
void inorderthreading(PBITHRTREE thrt,PBITHRTREE t);
void inordertraverse(PBITHRTREE t);
void inthread(PBITHRTREE t);
int main(void)
{
	BITHRTREE phead;                          //頭結點
	PBITHRTREE t;
	t=init();
	inorderthreading(&phead,t);
	inordertraverse(&phead);
	return 0;
}
PBITHRTREE init(void)
{
	PBITHRTREE pa,pb,pc,pd,pe,pf;
    pa=(PBITHRTREE)malloc(sizeof(BITHRTREE));
	pb=(PBITHRTREE)malloc(sizeof(BITHRTREE));
	pc=(PBITHRTREE)malloc(sizeof(BITHRTREE));
	pd=(PBITHRTREE)malloc(sizeof(BITHRTREE));
	pe=(PBITHRTREE)malloc(sizeof(BITHRTREE));
	pf=(PBITHRTREE)malloc(sizeof(BITHRTREE));
	if(NULL==pa||NULL==pb||NULL==pc||NULL==pd||NULL==pe)
		{
			printf("動態分配失敗");
			exit(-1);
		}
	pa->data='A'; pa->ltag=pa->rtag=link;
	pb->data='B'; pb->ltag=pb->rtag=link;
	pc->data='C'; pc->ltag=pc->rtag=link;
	pd->data='D'; pd->ltag=pd->rtag=link;
	pe->data='E'; pe->ltag=pe->rtag=link;
	pf->data='F'; pf->ltag=pf->rtag=link;
	pa->plchild=pb;
	pa->prchild=pc;
	pb->plchild=NULL;
	pb->prchild=pd;
	pd->plchild=pd->prchild=NULL;
	pc->plchild=pe;
    pc->prchild=NULL;
	pe->plchild=NULL;
	pe->prchild=pf;
	pf->plchild=pf->prchild=NULL;
	return pa;
}
void inorderthreading(PBITHRTREE thrt,PBITHRTREE t)
{

	thrt->ltag=link;
	thrt->rtag=thread;
	thrt->prchild=thrt;                    //右指針回指
    if(NULL==t)
		{
		thrt->plchild=thrt;                    //若爲空 左回指指針
		}
	else
		{
		thrt->plchild=t;
		pre=thrt;  
		inthread(t);                //中序線索化
	    pre->prchild=thrt;
		pre->rtag=thread;                               //最後一個結點的線索化
		thrt->prchild=pre;
		}
	return ;
}
void inthread(PBITHRTREE t)
{
	PBITHRTREE p=t;
	if(p)
		{
		inthread(p->plchild);                             //左子樹線索化
		if(p->plchild==NULL)                                      //前驅線索
			{
			p->ltag=thread;
			p->plchild=pre;
			}
		if(pre->prchild==NULL)                              //後驅線索
			{
			pre->rtag=thread;
			pre->prchild=p;
			}
		pre=p;
	    inthread(p->prchild);                       //右子樹線索化         
		}
	return ;
}
void inordertraverse(PBITHRTREE t)
{
	PBITHRTREE p;
	p=t->plchild;
	while(p!=t)                                    //指針回指指向頭結點時結束
	{ 
		while(p->ltag==link)                          //當左標誌域爲0 說明左指針是左孩子
		{
		p=p->plchild;                                 //一直遍歷到的左子樹的最左的結點
		}
		printf("%c",p->data);
		while(p->rtag==thread && p->prchild!=t)                   //當右標誌爲線索(找後繼) 並且沒有回指
			{
			p=p->prchild;                                                
			printf("%c",p->data);                  //訪問
			}
		p=p->prchild;                         //rtag 不爲線索 指針指向右孩子
	}
	return ;
	
}

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章