创建线索二叉树——中序线索二叉树的遍历(C++实现)

创建图示的二叉树,并将其线索化

先序遍历序列为:ABDGECF   

线索二叉树的链式结构描述如下:

typedef struct ThreadNode{
	char data;
	struct ThreadNode *lchild;
	struct ThreadNode *rchild;
	int ltag,rtag;//左右线索标志位
}ThreadNode,*ThreadTree;

 用先序遍历建立二叉树:

void creat_ThreadTree(ThreadTree &T){
	char data;
	cin>>data;
	if(data=='#'){
		T=NULL;return;
	}else{
	T=(ThreadNode *)malloc(sizeof(ThreadNode));
	T->data=data;
	T->lchild=NULL;
	T->rchild=NULL;
	T->ltag=0;
	T->rtag=0;
	creat_ThreadTree(T->lchild);
	creat_ThreadTree(T->rchild);
	}
}

线索化过程:

先定义一个全局变量pre指针,在访问到p节点时,pre指针指向中序遍历序列下p的前一个节点;

中序遍历每一个节点,边遍历边线索化,如果该节点的左(右)孩子指针为NULL,则将该指针指向节点的前驱(后继)节点,直到遍历结束。

值得注意的是,当找pre节点的后继节点p时,先要判断pre!=NULL。这点在代码中会有具体注释说明。

//中序线索化,对每个节点的处理
void visit(ThreadNode *q){
	if(q->lchild==NULL){//寻找前驱
	q->lchild=pre;
	q->ltag=1;//标志位为1,表示q节点的左指针指向的是前驱,而不是孩子
	}
	if(pre!=NULL&&pre->rchild==NULL){//这两个条件不能写反,因为在pre为NULL情况下访问它的右孩子,会导致程序崩溃
		pre->rchild=q;
		pre->rtag=1;
	}
	pre=q;

}
//对整棵树的所有节点做处理
void InThread(ThreadTree T){
	if(T!=NULL){

		InThread(T->lchild);
		visit(T);
		InThread(T->rchild);
	}
}
void creat_InThread(ThreadTree T){
	pre=NULL;
	if(T!=NULL){
		InThread(T);
		if(pre->rchild==NULL)
		pre->rtag=1;//最后一个节点要单独做处理,后继一定是NULL,标志为1
	}
}

中序线索二叉树的遍历:

中序线索二叉树的节点隐含了线索二叉树的前驱和后继信息。在中序线索二叉树中找节点后继规律是:若右标志位rtag==1,则右孩子指针指向的节点就是后继;否则,根据中序遍历"左 根 右"的特点,遍历右子树中第一个访问的节点(右子树中最左下的节点)为其后继。

//1.求中序线索二叉树中序下的第一个节点
ThreadNode *FirstNode(ThreadNode *p){
	while(p->ltag==0) p=p->lchild;
	return p;
}
//2.求节点p在中序序列下的后继
ThreadNode *NextNode(ThreadNode *p){
	if(p->rtag==0) return FirstNode(p->rchild);//p的右子树的左下角的元素就是它的后继
	else return p->rchild;
}

在中序线索二叉树中找节点后继规律是:若左标志位ltag ==1,则左孩子指针指向的节点就是前驱;否则,遍历左子树中最后一个被访问的节点(左子树最右下节点)为其前驱。

//3.找到中序线索二叉树中序遍历的最后一个节点
ThreadNode *LastNode(ThreadNode *p){
	while(p->rtag==0) p=p->rchild;
	return p;
}
//4.求节点p在中序遍历下的前驱
ThreadNode *PreNode(ThreadNode *p){
	if(p->ltag==0) return LastNode(p->lchild);//p的左子树右下角元素是它的前驱
	else return p->lchild;
}

根据找后继算法,可以从中序遍历的第一个节点开始,进行找后继遍历,这样可以顺序访问中序遍历下的每一个节点;

根据找前驱算法,可以从中序遍历的最后一个节点开始,进行找前驱遍历,这样可以逆序访问中序遍历下的每一个节点。


​​​​​​​

 

完整代码:


#include <cstdio>
#include <cstdlib>
#include<iostream>
#include <type_traits>
using namespace std;
typedef struct ThreadNode{
	char data;
	struct ThreadNode *lchild;
	struct ThreadNode *rchild;
	int ltag,rtag;//左右线索标志位
}ThreadNode,*ThreadTree;

ThreadNode *pre=NULL;//定义全局变量

