23王道——建立中序线索树,找前驱后继,并用其遍历

早上突然发现,我前天写的这个建立线索树并遍历的代码忘了发,今天补上,正好复盘一下

建立中序线索树

附设指针pre,p
p遍历完之后,pre=p,也就是pre是遍历结点p的前驱,p是pre的后继

如果p的左孩子为空,那么p-lchild=pre
如果pre的右孩子为空,&&pre!=NULL,pre->rchild=p

中序的前驱,

如果ltag=1,左孩子就是前驱
如果ltag=0,左孩子的最右下结点

中序的后继,

如果rtag=1,右孩子就是后继
如果rtag=0,右孩子的最左下结点

还要注意,前序遍历的前驱和后序遍历的后继借助二叉树是无法找到的
只能借用三叉链表,找到他的父节点,才有可能实现

中序借助线索遍历

建立循环,p不空,那么p就一直等于p的后继就可以实现
因为在上面,我们已经总结了后继的不同情况,可以写一个函数来实现
就在循环中调用函数就行了

我们还可以利用前驱,来实现中序的倒序遍历

#include<iostream>
using namespace std;


typedef struct Treenode {
	int data;
	struct Treenode* lchild, * rchild;
	int ltag, rtag;
}Treenode, * Tree;

Treenode* pre = NULL;

//变遍历,边建立线索二叉树
void visit(Tree T) {
	if (T->lchild == NULL) {
		T->ltag = 1;
		T->lchild = pre;//第一个左孩子为空,前驱为null
	}
	if (pre != NULL && pre->rchild == NULL) {
		pre->rchild = T;//后继,就让pre的→指向p
		pre->rtag = 1;
	}
	pre = T;//保持在T的后面
	//只需考虑每次的visit,结点关系
	//最后一个结点需要有孩子指向NULL
}

//中序线索化
void mid_order_(Tree& T) {
	if (T != NULL) {
		mid_order_(T->lchild);
		visit(T);
		mid_order_(T->rchild);
	}
}

//中序线索化
void mid_order_build(Tree& T) {
	if (T != NULL) {
		mid_order_(T);

		pre->rchild = NULL;//处理最后一个结点
		pre->rtag = 1;
		/*if (pre->lchild == NULL)
			pre->rtag = 1;*/
			//我觉得和这个是一个效果
	}
}

//树的初始化
void InitTree(Tree &T) {
	T = NULL;
}

//树的建立,递归建立,输入需要注意
//1 2 4 0 0 0 3 0 5 0 0 
void buildTree(Tree& T) {
	T = new Treenode;
	int x;
	cin >> x;
	if (x == 0)
		T = NULL;
	else {
		T->data = x;
		T->ltag = T->rtag = 0;
		buildTree(T->lchild);
		buildTree(T->rchild);
	}
}

//中序递归遍历
void midorder_circual(Tree T) {
	if (T != NULL) {
		midorder_circual(T->lchild);
		cout << T->data << " ";
		midorder_circual(T->rchild);
	}
}

//返回一个树的最左下结点
Treenode* left_low(Tree T) {
	Treenode* s = T;
	while (s->ltag ==0) {
		//这里lchild不能作为判断标志,因为线索二叉树的任何一个结点lchild都不为NULL
		//必须用ltag来判断
		s = s->lchild;
	}
	return s;
}

//返回树的最右下结点
Treenode* right_low(Tree T) {
	Treenode* s = T;
	while (s->rtag == 0)
		s = s->rchild;
	return s;
}

//中序的后继
Treenode * node_behind(Tree T) {
	Treenode* p = T;
	if (p->rtag == 1)
		return p->rchild;//后继为右孩子结点
	else {//为右子树的最左下结点
		return left_low(p->rchild);
	}
}

//中序的前驱
Treenode* node_pre(Tree T) {
	Treenode* p = T;
	if (p->ltag == 1)
		return p->lchild;
	else {//
		return right_low(p->lchild);
	}
}

//中序线索树的遍历
void visit_midorder_(Tree T) {
	Treenode* p;
	for (p=left_low(T);p != NULL; p = node_behind(p))
		cout << p->data << " ";
}

//中序线索树的倒序遍历
void visit_midorder_dao(Tree T) {
	Treenode* p = T;
	for (p = right_low(T); p != NULL; p = node_pre(p))
		cout << p->data << " ";
}

int main() {
	Tree T;
	InitTree(T);
	buildTree(T);
	midorder_circual(T);//中序递归遍历
	cout << endl;
	mid_order_build(T);//中序线索化
	visit_midorder_(T);//中序线索树的遍历,利用后继遍历
	cout << endl;
	visit_midorder_dao(T);//中序线索树的倒序遍历
	return 0;
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值