1. 程式人生 > >樹——線索二叉樹的建立、遍歷(前序、中序、後序)

樹——線索二叉樹的建立、遍歷(前序、中序、後序)

      直接上程式碼。
#include<iostream>
#include<cstdio>
using namespace std;

#define OK 1
#define ERROR 0

typedef int Status;
typedef char TElemType;
/*
  定義線索二叉樹的資料結構
*/
typedef struct BiThrNode
{
	char data;//結點對應的資料
	int ltag, rtag;//左右孩子標記
	struct BiThrNode *lchild;//左孩子
	struct BiThrNode *rchild;//右孩子
}BiThrNode,*BiThrTree;
/*
   輸出對應結點裡面的值
*/
Status PrintElement(TElemType e)
{
	cout << e;
	return OK;
}


/*
尋找p結點在Thrt樹中的父節點,便於進行後序遍歷
*/
BiThrTree parent(BiThrTree &Thrt, BiThrTree &p)
{
	BiThrTree temp=Thrt->lchild;

	if (p==Thrt->lchild)//p即為根節點,返回建立的頭結點
	{
		return Thrt;
	}
	if (temp->lchild == p)
	{
		return temp;//父節點就是我們尋找的結點
	}
	else
	{
		temp = temp->lchild;
		while (temp->lchild != p&&temp->rchild != p)
		{
			/*
			如果節點有右孩子,那就往右
			如果節點沒有右孩子,就往左
			沒有左孩子,就往前驅
			*/
			if (temp->rtag == 0)
			{
				temp = temp->rchild;
			}
			else
			{
				temp = temp->lchild;
			}
		}
		return temp;
	}
}



/*
    建立線索二叉樹,初始化跟二叉樹的初始化遞迴演算法一樣
*/
Status CreateBiThrTree(BiThrTree &T)
{
	char ch;
	cin >> ch;
	if (ch == '#')
		T = NULL;
	else
	{
		if (!(T = (BiThrNode *)malloc(sizeof(BiThrNode))))
			exit(OVERFLOW);

		T->data = ch;
		T->ltag = 0;
		T->rtag = 0;
		CreateBiThrTree(T->lchild);
		CreateBiThrTree(T->rchild);
	}
	return OK;
}

/*
    T指向頭結點,頭結點的左鏈lchild指向根節點
	中序遍歷二叉線索樹T的非遞迴演算法,對每個資料元素呼叫函式Visit

*/
Status InOrderTraverse_Thr(BiThrTree T, Status(*Visit)(TElemType e))
{
	BiThrTree p = T->lchild;
	while (p&&(p != T))
	{
		while (p->ltag == 0)
		{			
			p = p->lchild;
		}
		Visit(p->data);
		while (p->rtag == 1 && p->rchild != T)
		{
			p = p->rchild;
			Visit(p->data);
		}
		p = p->rchild;
	}
	return OK;
}
/*
   前序遍歷二叉樹非遞迴演算法(仿造中序遍歷)
*/
Status PreOrderTraverse_Thr(BiThrTree T, Status(*Visit)(TElemType e))
{
	BiThrTree p = T;
	while (p)
	{
		while (p->ltag == 0)
		{
			Visit(p->data);
			p = p->lchild;
		}		
		Visit(p->data);
		p = p->rchild;
	}
	return OK;
}
/*
   後序遍歷二叉樹非遞迴演算法
*/
Status PostOrderTraverse_Thr(BiThrTree T, Status(*Visit)(TElemType e))
{
	BiThrTree p = T->lchild;
	BiThrTree pre = T;

	//p指向第一個被訪問結點
	while (p->ltag == 0||p->rtag==0)
	{
		while(p->ltag==0)
			p = p->lchild;
		if (p->rtag == 0)
			p = p->rchild;
	}
	while (p != T) 
	{
		Visit(p->data);
		pre = parent(T, p);//找到該節點的雙親

		if (T == pre)//如果雙親是T,就說明p是根節點,無後繼
		{
			p = T;
		}
		//如果p是雙親的右孩子,或者雙親無右孩子,則後繼為雙親
		else if(p==pre->rchild||pre->rtag==1)
		{
			p = pre;
		}
		else
		{
			//若p的雙親有右孩子,後繼為雙親右子樹上後序遍歷的第一個孩子
			while (pre->rtag == 0)
			{
				pre = pre->rchild;
				while (pre->ltag == 0)
				{
					pre = pre->lchild;
				}
			}
			p = pre;
		}
	}
	
		
	
	
	return OK;
}
/*
  中序遍歷進行二叉樹線索化
*/
void InThreading(BiThrTree p,BiThrTree &pre)
{
	if (p)
	{
		InThreading(p->lchild,pre);//左子樹線索化
		if (!p->lchild)
		{
			p->ltag = 1;
			p->lchild = pre;
		}
		if ((!pre->rchild)&&pre->rchild==NULL)
		{
			pre->rtag = 1;
			pre->rchild = p;
		}
		pre = p;
		InThreading(p->rchild, pre);//右子樹線索化
	}
}
/*
   前序遍歷進行二叉樹線索化
*/
void preThreading(BiThrTree p, BiThrTree &pre)
{
	if (p)
	{
		if (p->lchild == NULL)
		{
			p->lchild = pre;
			p->ltag = 1;
		}
		if (pre != NULL&&pre->rchild == NULL)
		{
			pre->rchild = p;
			pre->rtag = 1;
		}
		pre = p;
		if (p->ltag == 0)
			preThreading(p->lchild, pre);
		if (p->rtag == 0)
			preThreading(p->rchild, pre);
	}
}

