数据结构-线索二叉树(先序线索二叉树及遍历)

  • 先序线索二叉树


  • 线索化的概念及相关图解

在上一篇中详细介绍了中序线索二叉树线索化图解相关概念都放在那篇博客啦,放个传送门

线索二叉树详细解析(含图解):传送门

 

  • 先序线索二叉树

(1)先序线索化

             ①思路:

                        a.根节点:若左孩子节点空,左孩子节点指向前驱节点(前一次访问的节点Pre_Node),标记该孩子为                                                       线索模式(Thread)

                                           若前一次访问的节点不为空并且它的右孩子为空,则该右孩子指向当前节点(后继节点),                                                         标记该孩子为线索模式(Thread)

                        b.保存当前节点,作为下一次的Pre_Node (记录历史的意思)

                        c.先线索化左孩子节点,再而是右孩子节点,前提是该孩子是链模式(Link)

             ②实现代码:

#define Link	0	//表示该节点有非空孩子节点
#define Thread	1	//表示该节点有后续节点(对于右子树来说)
template<class T>
void Thread_Binary_tree<T>::PreOrder_Thread_Op(BT_Thread_Node<T>* &Tree)
{
	if (Tree == NULL)
		return;

	if (Tree->Left_Child == NULL)		//根
	{
		Tree->Ltag = Thread;
		Tree->Left_Child = Pre_Node;
	}

	if (Pre_Node != NULL && Pre_Node->Right_Child == NULL)
	{
		Pre_Node->Rtag = Thread;
		Pre_Node->Right_Child = Tree;
	}

	Pre_Node = Tree;
	if (Tree->Ltag == Link)
		PreOrder_Thread_Op(Tree->Left_Child);		//左孩子节点
	if (Tree->Rtag == Link)
		PreOrder_Thread_Op(Tree->Right_Child);		//右孩子节点

}

注意!!!!!Pre_Node 是作为类内私有数据,相当于全局变量,对每个节点的线索都会使它改变!

 

(2)中序线索遍历

             ①思路:

                        a.靠左(每次都指向左孩子节点)访问:直到该节点的下一左孩子节点是指向它的前驱节点(不为Link模                                                                                                      式了),这个节点也是要访问的。

                        b.找后继节点:若该节点的右孩子指向的是后继节点,则进入该右孩子节点(暂不访问)

                        c.靠右访问:前提是该节点没有处在链(Link)模式的左孩子,有的话进入新一轮的遍历。

             ②实现代码:

template<class T>
void Thread_Binary_tree<T>::_PreOrder_Op(BT_Thread_Node<T>* &Tree)
{
	if (Tree == NULL)
		return;
	BT_Thread_Node<T>* Cur_Node = Tree;
	while (Cur_Node != NULL)		//遍历完的标志是节点为空
	{
		while (Cur_Node->Left_Child != NULL && Cur_Node->Ltag == Link)		//该节点存在左孩子节点
		{
			BT_Node_Stack[++Top] = Cur_Node;		//入栈是为了便于二叉树的析构
			cout << Cur_Node->Data << " ";
			Cur_Node = Cur_Node->Left_Child;
		}
		BT_Node_Stack[++Top] = Cur_Node;		//该节点的左孩子节点为NULL
		cout << Cur_Node->Data << " ";
		
		if (Cur_Node->Ltag == Thread)		//遇到线索,看右节点
		{
			Cur_Node = Cur_Node->Right_Child;
		}

		while (Cur_Node != NULL)		//右
		{
			if (Cur_Node->Left_Child != NULL && Cur_Node->Ltag == Link)//有左孩子节点,直接跳出循环
				break;

			BT_Node_Stack[++Top] = Cur_Node;		//访问并入栈该节点
			cout << Cur_Node->Data << " ";
			Cur_Node = Cur_Node->Right_Child;		//指向右孩子节点
		}
	}
	cout << endl;
}

把要访问的节点全部入栈???答:为了方便析构。

 

