C++线索二叉树的相关操作

 

C++线索二叉树的相关操作

#pragma once
//5.21 --212--线索二叉树的类定义
template<class T>
struct ThreadNode
{
	int ltag, rtag;
	ThreadNode<T>* leftChild, * righChild;
	T data;
	ThreadNode(const T item) :data(item), leftChild(nullptr), righChild(nullptr),
		ltag(0), rtag(0) {}

};
template<class T>
class ThreadTree {
protected:
	ThreadNode<T>* root;
	void createInThread(ThreadNode<T>* current, ThreadNode<T>*& pre);
	//中序遍历建立二叉树
	ThreadNode<T>* parent(ThreadNode<T>* t);
	//寻找结点t的父结点
public:
	ThreadTree() :root(nullptr) {}
	void createInThread();
	ThreadNode<T>* First(ThreadNode<T>* current);//寻找第一个结点
	ThreadNode<T>* Last(ThreadNode<T>* current);//寻找最后一个结点
	ThreadNode<T>* Next(ThreadNode<T>* current);//寻找  后继结点
	ThreadNode<T>* Prior(ThreadNode<T>* current);//寻找  前驱结点
	void InOrder(void (*visit)(ThreadNode<T>* p));
	void PreOrder(void (*visit)(ThreadNode<T>* p));
	void PostOrder(void (*visit)(ThreadNode<T>* p));
	
	void InsertRight(ThreadNode<T>* current);//插入一个结点

	//........
};
//5.22 --213-中序二叉树 成员函数实现
//求序列的 第一个结点
template<class T>
ThreadNode<T>* ThreadTree<T>::First(ThreadNode<T>* current) {
	//以*current為根的 第一个结点
	ThreadNode<T>* p = current;
	while (p->ltag == 0) {//只要有 左子女,就一直向左
		p = p->leftChild;//最左下结点,(不一定是叶子结点)
	}
	//最左边的就是 中序遍历的第一个结点。
	return p;
};
//求后继
template<class T>
ThreadNode<T>* ThreadTree<T>::Next(ThreadNode<T>* current) {
	ThreadNode<T>* p = current->righChild;
	if (current->rtag == 0) {//该点 A有 右子女,
		return First(p);//求该点的右子女为根的子树的 第一个结点就是E
	}else{//否则就是 rtag==1.存放的就是后继结点。
		return p;//返回后继结点
	}
};
//序列的最后一个结点
template<class T>
ThreadNode<T>* ThreadTree<T>::Last(ThreadNode<T>* current) {
	ThreadNode<T>* p = current;
	while (p->rtag == 0) {//只要有右子女,就一直向右。
		p = p->righChild;
	}
	return p;
};
//求 前驱结点。
template<class T>
ThreadNode<T>* ThreadTree<T>::Prior(ThreadNode<T>* current) {
	ThreadNode<T>* p = current->leftChild;//先记录改点的左子女,
	if (current->ltag == 0) {//如果 有左 子女,比如A,
		return Last(p);//求以 该点 左子女为根的子树(比如B) 的最右一个结点。
	}
	else {//否则就是rtag==1,存放的就是 前驱结点
		return p;
	}
};
//5.23进行中序遍历
template<class T>
void ThreadTree<T>::InOrder(void (*visit)(ThreadNode<T>* p)) {
	ThreadNode<T>* p;
	for (p = First(root);p != nullptr;p = Next(p)) {
		visit(p);
	}
};
//5.24利用中序遍历 对二叉树进行中序线索化
template<class T>
void ThreadTree<T>::createInThread() {
	ThreadNode<T>* pre = nullptr;//前驱结点指针
	if (root != nullptr) {//非空二叉树,进行线索化
		createInThread(root, pre);//中序遍历 线索化
		pre->righChild = nullptr;//后 处理中序最后一个结点指针。(最后一个是特殊的)
		pre->rtag = 1;
	}
};
template<class T>
void ThreadTree<T>::createInThread(ThreadNode<T>* current,
	ThreadNode<T>*& pre) {
	//通过中序遍历,对二叉树进行线索化
	if (current == nullptr) {
		return;
	}
	createInThread(current->leftChild, pre);//递归,左子树线索化
	if (current->leftChild == nullptr) {//建立当前结点的前驱
		current->leftChild = pre;
		current->ltag = 1;
	}
	if (pre != nullptr && pre->righChild == nullptr) {
		pre->righChild = current;//建立当前结点的后继
		pre->rtag = 1;
	}
	pre = current;
	createInThread(current->righChild, pre);//递归,右子树线索化
};