//先建立一棵二叉树
void creat_ThreadTree(ThreadTree &T){
	char data;
	cin>>data;
	if(data=='#'){
		T=NULL;return;
	}else{
	T=(ThreadNode *)malloc(sizeof(ThreadNode));
	T->data=data;
	T->lchild=NULL;
	T->rchild=NULL;
	T->ltag=0;
	T->rtag=0;
	creat_ThreadTree(T->lchild);
	creat_ThreadTree(T->rchild);
	}
}
//中序线索化,对每个节点的处理
void visit(ThreadNode *q){
	if(q->lchild==NULL){//寻找前驱
	q->lchild=pre;
	q->ltag=1;//标志位为1,表示q节点的左指针指向的是前驱,而不是孩子
	}
	if(pre!=NULL&&pre->rchild==NULL){//这两个条件不能写反,因为在pre为NULL情况下访问它的右孩子,会导致程序崩溃
		pre->rchild=q;
		pre->rtag=1;
	}
	pre=q;

}
//对整棵树的所有节点做处理
void InThread(ThreadTree T){
	if(T!=NULL){

		InThread(T->lchild);
		visit(T);
		InThread(T->rchild);
	}
}
void creat_InThread(ThreadTree T){
	pre=NULL;
	if(T!=NULL){
		InThread(T);
		if(pre->rchild==NULL)
		pre->rtag=1;//最后一个节点要单独做处理,后继一定是NULL,标志为1
	}
}
//中序线索二叉树遍历
//1.求中序线索二叉树中序下的第一个节点
ThreadNode *FirstNode(ThreadNode *p){
	while(p->ltag==0) p=p->lchild;
	return p;
}
//2.求节点p在中序序列下的后继
ThreadNode *NextNode(ThreadNode *p){
	if(p->rtag==0) return FirstNode(p->rchild);//p的右子树的左下角的元素就是它的后继
	else return p->rchild;
}
void Outp(ThreadNode *i){
	cout<<i->data<<" ";

}
//利用上面1、2算法可以对中序线索二叉树进行遍历
void Inorder(ThreadNode *T){
	for(ThreadNode *i=FirstNode(T);i!=NULL;i=NextNode(i))
	Outp(i);
}
//3.找到中序线索二叉树中序遍历的最后一个节点
ThreadNode *LastNode(ThreadNode *p){
	while(p->rtag==0) p=p->rchild;
	return p;
}
//4.求节点p在中序遍历下的前驱
ThreadNode *PreNode(ThreadNode *p){
	if(p->ltag==0) return LastNode(p->lchild);//p的左子树右下角元素是它的前驱
	else return p->lchild;
}
//利用上面3、4算法可对中序线索二叉树进行逆向遍历
void RevInorder(ThreadNode *T){
	for(ThreadNode *i=LastNode(T);i!=NULL;i=PreNode(i))
	Outp(i);
}

int main(){
	ThreadTree T;
	creat_ThreadTree(T);

	creat_InThread(T);
	cout<<"中序顺序遍历结果:"<<endl;
	Inorder(T);
    puts("");
    cout<<"中序逆序遍历结果:"<<endl;
	RevInorder(T);
	return 0;
}

输出结果:

  • 4
    点赞
  • 29
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
二叉树的中序线索化是指在二叉树的每个节点中,增加两个指针ltag和rtag,分别表示该节点的左子树指针和右子树指针是指向其前驱或后继节点的线索,而不是指向子树。通过线索化,可以在不使用递归和栈的情况下,完成二叉树的中序遍历实现中序线索化的核心思路是在中序遍历的过程中,记录前驱节点和后继节点,并将其指针修改为指向对应的节点。下面是一个简单的C++代码实现: ```C++ #include<iostream> using namespace std; struct TreeNode { int val; TreeNode* left; TreeNode* right; bool ltag; bool rtag; TreeNode(int x) : val(x), left(NULL), right(NULL), ltag(false), rtag(false) {} }; // 中序线索化 void InThread(TreeNode* root, TreeNode*& pre) { if (!root) return; InThread(root->left, pre); if (!root->left) { root->left = pre; root->ltag = true; } if (pre && !pre->right) { pre->right = root; pre->rtag = true; } pre = root; InThread(root->right, pre); } // 中序遍历 void InOrder(TreeNode* root) { if (!root) return; TreeNode* p = root; while (p->left) p = p->left; while (p) { cout << p->val << " "; if (p->rtag) p = p->right; else p = p->right->left; } } int main() { TreeNode* root = new TreeNode(1); root->left = new TreeNode(2); root->right = new TreeNode(3); root->left->left = new TreeNode(4); root->left->right = new TreeNode(5); root->right->left = new TreeNode(6); root->right->right = new TreeNode(7); TreeNode* pre = NULL; InThread(root, pre); InOrder(root); return 0; } ``` 在这个例子中,我们定义了一个结构体`TreeNode`来表示二叉树的节点。其中,`ltag`和`rtag`分别表示该节点的左子树指针和右子树指针是否是线索。在中序线索化的过程中,我们使用一个指针`pre`来记录前驱节点,以便修改指针的指向。在中序遍历时,我们从根节点开始,找到最左侧的节点,然后按照线索指针依次遍历每个节点,直到遍历完整棵树。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值