C++ 用土办法找到二叉树中序遍历序列前驱和后继

37 篇文章 6 订阅
27 篇文章 4 订阅

问题思考:如果不用三叉树,而用指针怎么找到中序遍历序列的前驱和后继呢?

思路:从根结点出发,重新进行一次中序遍历,指针q记录当前访问的结点,指针pre记录上一个被访问结点,指针pre记录上一个被访问的结点。

①如何找到指定结点p在 q 中序遍历序列中的前驱?

②如何找到p的中序后继?

①如何找到指定结点 p
中序遍历序列中的前驱?

(1)寻找中序前驱

//中序遍历寻找前驱 
void BiTree::BInorder(BiNode *bt){
	if(bt!=nullptr){
		BInorder(bt->lchild);//递归遍历左子树
		Bvisit(bt);//访问根结点
		BInorder(bt->rchild);//递归遍历右子树 
	}
} 
//访问,可以得到中序前驱 
void BiTree::Bvisit(BiNode *q){
	if( q->data == p->data)//当前访问结点刚好是结点p 
		final1= pre;//找到p的前驱
	else
		pre = q;//pre指向当前访问的结点 
} 

(2)寻找中序后继

//中序遍历寻找后继
void BiTree::AInorder(BiNode *bt){
	if(bt!=nullptr){
		AInorder(bt->lchild);//递归遍历左子树
		Avisit(bt);//访问根结点
		AInorder(bt->rchild);//递归遍历右子树 
	}
}
//访问,可以得到中序后继
void BiTree::Avisit(BiNode *q){
	if(flag == 1 && pre!=nullptr && pre->data == p->data){//当前访问结点刚好是结点p 
		final2= q;//找到p的后继
		flag = 0;
	}
	else
		pre = q;//pre指向当前访问的结点 
}

C++完整代码:

//用土办法找到中序前驱
#include<iostream>
using namespace std;
typedef char DataType;
struct BiNode
{
	DataType data;
	BiNode *lchild,*rchild;
};
BiNode *p=new BiNode; //记录目标节点
BiNode *pre = nullptr;//指向当前访问结点的前驱
BiNode *final1= nullptr;//用于记录最终结果 
BiNode *final2= nullptr;//用于记录最终结果 
class BiTree
{
	public:
		BiTree(){root=Create(root);}//构造函数,建立一颗二叉树
		~BiTree(){Release(root);}//析构函数,释放各个节点的存储空间
		void Inorder(){Inorder(root);}//中序遍历二叉树
		void BInorder(){BInorder(root);}//中序遍历寻找前驱二叉树
		void AInorder(){AInorder(root);}//中序遍历寻找后继二叉树
		void Bvisit(BiNode *q);//访问,可以得到中序前驱 
		void Avisit(BiNode *q);//访问,可以得到中序后继
	private:
		BiNode *root;//指向根节点的头指针
		BiNode *Create(BiNode *bt);//构造函数调用
		int flag=1;
		void Release(BiNode *bt);
		void Inorder(BiNode *bt);//中序遍历函数调用
		void BInorder(BiNode *bt);//中序遍历寻找前驱函数调用
		void AInorder(BiNode *bt); //中序遍历寻找后继函数调用
};
//创建二叉树 
BiNode *BiTree::Create(BiNode *bt)
{
	static int i=0;
	char ch;
	string str="AB#D##C##";
	ch=str[i++];
	if(ch=='#')bt=nullptr;//建立一棵空树 
	else {
		bt=new BiNode;bt->data=ch;//生成一个结点,数据域为ch
		bt->lchild=Create(bt->lchild);//递归建立左子树
		bt->rchild=Create(bt->rchild);//递归建立右子树
	}
	return bt;
}
//销毁二叉树 
void BiTree::Release(BiNode *bt)
{
	if(bt!=nullptr){
		Release(bt->lchild);
		Release(bt->rchild);
		delete bt;
	}
}
//中序遍历
void BiTree::Inorder(BiNode *bt)
{
	if(bt==nullptr)return;//递归调用的结束条件
	else{
		Inorder(bt->lchild);//中序递归遍历bt的左子树
		cout<<bt->data<<" ";//访问根节点的数据域
		Inorder(bt->rchild);//中序递归遍历bt的右子树
	}
}
//中序遍历寻找前驱 
void BiTree::BInorder(BiNode *bt){
	if(bt!=nullptr){
		BInorder(bt->lchild);//递归遍历左子树
		Bvisit(bt);//访问根结点
		BInorder(bt->rchild);//递归遍历右子树 
	}
} 
//中序遍历寻找后继
void BiTree::AInorder(BiNode *bt){
	if(bt!=nullptr){
		AInorder(bt->lchild);//递归遍历左子树
		Avisit(bt);//访问根结点
		AInorder(bt->rchild);//递归遍历右子树 
	}
}
//访问,可以得到中序前驱 
void BiTree::Bvisit(BiNode *q){
	if( q->data == p->data)//当前访问结点刚好是结点p 
		final1= pre;//找到p的前驱
	else
		pre = q;//pre指向当前访问的结点 
} 
//访问,可以得到中序后继
void BiTree::Avisit(BiNode *q){
	if(flag == 1 && pre!=nullptr && pre->data == p->data){//当前访问结点刚好是结点p 
		final2= q;//找到p的后继
		flag = 0;
	}
	else
		pre = q;//pre指向当前访问的结点 
}
int main(){
	p->data ='D';//p指向目标结点
	cout<<"创建一棵二叉树"<<endl;
	BiTree T{};//创建一颗二叉树
	cout<<"---中序遍历---"<<endl;//B D A C
	T.Inorder();
	cout<<endl;
	T.BInorder();
	if (final1 != nullptr)
        cout<<"结点"<<p->data<<"中序前驱"<<"  "<<final1->data<<endl;
    else
        cout<<"结点"<<p->data<<"无前驱"<<endl;
	T.AInorder();
	if (final2 != nullptr)
        cout<<"结点"<<p->data<<"中序后继"<<"  "<<final2->data<<endl;
    else
        cout<<"结点"<<p->data<<"无后继"<<endl;
	return 0;
}
 

实验结果图:

 

我是热爱学习的呵呵哒~如果你觉得文章很棒,对你有帮助的话,可以点赞+收藏+加关注喔~

如果文章有不正确的地方,欢迎交流指正,我将虚心请教~o(>ω<)o

我会定期更新文章,继续为您提供优质文章~o(>ω<)o

二叉树的中序线索化是指在二叉树的每个节点中,增加两个指针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`来记录前驱节点,以便修改指针的指向。在中序遍历时,我们从根节点开始,找到最左侧的节点,然后按照线索指针依次遍历每个节点,直到遍历完整棵树。
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

呵呵哒( ̄▽ ̄)"

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值