(3)析构线索树

              在写中序线索树的时候我是比较傻,又写了一遍线索遍历,这次干脆在遍历的时候就把节点入栈,便于删除。

             ①实现代码:

template<class T>
Thread_Binary_tree<T>::~Thread_Binary_tree()
{
	while (Top != -1)
	{
		delete BT_Node_Stack[Top];
		Top--;
	}
}

 

到这基础就讲完啦,看看类实现代码吧~

  • 先序线索二叉树类实现

(1)类定义包括常量定义

                         老思路,实现与接口分开~实现函数全部私有化

#include<iostream>
using namespace std;
#define Link	0	//表示该节点有非空孩子节点
#define Thread	1	//表示该节点有后续节点(对于右子树来说)
#define MAXSIZE  100

template<class T>
struct BT_Thread_Node
{
	T Data;
	BT_Thread_Node* Left_Child;
	BT_Thread_Node* Right_Child;
	int Ltag;
	int Rtag;
};

template<class T>
class Thread_Binary_tree
{
private:
	BT_Thread_Node<T>* Tree;
	BT_Thread_Node<T>* Pre_Node;
	BT_Thread_Node<T>* BT_Node_Stack[MAXSIZE];
	int Top;
	int Create_Thread_BTree(BT_Thread_Node<T>* &Tree);
	void PreOrder_Thread_Op(BT_Thread_Node<T>* &Tree);
	void _PreOrder_Op(BT_Thread_Node<T>* &Tree);
public:
	Thread_Binary_tree();
	~Thread_Binary_tree();
	void PreOrder_Thread();
	void _PreOrder();
};

(2)完整代码

#include<iostream>
using namespace std;
#define Link	0	//表示该节点有非空孩子节点
#define Thread	1	//表示该节点有后续节点(对于右子树来说)
#define MAXSIZE  100

template<class T>
struct BT_Thread_Node
{
	T Data;
	BT_Thread_Node* Left_Child;
	BT_Thread_Node* Right_Child;
	int Ltag;
	int Rtag;
};

template<class T>
class Thread_Binary_tree
{
private:
	BT_Thread_Node<T>* Tree;
	BT_Thread_Node<T>* Pre_Node;
	BT_Thread_Node<T>* BT_Node_Stack[MAXSIZE];
	int Top;
	int Create_Thread_BTree(BT_Thread_Node<T>* &Tree);
	void PreOrder_Thread_Op(BT_Thread_Node<T>* &Tree);
	void _PreOrder_Op(BT_Thread_Node<T>* &Tree);
public:
	Thread_Binary_tree();
	~Thread_Binary_tree();
	void PreOrder_Thread();
	void _PreOrder();
};

template<class T>
int Thread_Binary_tree<T>::Create_Thread_BTree(BT_Thread_Node<T>* &Tree)
{
	int Data;
	cin >> Data;
	if (Data == -1)
		Tree = NULL;
	else
	{
		Tree = new BT_Thread_Node<T>;
		Tree->Data = Data;

		//节点都要初始化为链状态Link
		Tree->Ltag = Link;
		Tree->Rtag = Link;
		Create_Thread_BTree(Tree->Left_Child);
		Create_Thread_BTree(Tree->Right_Child);
	}
	return 1;
}

template<class T>
void Thread_Binary_tree<T>::PreOrder_Thread_Op(BT_Thread_Node<T>* &Tree)
{
	if (Tree == NULL)
		return;

	if (Tree->Left_Child == NULL)		//根
	{
		Tree->Ltag = Thread;
		Tree->Left_Child = Pre_Node;
	}

	if (Pre_Node != NULL && Pre_Node->Right_Child == NULL)
	{
		Pre_Node->Rtag = Thread;
		Pre_Node->Right_Child = Tree;
	}

	Pre_Node = Tree;
	if (Tree->Ltag == Link)
		PreOrder_Thread_Op(Tree->Left_Child);		//左孩子节点
	if (Tree->Rtag == Link)
		PreOrder_Thread_Op(Tree->Right_Child);		//右孩子节点

}

