1. 程式人生 > >線索二叉樹的中序遍歷

線索二叉樹的中序遍歷

#include<iostream>
#include<vector>
using namespace std;
typedef enum{Link,Thread}PointTag;	//Link==0:指標,Thread==1:線索

template<class T>
class BiTrNode{
	template<class T> friend class BiTrTree;
private:
	T data;
	BiTrNode *lchild,*rchild;		//左右孩子指標
	PointTag ltag,rtag;				//左右標誌
};
 
template<class T>
class BiTrTree
{
public:
	//BiTrTree<T>():elem={};
	void InputBiTrNode();							   //輸入構成數的結點元素,‘#’表示空串  
    void Pre_CreateBiTrTree(BiTrNode<T> *&TT);			   //先序構造二叉樹
	void InThreading(BiTrNode<T> *p);	   //中序遍歷二叉樹
	void InOrderThreading(BiTrNode<T> *&Thrt,BiTrNode<T> *TT);//中序遍歷二叉樹T,將其中序線索化,Thrt指向頭結點
	void InOrderTraverse_Thr(BiTrNode<T> *TT);			   //中序遍歷二叉線索樹
	void visit(T data);								   //輸出結點元素
private:  
    vector<T> elem;  
	BiTrNode<T> *pre;
};

template<class T>
void BiTrTree<T>::InputBiTrNode()  
{  
    T ch;  
    cout<<"!!!注意:(1)'#'表示空結點;(2)請在輸入的字串末尾加0,作為輸入結束的標誌。"<<endl;  
    while(cin>>ch&&ch!='0')  
    {  
        elem.push_back(ch); //在容器中加入結點元素  
    }//while  
}//InputBiTrNode

template<class T>
void BiTrTree<T>::Pre_CreateBiTrTree(BiTrNode<T> *&TT)  
{                               
    vector<T>::iterator it=elem.begin();   //迭代器it指向elem的開頭  
    if(it!=elem.end())  
    {  
        if(*it=='#')//字元為空格,表示結點不存在  
        {  
            TT=NULL;  
            elem.erase(it); //刪除迭代器it指向的elem中的元素,作用是依次刪除elem的第一個元素  
        }//if  
        else  
        {  
            if(!(TT=new BiTrNode<T>))  
                exit(-1);  
            TT->data=*it;     //生成根結點  
            elem.erase(it); //刪除迭代器it指向的elem中的元素,作用是依次刪除elem的第一個元素  
            Pre_CreateBiTrTree(TT->lchild);    //構造左子樹  
            Pre_CreateBiTrTree(TT->rchild); //構造右子樹  
        }//else  
    }//if  
    else    //此時elem為空,使此時T=NULL;,即結束最初的T的結點的賦值  
        TT=NULL;   
}//Pre_CreateBiTrTree  

template<class T>
void BiTrTree<T>::InThreading(BiTrNode<T> *p)
{
	BiTrNode<T> *pt=pre;	//用p儲存pre最初的值Thrt
	if(p)
	{
		InThreading(p->lchild);	//左子樹線索化
		if(!(p->lchild))
		{
			p->ltag=Thread;p->lchild=pre;	//前驅線索
		}//if
		else					//左子樹不為空,則左孩子標記為指標
			p->ltag=Link;
		if(!(pre->rchild))		
		{
			pre->rtag=Thread;pre->rchild=p;	//後繼線索
		}//if
		else					//右結點指標不為空,則二叉樹T中的結點右結點標誌設定為指標Link型
		{
			if(pre!=pt)		//pre是二叉樹T中的結點(不帶頭結點Thrt的二叉樹)
				pre->rtag=Link;
		}//else
		pre=p;								//保持pre指向p的前驅
		InThreading(p->rchild);				//右子樹線索化
	}//else
}//InOrderThreading

template<class T>
void BiTrTree<T>::InOrderThreading(BiTrNode<T> *&Thrt,BiTrNode<T> *TT)
{
	//BiTrNode<T> *pre=NULL;
	if(!(Thrt=new BiTrNode<T>))
		exit(-1);
	Thrt->ltag=Link;Thrt->data=0;Thrt->rtag=Thread;	//建立頭結點,左標誌為指標,右標誌為線索
	Thrt->rchild=Thrt;					//右指標回指,指向自己實現二叉連結串列的迴圈操作if
	if(!TT)
		Thrt->lchild=Thrt;				//若二叉樹為空,則左指標回指
	else
	{
		Thrt->lchild=TT;pre=Thrt;
		InThreading(TT);					//中序遍歷進行中序線索化
		pre->rchild=Thrt;pre->rtag=Thread;	//最後一個結點線索化
		Thrt->rchild;
	}//else
}//InOrderThreading

template<class T>
void BiTrTree<T>::InOrderTraverse_Thr(BiTrNode<T> *TT)
{
	BiTrNode<T> *p=NULL;
	p=TT->lchild;
	while(p!=TT)
	{
		while(p->ltag==Link)	//找到二叉樹左子樹最左端的結點,即中序遍歷的第一個結點
		{
			p=p->lchild;
		}//while
		visit(p->data);			//訪問其左子樹為空的結點
		while(p->rtag==Thread&&p->rchild!=TT) 
		{									 
			p=p->rchild;					 
			visit(p->data);					 
		}//
		/*假設沒有進行while迴圈,則該結點無左孩子有右孩子,由於已被訪問,則下一步就是訪問其右結點 */
		/*假設執行了while迴圈,此時p不滿足while條件,說明p有右孩子,以p為根節點,既然p被訪問,則中*/
		/*序遍歷剩下遍歷其右子樹                                                                  */
		p=p->rchild;
	}//while
}//InOrderTraverse_Thr

template<class T>
void BiTrTree<T>::visit(T data)
{
	cout<<data;
}//visit

void main()
{
	BiTrNode<char> *TT,*Thrt;
	BiTrTree<char>  BTT;
	BTT.InputBiTrNode();
	BTT.Pre_CreateBiTrTree(TT);
	BTT.InOrderThreading(Thrt,TT);
	cout<<"\n"<<"中序遍歷線索二叉樹:"<<endl;
	BTT.InOrderTraverse_Thr(Thrt);
}//mian