后序线索化二叉树及遍历(图解)

上一篇博客对于 二叉树线索化以及线索化的先序、中序、后序遍历做了比较详细的描述

写在前面

 其实,我还是很想把本篇博客和二叉树的线索化写在一块的,但是考虑到可能这博客的内容就看足以超过了上一篇的篇幅,考虑到读者可能会疲乏,而且这篇也是线索二叉树中最难的了(查阅了很多网上的资料也鲜有人来讲述后序线索二叉树的遍历,有的就算有也只是把代码放在那里,理解 对于初学者还是有点困难的)


构建节点多了双亲节点节点

typedef enum
{
	Link,
	Thread
}Pointer;

typedef struct TriTreeNode
{
	TriTreeNode(const char data)
	:_data(data)
	, pLeft(NULL)
	, pRight(NULL)
	, pParent(NULL)
	, Ltag(Link)
	, Rtag(Link)
	{}
	char _data;
	struct TriTreeNode* pLeft;
	struct TriTreeNode* pRight;
	struct TriTreeNode* pParent;//双亲
	Pointer Ltag, Rtag;
}TriTreeNode;


还是先给出一个树结构吧:


后序线索化二叉树

后序的顺序是:左- 右-根

思路:和先序、中序线索化二叉树的顺序是一样的,在此不再赘述,想看的话上一篇博客会让你满意的。


上代码:

void _PostThreading(TriTreeNode*&  Root)
	{
		if (Root)
		{
			_PostThreading(Root->pLeft);
			_PostThreading(Root->pRight);
			if (Root->pLeft == NULL)
			{
				Root->pLeft = Prev;
				Root->Ltag = Thread;
			}
			if (Prev && Prev->pRight == NULL ) //条件 Prev
			{
				Prev->pRight = Root;
				Prev->Rtag = Thread;
			}
			Prev = Root;
		}
	}

如下图,后序线索化的二叉树

后序线索化二叉树及遍历(图解)_第1张图片


!!!

后序遍历线索二叉树

由后序遍历的顺序,我们很容易就想到了找到后序遍历的起点(左子树最左边的节点),然后一直遍历节点的后继(记住每次遍历的前一个节点),当遍历到节点没有后继了,我们就判断是不是到了根节点了(如果根节点没有右子树,就是这种情况了),要是还没有到根节点,那就继续找寻节点的双亲节点(此时就需要我们催节点的结构进行增加双亲节点了),一直找到根节点的位置,继续判断根节点是不是存在右子树(注意这里不能用NULL判断右子树是不是存在,而是用右子树存在的标识Rtag )

好了,描述再多还是代码代码来的实在!!!

	void _PostOrder(TriTreeNode* Root)
	{
		if (Root)
		{
			TriTreeNode* pCur = Root;
			Prev = NULL;
			while (pCur != NULL)
			{
				//第一步:找树最左边的节点
				while ( pCur->pLeft != Prev && pCur->Ltag == Link) //左子树
				{
					pCur = pCur->pLeft;
				}
				//循环结束后 pCur== Root 或者为空

				//第二步:访问后继
				while (pCur && pCur->Rtag== Thread)
				{
					cout << pCur->_data << ' ';
					Prev = pCur;
					pCur = pCur->pRight;
				}
				//判断此时pCur是不是指向了根节点
				if (pCur == Root)
				{
					cout << pCur->_data << ' ';
					return;
				}
				while (pCur && pCur->pRight == Prev)
				{
					cout << pCur->_data << ' ';
					Prev = pCur;
					pCur = pCur->pParent;  //往上一级走
				}
				//这里不能用NULL判断,而是用Rtag
				if (pCur && pCur->Rtag == Link)
				{
					pCur = pCur->pRight;
				}
			}
	        //end-while
		}
	}
下面就是对代码的一一讲述 < 福利来了>

首先对,大循环中的第一个循环解释(找到最左边的节点)

后序线索化二叉树及遍历(图解)_第2张图片

第二个循环(访问后继)

后序线索化二叉树及遍历(图解)_第3张图片

第三个循环以及后面的判断

后序线索化二叉树及遍历(图解)_第4张图片


后面就是对代码的测试


来个简单的Tree

后序线索化二叉树及遍历(图解)_第5张图片

加深一点

后序线索化二叉树及遍历(图解)_第6张图片

再难点吧。哈哈

后序线索化二叉树及遍历(图解)_第7张图片


