The clueization and traversal of preorder, middle order and postorder of binary clue tree

Clue binary tree

Note: source code

  • The concept of binary clue tree The
    binary clue tree is based on the traditional binary tree structure, plus flags to determine whether the left and right children of the node are empty-LTag, RTag.
    When the left child is empty, lchild points to the predecessor node of the node, and when the right child is empty, rchild points to the successor node of the node. In order to increase the storage density of the linked list. Below we give the structure of the binary clue tree:
	typedef struct BiTNode
	{
    
    
		char data;//数据域
		int LTag = 0;//左标签
		int RTag = 0;//右标签
		struct BiTNode* lchild = nullptr;//指针必须初始化,c11标准
		struct BiTNode* rchild = nullptr;//左右孩子
	}BiTNode, * BiTree;
  • Compared with the general binary tree, the advantage of the binary clue tree is the binary
    linked list as the storage structure. It can only find the left and right child information of the node, but cannot get the predecessor and successor information of the node in any sequence. This information can only be traversed It can only be obtained in the dynamic process, and the binary clue tree can store the predecessor and successor information in these dynamic processes. And because the general binary tree has n nodes, there must be an (n+1) empty chain domain (easy to prove). Therefore, these air chain domains can be fully utilized to store the precursor and subsequent information, and the storage density can be increased.

  • Create a binary tree
    We create a binary tree by traversing first, input the root node first, then create the left subtree, and then create the right subtree (if the node data is #, it means an empty tree). code show as below:

	void CreateBiTree(BiTree& T,BiTree P)//先序输入 
	{
    
    
		char ch;
		cin >> ch;
		if (ch == '#') T = NULL;
		else
		{
    
    
			T = new BiTNode;//分配空间
			T->data = ch;//根节点赋值
			T->parent = P;
			CreateBiTree(T->lchild,T);//建立左子树
			CreateBiTree(T->rchild,T);//建立右子树
		}
	}
  • First-order threaded binary tree The first-order threading is
    carried out in the order from the left to the root. The specific process is:
    first, we first create an empty BiTree Thrt (on the one hand, it is used as the precursor node of the first node, and the last node Successor nodes. On the other hand, the binary tree can also be formed into a doubly linked list. It can be traversed from the first node in succession or from the last node to the predecessor, which is very convenient -^- ^- ), create a BiTree pre always point to the node just visited.
    Second, we first find the root node. If this node does not have a left child, we point lchild to its predecessor and assign this node to pre. If pre has no right child, we point the rchild of pre to the current node.
    Finally, recurse the left subtree and then recurse the right subtree.
    The tree we want to traverse is as follows:

Insert picture description here
The binary tree after the pre-order threading is like this (a bit ugly -^- ^- ):
Insert picture description here
The code is attached below (pre is a global variable of BiTree type. If you don’t want the lead tree of the node, it will be the first leftmost The lchild of the node is empty, and then pre points to this node):

//以结点T为根的子树先序线索化
void PreThreading(BiTree& T)
{
    
    
	if (T)//T非空
	{
    
    
		if (!T->lchild)//左子树为空
		{
    
    
			T->LTag = 1;
			T->lchild = pre;//指向前驱结点
		}
		else
		{
    
    
			T->LTag = 0;
		}
		if (!pre->rchild)
		{
    
    
			pre->RTag = 1;
			pre->rchild = T;//指向后继结点
		}
		else
		{
    
    
			T->RTag = 0;
		}
		pre = T;//pre指向当前节点
		if (T->LTag == 0)//这点很重要,只有结点有左孩子的时候才可以遍历左子树,否则会陷入死循环
		{
    
    
			PreThreading(T->lchild);//遍历左子树
		}
		if (T->RTag == 0)//同上
		{
    
    
			PreThreading(T->rchild);//遍历右子树
		}
	}
}
//以结点T为根的字树先序线索化

//带头节点的二叉树先序线索化
void PreOrderThreading(BiTree& Thrt, BiTree T)
{
    
    
	Thrt = new BiTNode;//头节点
	Thrt->LTag = 0;//左标签为零,表明有左子树
	Thrt->RTag = 1;
	Thrt->rchild = Thrt;//右子树指向自己
	if (!T)//若为空树,右子树指向自己
	{
    
    
		Thrt->lchild = Thrt;
	}
	else
	{
    
    
		Thrt->lchild = T;//左指针指向T
		pre = Thrt;
		PreThreading(T);//进行线索化
		pre->rchild = Thrt;//此时pre为最右面的那个节点,让它的右子树为Thrt
		pre->RTag = 1;
		Thrt->rchild = pre;//Thrt的右子树为pre,形成闭环
	}
}
//带头节点的二叉树先序线索化

At this point, the preorder threading of the binary tree is over.

  • Middle-order threaded binary
    tree The steps of middle-order threaded binary tree are similar to pre-order binary tree. The specific steps are:
    1. Traverse the left subtree, find the leftmost node, let his lchild point to pre, and point pre to the current node .
    2. Repeat the above steps for the root node.
    3. Traversing the right subtree.
    The following is a diagram of an in-order threaded binary tree (the diagram is still very ugly):
    Insert picture description here
    The code is attached below (the code is still that code, but the order is changed):
//以结点T为根的子树中序线索化
void InThreading(BiTree &T)
{
    
    
	if (T)//T非空
	{
    
    
		InThreading(T->lchild);//遍历左子树
		if (!T->lchild)//左子树为空
		{
    
    
			T->LTag = 1;
			T->lchild = pre;
		}
		else
		{
    
    
			T->LTag = 0;
		}
		if (!pre->rchild)
		{
    
    
			pre->RTag = 1;
			pre->rchild = T;
		}
		else
		{
    
    
			T->RTag = 0;
		}
		pre = T;
		InThreading(T->rchild);//遍历右子树
	}
}
//以结点T为根的字树中序线索化

//带头节点的二叉树中序线索化
void InOrderThreading(BiTree& Thrt, BiTree T)
{
    
    
	Thrt = new BiTNode;
	Thrt->LTag = 0;
	Thrt->RTag = 1;
	Thrt->rchild = Thrt;
	if (!T)
	{
    
    
		Thrt->lchild = Thrt;
	}
	else
	{
    
    
		Thrt->lchild = T;
		pre = Thrt;
		InThreading(T);
		pre->rchild = Thrt;
		pre->RTag = 1;
		Thrt->rchild = pre;
	}
}
//带头节点的二叉树中序线索化
  • Post-order clue binary tree The
    post-order clue binary tree is the same as the previous idea:
    1. First traverse the left subtree, find the leftmost node, if its lchild is empty, this lchild points to pre, if the rchild of pre is empty, then The rchild of pre points to the current node.
    2. Traverse the right subtree and proceed with the above steps.
    3. Finally, perform the above operations on the root node.
    The following is a diagram of the post-order clues binary tree (the diagram is still very ugly):
    Insert picture description here
    Attach the code:
//以结点T为根的子树后序线索化
void PosThreading(BiTree& T)
{
    
    
	if (T)//T非空
	{
    
    
		PosThreading(T->lchild);//遍历左子树
		PosThreading(T->rchild);//遍历右子树
		if (!T->lchild)//左子树为空
		{
    
    
			T->LTag = 1;
			T->lchild = pre;
		}
		else
		{
    
    
			T->LTag = 0;
		}
		if (!pre->rchild)
		{
    
    
			pre->RTag = 1;
			pre->rchild = T;
		}
		else
		{
    
    
			T->RTag = 0;
		}
		pre = T;
	}
}
//以结点T为根的字树后序线索化

//带头节点的二叉树后序线索化
	void PosOrderThreading(BiTree& Thrt, BiTree T)
	{
    
    
		Thrt = new BiTNode;
		Thrt->LTag = 0;
		Thrt->RTag = 1;
		Thrt->rchild = T;
		if (!T)
		{
    
    
			Thrt->lchild = Thrt;
		}
		else
		{
    
    
			Thrt->lchild = T;
			pre = Thrt; 
			PosThreading(T);
		}
	}
	//带头节点的二叉树后序线索化

Seeing this, the clues of the binary clue tree are over, when our story is not over (life is not only the clues in front of us, but also the traversal of the binary tree). Let's talk about the traversal of the binary tree clue tree.

  • Traversing the preorder clue tree When
    traversing the clue tree preorder, first define a BiTree p, pointing to the left subtree of the head node p, that is, p = T->child.
    Then, we need to output the information of p. If the node has a left subtree, then p points to the left subtree and outputs the node information. If there is no left subtree, then p points to the right subtree and outputs the information.
    Finally, when p points to T, the loop ends.
    The following is an example of the pre-order traversal (the animation is not well done):
    Insert picture description here
    The code is attached below (it is so simple):
	//遍历先序线索二叉树
	void PreTraverse_Thr(BiTree T)
	{
    
    
		BiTree p = T->lchild;
		while (p != T)
		{
    
    
			cout << p->data;
			if (p->LTag == 0)
			{
    
    
				p = p->lchild;
			}
			else
			{
    
    
				p = p->rchild;
			}
		}
	}
//遍历先序线索二叉树
  • Traversing the middle-order clue tree
    The idea of ​​traversing the middle-order clue tree is to follow the left-root-right idea:
    First, find the leftmost node p and output the node value.
    Then, if rchild=1, p = p->rchild of the node on the left, output the node value and repeat.
    If traversing to the root node p, p = p->rchild. In the loop, until p is the end of T.
    The following is an example of the middle order traversal (the animation is still not well done):
    Insert picture description here
    attach the code (still as simple as that):
//遍历中序线索二叉树
void InTraverse_Thr(BiTree T)
{
    
    
	BiTree p = T->lchild;//
	while (p != T)
	{
    
    
		while (p->LTag == 0)
		{
    
    
			p = p->lchild;
		}
		cout << p->data;
		while (p->RTag == 1 && p->rchild != T)
		{
    
    
			p = p->rchild;
			cout << p->data;
		}
		p = p->rchild;
	}
}
//遍历中序线索二叉树
  • Traversing the post-order clue tree
    Traversing the post-order clue tree is a bit difficult. The original binary tree structure needs to be changed. We need to add a parent node for each node to solve the problem of not being able to access the parent node when traversing to the right subtree.
    code show as below:
	typedef struct BiTNode
	{
    
    
		char data;//数据域
		int LTag = 0;//左标签
		int RTag = 0;//右标签
		struct BiTNode* lchild = nullptr;//指针必须初始化,c11标准
		struct BiTNode* rchild = nullptr;//左右孩子
		struct BiTNode* parent = nullptr;//双亲
	}BiTNode, * BiTree;

With the above structure, it is much simpler to traverse the clue tree in subsequent order.
1. First of all, we should find the leftmost node p first, like the middle order traversal, and output the value of the node, if p->rchild == 1; p = p->rchild, the value of the output node, repeating, Until p->lchild == 0 and p->rchild == 0.
2. At this time p is the root node (relatively speaking), we need to continue traversing by the parent node and output the value of the node. Until we find the real root node p, then p = p->rchild.
3. Repeat steps 1 and 2 until the parent node of p is empty.
Demonstration diagram:
Insert picture description here
attach the code (not simple this time):

//后序遍历需要双亲节点
void PosTraverse_Thr(BiTree T)
{
    
    
	BiTree root = T->lchild;//初始节点
	BiTree prev = nullptr;//记录上一个节点
	while (root)
	{
    
    
		if (root->lchild == root->rchild)//如果双亲没有左子树或者右子树
		{
    
    
			root = root->rchild;
		}
		while (root->LTag == 0 && root->lchild != prev)//找到最左边的节点
		{
    
    
			root = root->lchild;
		}
		while (root->RTag == 1)//输出并遍历节点的后继
		{
    
    
			cout << root->data;
			prev = root;//记录上一个节点
			root = root->rchild;
		}
		if (root == T->lchild)//判断是不是根节点
		{
    
    
			cout << root->data;
			return;
		}
		while (root->rchild == prev)//不是根节点,访问当前节点的双亲节点
		{
    
    
			cout << root->data;
			prev = root;
			root = root->parent;
			if (root == nullptr)//遍历到根节点,退出
			{
    
    
				return;
			}
		}
		if (root->RTag == 0)//遍历右子树
		{
    
    
			root = root->rchild;
		}
	}
}
//遍历后序线索二叉树

Guess you like

Origin blog.csdn.net/m0_43456002/article/details/104268875