【数据结构】线索二叉树的实现

线索二叉树存储结构

结点定义

在这里插入图片描述

使用枚举类型表示结点的类型LINKTHREAD

enum BiThrNodeType{LINK,THREAD};
template<class T>
struct BiThrNode
{
	BiThrNodeType ltype, rtype;
	T data;
	BiThrNode<T>* lchild,* rchild;
};

线索二叉树类模板

template<class T>
class InBiThrTree
{
	BiThrNode<T>* root;
public:
	BiThrNode<T>* GetRoot() { return root; }
	BiThrNode<T>* CreateByPre(vector<T>& pre, int& i);
	InBiThrTree() { root = nullptr; }
	InBiThrTree(vector<T>& pre);
	void InThreaded(BiThrNode<T>* p);
	void InThreaded();
	BiThrNode<T>* GetNext(BiThrNode<T>* p);//求中序遍历中的后继节点
	BiThrNode<T>* GetPrev(BiThrNode<T>* p);//求中序遍历中的前驱节点
	void traverse();//利用线索进行中序遍历
	BiThrNode<T>* GetParent(BiThrNode<T>*p);//求父节点地址
};

先序序列构造函数

*表示nullptr,先序序列使用 “中左右” 的顺序构造二叉树

  • 先构造当前结点
  • 再遍历构造左子树
  • 再遍历构造右子树

注意参数i传的是引用,在某种程度上起到了 “返回 i ” 的效果。
初始将ltypertype都设为LINK

template<class T>
BiThrNode<T>* InBiThrTree<T>::CreateByPre(vector<T>& pre, int& i)
{
	T e = pre[i++];
	if (e == '*')return nullptr;
	BiThrNode<T>* p = new BiThrNode<T>;
	p->data = e;
	p->ltype = LINK;
	p->rtype = LINK;
	p->lchild=CreateByPre(pre, i);
	p->rchild = CreateByPre(pre, i);
	return p;
}
template<class T>
InBiThrTree<T>::InBiThrTree(vector<T>& pre)
{
	int i = 0;
	root = CreateByPre(pre, i);
}

当输入

	string str = "ABH**FD***E*CK**G**";
	vector<char> pre(str.begin(), str.end());
	InBiThrTree<char> tree(pre);

构建二叉树如下:
在这里插入图片描述

中序线索化函数

根据遍历次序,逐个检查每个结点。
若结点的左孩子为空,则将结点的左孩子设为前驱指针,左标记域设为THREAD
若结点的右孩子为空,则将结点的右孩子设为后继指针,右标记域设为THREAD
在代码的具体实现上,声明一个全局变量pre来记录序列中上一个指针。
伪代码如下:
在这里插入图片描述

template<class T>
BiThrNode<T>* prenode;
template<class T>
void InBiThrTree<T>::InThreaded(BiThrNode<T>* p)
{
	if (p == nullptr)return;
	InThreaded(p->lchild);
	if (p->lchild == nullptr) {
		p->ltype = THREAD;
		p->lchild = prenode<T>;
	}
	if (p->rchild == nullptr) {
		p->rtype = THREAD;
	}
	if (prenode<T>) {
		if (prenode<T>->rtype == THREAD)
			prenode<T>->rchild = p;
	}
	prenode<T> = p;
	InThreaded(p->rchild);
}
template<class T>
void InBiThrTree<T>::InThreaded()
{
	BiThrNode<T>* prenode = root;
	InThreaded(root);
}

中序线索化后的二叉数结构如下:
在这里插入图片描述

查找中序序列前驱和后继结点

查找后继结点

根据中序“左中右”顺序:

  • 如果p的右标记为THREAD,则p的右孩子就是后继节点。
  • 如果p的右标记为LINK,则p的后继节点就是右孩子的最左孩子。
    在这里插入图片描述
template<class T>
BiThrNode<T>* InBiThrTree<T>::GetNext(BiThrNode<T>* p)
{
	if (p->rtype == THREAD)
		return p->rchild;
	p = p->rchild;               //右孩子的最左孩子
	while (p->ltype == LINK)
		p = p->lchild;
	return p;
}

查找前驱结点

同理,根据中序“左中右”顺序:

  • 如果p的左标记为THREAD,则p的左孩子就是前驱节点。
  • 如果p的左标记为LINK,则p的前驱节点就是左孩子的最右孩子。
template<class T>
BiThrNode<T>* InBiThrTree<T>::GetPrev(BiThrNode<T>* p)
{
	if (p->ltype == THREAD)
		return p->lchild;
	p = p->lchild;             //左孩子的最右孩子
	while (p->rtype == LINK)
		p = p->rchild;
	return p;
}

中序遍历

通过不断p=p->lchild,找到中序序列的起点。
调用GectNext()函数查找当前结点的后继结点,输出,实现中序遍历。

template<class T>
void InBiThrTree<T>::traverse()
{
	BiThrNode<T>* p = root;
	while (p->ltype == LINK)
		p = p->lchild;        //找到中序遍历的起点
	while (p) {
		cout << p->data << " ";
		p = GetNext(p);
	}
	cout << endl;
}

查找父结点

根据中序“左中右”顺序:

  • 如果*p*parent的左孩子,则*p的最右下方节点的后继结点一定是*p的父结点。
  • 如果*p*parent的右孩子,则*p的最左下方节点的前驱结点一定是*p的父结点。
    在这里插入图片描述
template<class T>
BiThrNode<T>* InBiThrTree<T>::GetParent(BiThrNode<T>* p)
{
	if (p == nullptr)
		return nullptr;
	BiThrNode<T>* parent = p;
	while (parent->rtype == LINK) {
		parent = parent->rchild;
	}
	parent = parent->rchild;//*p最右下方节点的后继指针
	if (parent && parent->lchild == p)
		return parent;

	parent = p;
	while (parent->ltype == LINK) {
		parent = parent->lchild;
	}
	parent = parent->lchild;//*p最左下方节点的前驱指针
	return parent;
}

测试

int main()
{
	string str = "ABH**FD***E*CK**G**";
	vector<char> pre(str.begin(), str.end());
	InBiThrTree<char> tree(pre);
	tree.InThreaded();
	tree.traverse();

	cout << "Get next node of B: " << tree.GetNext(tree.GetRoot()->lchild)->data << endl;
	cout << "Get next node of K: " << tree.GetNext(tree.GetRoot()->rchild->rchild->lchild)->data << endl;

	cout << "Get previous node of 'E': " << tree.GetPrev(tree.GetRoot()->rchild)->data << endl;
	cout << "Get previous node of 'C': " << tree.GetPrev(tree.GetRoot()->rchild->rchild)->data << endl;


	cout << "Parent of B: " << tree.GetParent(tree.GetRoot()->lchild)->data << endl;
	cout << "Parent of C: " << tree.GetParent(tree.GetRoot()->rchild->rchild)->data << endl;
}

在这里插入图片描述

在这里插入图片描述

  • 2
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值