能看到这里的都是好样的!


全部代码

#define _CRT_SECURE_NO_WARNINGS 1
#include
using namespace std;

typedef enum
{
	Link,
	Thread
}Pointer;

typedef struct TriTreeNode
{
	TriTreeNode(const char data)
	:_data(data)
	, pLeft(NULL)
	, pRight(NULL)
	, pParent(NULL)
	, Ltag(Link)
	, Rtag(Link)
	{}
	char _data;
	struct TriTreeNode* pLeft;
	struct TriTreeNode* pRight;
	struct TriTreeNode* pParent;//双亲
	Pointer Ltag, Rtag;
}TriTreeNode;

class PostThread_BiTree
{
public://先序遍历创建树
	PostThread_BiTree(const char arr[], size_t size)
	{
		size_t index = 0;
		TriTreeNode* parent = NULL;
		_Creat_Bitree(_pRoot, arr, size, index, parent);
	}
protected:
	void _Creat_Bitree(TriTreeNode*& Root, const char arr[], size_t size, size_t& index , TriTreeNode*& parent)
	{
		if (arr && size > index && arr[index] != '#')
		{
			Root = new TriTreeNode(arr[index]);
			Root->pParent = parent;

			_Creat_Bitree(Root->pLeft, arr, size, ++index , Root);  //每次传双亲节点
			_Creat_Bitree(Root->pRight, arr, size, ++index , Root);
		}
	}
public:
	//后序线索化
	void PostTreading()
	{
		_PostThreading(this->_pRoot);
	}
protected:
	void _PostThreading(TriTreeNode*&  Root)
	{
		if (Root)
		{
			_PostThreading(Root->pLeft);
			_PostThreading(Root->pRight);
			if (Root->pLeft == NULL)
			{
				Root->pLeft = Prev;
				Root->Ltag = Thread;
			}
			if (Prev && Prev->pRight == NULL ) //条件 Prev
			{
				Prev->pRight = Root;
				Prev->Rtag = Thread;
			}
			Prev = Root;
		}
	}
public:
	void PostOrder()
	{
		_PostOrder(this->_pRoot);
	}
protected:
	void _PostOrder(TriTreeNode* Root)
	{
		if (Root)
		{
			TriTreeNode* pCur = Root;
			Prev = NULL;
			while (pCur != NULL)
			{
				//第一步:找树最左边的节点
				while ( pCur->pLeft != Prev && pCur->Ltag == Link) //左子树
				{
					pCur = pCur->pLeft;
				}
				//循环结束后 pCur== Root 或者为空

				//第二步:访问后继
				while (pCur && pCur->Rtag== Thread)
				{
					cout << pCur->_data << ' ';
					Prev = pCur;
					pCur = pCur->pRight;
				}
				//判断此时pCur是不是指向了根节点
				if (pCur == Root)
				{
					cout << pCur->_data << ' ';
					return;
				}
				while (pCur && pCur->pRight == Prev)
				{
					cout << pCur->_data << ' ';
					Prev = pCur;
					pCur = pCur->pParent;  //往上一级走
				}
				//这里不能用NULL判断,而是用Rtag
				if (pCur && pCur->Rtag == Link)
				{
					pCur = pCur->pRight;
				}
			}
	        //end-while
		}
	}
private:
	TriTreeNode* _pRoot;
	TriTreeNode* Prev;
};

void Test()
{
	char* arr = "013##4##25##6##";
	PostThread_BiTree tree(arr, strlen(arr)); //构建三叉树
	tree.PostTreading();
	tree.PostOrder();//arr 3 4 1  5 6 2  0
	cout << endl << "______________________" << endl;

	char* arr1 = "013##4##2#56###";
	char* arr2 = "12#3##4##";
	PostThread_BiTree tree1(arr2, strlen(arr2));
	tree1.PostTreading();
	tree1.PostOrder();
	cout << endl << "______________________" << endl;

	char* arr3 = "12#3#4##5##";
	PostThread_BiTree tree2(arr3, strlen(arr3));
	tree2.PostTreading();
	tree2.PostOrder();
	cout << endl << "______________________" << endl;

	char* arr4 = "126##3#4##5##";
	PostThread_BiTree tree3(arr4, strlen(arr4));
	tree3.PostTreading();
	tree3.PostOrder();
	cout << endl << "______________________" << endl;

}
int main()
{
	Test();
	return 0; 
}


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