template<class T>
void Thread_Binary_tree<T>::_PreOrder_Op(BT_Thread_Node<T>* &Tree)
{
	if (Tree == NULL)
		return;
	BT_Thread_Node<T>* Cur_Node = Tree;
	while (Cur_Node != NULL)		//遍历完的标志是节点为空
	{
		while (Cur_Node->Left_Child != NULL && Cur_Node->Ltag == Link)		//该节点存在左孩子节点
		{
			BT_Node_Stack[++Top] = Cur_Node;		//入栈是为了便于二叉树的析构
			cout << Cur_Node->Data << " ";
			Cur_Node = Cur_Node->Left_Child;
		}
		BT_Node_Stack[++Top] = Cur_Node;		//该节点的左孩子节点为NULL
		cout << Cur_Node->Data << " ";
		
		if (Cur_Node->Ltag == Thread)		//遇到线索,看右节点
		{
			Cur_Node = Cur_Node->Right_Child;
		}

		while (Cur_Node != NULL)		//右
		{
			if (Cur_Node->Left_Child != NULL && Cur_Node->Ltag == Link)//有左孩子节点,直接跳出循环
				break;

			BT_Node_Stack[++Top] = Cur_Node;		//访问并入栈该节点
			cout << Cur_Node->Data << " ";
			Cur_Node = Cur_Node->Right_Child;		//指向右孩子节点
		}
	}
	cout << endl;
}


template<class T>
Thread_Binary_tree<T>::Thread_Binary_tree()
{
	Create_Thread_BTree(Tree);
}

template<class T>
Thread_Binary_tree<T>::~Thread_Binary_tree()
{
	while (Top != -1)
	{
		delete BT_Node_Stack[Top];
		Top--;
	}
}

template<class T>
void Thread_Binary_tree<T>::PreOrder_Thread()
{
	PreOrder_Thread_Op(Tree);
}

template<class T>
void Thread_Binary_tree<T>::_PreOrder()
{
	_PreOrder_Op(Tree);
}

//测试
int main()
{
	Thread_Binary_tree<int> MyTree;
	MyTree.PreOrder_Thread();
	MyTree._PreOrder();
	return 0;
}

 

  • 11
    点赞
  • 46
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
线索叉树是一种对普通二叉树进行优化的数据结构,它的主要特点是将原本为空的左右子树指针利用起来,指向该节点在某种遍方式下的前驱或后继节点,从而实现遍时的快速跳转。线索叉树可以通过以下步骤实现: 1. 从根节点开始,如果当前节点不为空,则输出该节点的值。 2. 判断当前节点是否有左子树,如果有,则将当前节点的左子树指针作为线索指向该节点的前驱节点,然后将当前节点移动到其左子树。 3. 如果当前节点没有左子树,则将当前节点的左子树指针作为线索指向该节点的前驱节点的后继节点,然后将当前节点移动到其右子树。 4. 重复步骤2和3,直到当前节点为空或者遍完整棵树。 下面是一个示例代码,其中`preorder_threading`函数用于将普通二叉树转换为线索叉树,`preorder_traversal`函数用于实现线索叉树: ```python class ThreadedBinaryTreeNode: def __init__(self, value): self.value = value self.left = None self.right = None self.left_thread = False self.right_thread = False def preorder_threading(root): def _preorder_threading(node, prev): if node is None: return prev if node.left is None: node.left = prev node.left_thread = True if prev is not None and prev.right is None: prev.right = node prev.right_thread = True next_node = node.right if node.left_thread else node.left return _preorder_threading(node.left, node) if node.left else _preorder_threading(node.right, prev) _preorder_threading(root, None) def preorder_traversal(root): node = root while node is not None: print(node.value) if node.left_thread: node = node.left.right else: node = node.left ```

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值