/*
   後序遍歷進行線索二叉樹化
*/
void postThreading(BiThrTree p, BiThrTree &pre)
{
	if (p)
	{
	postThreading(p->lchild, pre);
	postThreading(p->rchild, pre);
	if (p->lchild==NULL)
	{
		p->lchild = pre;
		p->ltag = 1;
	}
	if (pre != NULL&&pre->rchild == NULL)
	{
		pre->rchild = p;
		pre->rtag = 1;
	}
	pre = p;
   }
}


/*
   中序遍歷二叉樹T,並將其中序線索化,Thrt指向頭結點
*/
Status InOrderThreading(BiThrTree &Thrt, BiThrTree T)
{
	//建立頭結點
	if (!(Thrt = (BiThrTree)malloc(sizeof(BiThrNode))))
		exit(OVERFLOW);
	Thrt->ltag = 0;
	Thrt->rtag = 1;

	Thrt->rchild = Thrt;//右指標回指
	BiThrTree pre;
	if (!T)
		Thrt->lchild = Thrt;//若二叉樹為空,則指標回指
	else
	{
		Thrt->lchild = T;
		pre = Thrt;
		InThreading(T,pre);//中序遍歷進行中序線索化
		pre->rchild = Thrt;//最後一個結點線索化
		pre->rtag = 1;
		Thrt->rchild = pre;
	}
	return OK;
}

/*
   後序遍歷二叉樹,並將其線索化,原理同中序
*/
Status PostOrderThreading(BiThrTree &Thrt, BiThrTree T)
{
	//建立頭結點
	if (!(Thrt = (BiThrTree)malloc(sizeof(BiThrNode))))
		exit(OVERFLOW);
	Thrt->ltag = 0;
	Thrt->rtag = 1;

	Thrt->rchild = Thrt;//右指標回指
	BiThrTree pre;

	if (!T)
		Thrt->lchild = Thrt;//若二叉樹為空,則指標回指
	else
	{
		Thrt->lchild = T;
		pre = NULL;
		postThreading(T, pre);//後序遍歷進行後序線索化
		pre->rchild = Thrt;
		pre->rtag = 1;
		Thrt->rchild = pre;//最後一個結點線索化
	}
	return OK;
}



void main()
{
	
	BiThrTree T1, Thrt1;
	cout << "建立線索二叉樹,按先序次序輸入線索二叉樹中結點的值:\n";
	CreateBiThrTree(T1);
	if (InOrderThreading(Thrt1, T1) == OK)
		cout << "成功建立中序線索化連結串列!\n";
	cout << "中序遍歷線索二叉樹,結果是:\n";
	InOrderTraverse_Thr(Thrt1, PrintElement);
	cout << endl;

	BiThrTree T2;
	 
	cout << "建立線索二叉樹,按先序次序輸入線索二叉樹中結點的值:\n";
	CreateBiThrTree(T2);
	BiThrTree test1 = T2;
	preThreading(T2, test1);
	cout << "前序遍歷線索二叉樹,結果是:\n";
	PreOrderTraverse_Thr(T2, PrintElement);
	cout << endl;
	
	BiThrTree T3,Thrt3;
	cout << "建立線索二叉樹,按先序次序輸入線索二叉樹中結點的值:\n";
	CreateBiThrTree(T3);
	if (PostOrderThreading(Thrt3, T3) == OK)
		cout << "成功建立後序序線索化連結串列!\n";
	cout << "後序遍歷線索二叉樹,結果是:\n";
	PostOrderTraverse_Thr(Thrt3, PrintElement);
	cout << endl;

	system("pause");
}