二叉树线索化

        二叉树遍历是一个很不错的问题,但是处理起来有点复杂,使用递归算法,会导致空间复杂度极大,而不使用递归会导致算法极难控制。因此我们使用一种线索化的算法,使得有的节点指向遍历时访问的下一个节点,从而通过很简单的算法实现遍历。

        就让我们来看一下代码的实现吧:

首先是一些头文件引用和节点的构造

#include <iostream>
#include <stdlib.h>
#include <stack>
using namespace std;

enum PointTag{ LINK, THREAD };                //区别节点的指针的类别是link还是线索
template<class T>
struct BinaryTreeNode
{
	T _data;
	BinaryTreeNode* _left;
	BinaryTreeNode* _right;
	PointTag _lefttag;
	PointTag _righttag;
	BinaryTreeNode(const T& x)
		:_data(x), _left(NULL), _right(NULL), _lefttag(LINK), _righttag(LINK)
	{
	}
};


然后就是这个二叉树类的实现,还有上次未完成的后续遍历的算法实现。


template<class T>
class BinaryTree
{
	typedef BinaryTreeNode<T> Node;
public:
	BinaryTree(const T* a,size_t n,const T& invalid )
	{
		size_t index = 0;
		_root=create(a,n,invalid,index);
	}
	void inorderthread()
	{
		Node* prev = NULL;
		_inorderthread(_root,prev);
		prev->_righttag = THREAD;
	}
	void inorderthd()
	{
		_inorderthd(_root);
		cout << endl;
	}
	void PostOrderNorm()
	{
		_PostOrderNorm(_root);
		cout << endl;
	}
protected:
	Node* create(const T* a, size_t n, const T& invalid,size_t& index)
	{
		Node* root = NULL;
		if ((a[index] != invalid) && (index < n))
		{
			root = new Node(a[index]);
			root->_left = create(a, n, invalid, ++index);
			root->_right = create(a, n, invalid, ++index);
		}
		return root;
	}
	void _inorderthd(Node* cur)             //线索化后的遍历,无需使用栈,比普通使用栈的算法又简洁了不少
	{
		while (cur)
		{
			while (cur->_lefttag == LINK)
			{
				cur = cur->_left;
			}
			cout << cur->_data << " ";
			while (cur&&(cur->_righttag == THREAD))
			{
				cur = cur->_right;
				if (cur!=NULL)
				cout << cur->_data << " ";
			}
			if (cur)
			cur = cur->_right;
		}
	}
	void _inorderthread(Node* cur,Node*& prev)//中序线索化
	{
		if (cur == NULL)
			return;
		if (cur->_left!=NULL)
		_inorderthread(cur->_left,  prev);



               //走到这,按照顺序改访问此(cur)节点了
		if (cur->_left == NULL)                  //此节点访问的上一个节点,为该节点的左线索
		{
			cur->_left = prev;
			cur->_lefttag = THREAD;
			
		}
		if (prev&&(prev->_right == NULL))        //负责上个节点的右孩子的线索化
		{
			prev->_right = cur;
			prev->_righttag = THREAD;
		}
        prev = cur;


		if (cur->_right!=NULL)
		_inorderthread(cur->_right, prev);
	}
	void _PostOrderNorm(Node* cur)  //后续遍历的非递归算法
	{
		stack<Node*> s;
		Node* prev = NULL;      //用来标记上次访问的节点
		while (!s.empty() || cur != NULL)
		{
			while (cur)
			{
				s.push(cur);
				cur = cur->_left;
			}
			Node* top = s.top();
			if (top->_right == NULL)// 叶子节点访问
			{
				cout << top->_data << " ";
				prev = top;
				s.pop();
				top = s.top();
			}
			while (top&&(((top->_left == prev) && (top->_right == NULL)) || (top->_right == prev))) //如果该节点所有子树都遍历完毕,就该访问该节点了
			{
				cout << top->_data << " ";
				prev = top;
				s.pop();
				if (s.empty())
					top = NULL;
				else
					top = s.top();
				
			}

			if (top!=NULL)     //子问题
			cur = top->_right;
		}
	}
protected:
	Node* _root;
};
测试代码如下(后序遍历和线索化要分开测试):
void testbinarytree()
{
	int a[10] = { 1, 2, 3, '#', '#', 4, '#', '#', 5, 6 };
	BinaryTree<int> t1(a, sizeof(a) / sizeof(a[0]), '#');
	//t1.inorderthread();
	//t1.inorderthd();
	t1.PostOrderNorm();
}

有必要一提的是,一棵树只能有一种线索化(前序,中序,后序)。



  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值