//5.25 在中序遍历二叉树上实现前序遍历算法
template<class T>
void ThreadTree<T>::PreOrder(void (*visit)(ThreadNode<T>* current)) {
	ThreadNode<T>* current = root;
	while (current != null) {
		visit(current);//访问根结点
		if (current->ltag == 0) {//如果有 左子女.即为 后继
			current = current->leftChild;
		}
		else if (current->rtag == 0) {//否则 有 右子女,即为后继
			current = current->righChild;
		}
		else {
			//沿着后继继续检测
			while (current != nullptr && current->rtag == 1) {
				current = current->righChild;//直到有 右子女的结点
			}
			if (current != nullptr) {//右 子女 即为后继
				current = current->righChild;
			}
		}
	}
};
//5.26 在中序遍历二叉树上实现后序遍历算法
template<class T>
void ThreadTree<T>::PostOrder(void (*visit)(ThreadNode<T>* current)) {
	ThreadNode<T>* current = root;
	//寻找最后一个结点
	while (current->ltag == 0 || current->rtag == 0) {
		if (current->ltag == 0) {
			current = current->leftChild;
		}
		else if (current->rtag == 0) {
			current = current->righChild;
		}
	}
	visit(current);//访问第一个结点
	ThreadNode<T>* p;
	while ((p = parent(t)) != nullptr) {
		if (p->righChild == current || p->rtag == 1) {//*current是*p的后序后继
			current = p;
		}else{//否则,current 移动到 p的右子树
			current = p->righChild;
			while (current->ltag == 0 || current->rtag == 0) {
				if (current->ltag == 0) {
					current = current->leftChild;
				}
				else if (current->rtag == 0) {
					current = current->righChild;
				}
			}
		}
		visit(current);
	}
};
//5.27 求父结点
template<class T>
ThreadNode<T>* ThreadTree<T>::parent(ThreadNode<T>* t) {
	ThreadNode<T>* p;
	if (t == root)return nullptr;//根结点 无父结点
	for (p = t;p->ltag == 0;p = p->leftChild);//求 t为根子树第一个结点。
	if (p->leftChild != nullptr)
		for (p = p->leftChild;
			p != nullptr && p->leftChild != t && p->righChild != t;
			p = p->righChild);
	if (p == nullptr || p->leftChild == nullptr) {
		for (p = t;p->rtag == 0;p = p->righChild);
		for (p = p->righChild;p != nullptr && p->leftChild != t && p->righChild != t;
			p = p->leftChild);
	}
	return p;
};
//5.28
template<class T>
void ThreadTree<T>::InsertRight(ThreadNode<T>* s, ThreadNode<T>* r) {
	//将新结点*r当做*s的 右子女插入
	r->rightChild = s->rightChild;//s的右子女或者后继 线索 传给r
	r->rtag = s->rtag;//后继线索 标志一同传送
	t->leftChild = s;
	r->ltag = 1;
	s->rightChild = r;//r成为s右子女
	s->rtag = 0;
	if (r->rtag == 0) {//s原来有右子女
		ThreadNode<T>* temp;
		temp = First(r->rightChild);//在s原来的柚子树找中序遍历 第一个点
		temp->leftChild = r;//建立指向r的前驱线索
	}

};
//在*s的左子女处插入 *p
template<class T>

void ThreadTree<T>::InsertRight(ThreadNode<T>* s, ThreadNode<T>* p) {

	if (s != nullptr && p != nullptr) {
		if (s->rtag) {//首先判断 是否有子女。  无!
			p->leftChild = s->leftChild;//s的左线索 复制给 p
			p->rtag = 1;      //p无右子女
		}
		else {//有左子女
			p->leftChild = s->leftChild;
			p->ltag = 0;//插入
			p->rightChild = s;//p的后继 是s
			p->rtag = 1;//p无右子女

			ThreadNode<T>* temp = p->leftChild;
			while (!temp->rtag) {//找p左子树 中序遍历中的最后一个点。
				temp = temp->rightChild;
			}
			temp->rightChild = p;//该点的后继 是 p

		}
		s->leftChild = p;
		s->ltag = 0;
	}
};

 

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

Roam-G

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

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

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

打赏作者

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

抵扣说明:

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

余额充值