【C++数据结构】应用类模板技术实现二叉线索树的构造、中序线索化与求后继、前驱、父结点

实现线索二叉树类及若干应用算法

实现内容

1.根据带空指针的先序序列构造二叉树

2.中序线索化

3.求后继结点和前驱结点

4.求父结点

实现过程

以下图二叉树为例,

带空指针的形式abd**e**cf***:

构造二叉树:

 

中序线索化:

遍历每个结点,若左孩子域不空,保持左孩子和左指针域不变,否则将左孩子置为前驱结点的指针,左标记域置为THREAD;若右孩子域不空,保持右孩子和右标机域不变,否则将右孩子置为后继结点的指针,右标记域置为THREAD。

    

BiThrTree.h:

#pragma once
#include<iostream>
#include<vector>
using namespace std;
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;
	BiThrNode<T>* prenode = NULL;
	BiThrNode<T>* CreateByPre(vector<T>&, int&);
	void InThreaded(BiThrNode<T>* p);
public:
	InBiThrTree() {
		root = NULL;
	}
	InBiThrTree(vector<T>& pre);   //根据先序序列创建
	~InBiThrTree(){}
	void InThreaded();             //中序线索化
	void travese();                //利用线索进行中序遍历
	BiThrNode<T>* GetNext(BiThrNode<T>* p);//求中序遍历中的后继结点
	BiThrNode<T>* GetPrev(BiThrNode<T>* p);//求中序遍历中的前驱结点
	BiThrNode<T>* SearchParent(T data) {   //查找父结点
		BiThrNode<T>* p = root;
		while (p->ltype == LINK)
			p = p->lchild;
		while (p) {
			if (p->data == data)
				return p;
			p = GetNext(p);
			if (p == NULL)
				break;
		}
	}
	BiThrNode<T>* GetParent(T data);     //求父结点地址
};

 BiThrTree.cpp

先序构造

使用数组记录先序序列,传入构造函数,通过递归构建二叉树

//先序构造
template<class T>
InBiThrTree<T>::InBiThrTree(vector<T>& pre) { //构造函数
	int i = 0;
	root = CreateByPre(pre, i);
}

template<class T>
BiThrNode<T>* InBiThrTree<T>::CreateByPre(vector<T>& pre, int& i)
{
	if (i >= pre.size())
		return NULL;
	T e = pre[i++];
	if (e == '*') {
		return NULL;
	}
	BiThrNode<T>* p = new BiThrNode<T>;
	p->ltype = p->rtype = LINK; //左右结点都是指针
	p->data = e;
	p->lchild = CreateByPre(pre, i); //创建左子树
	p->rchild = CreateByPre(pre, i); //创建右子树
	return p;
}
 中序线索化

因为中序遍历是左-根-右的顺序,所以左子树要有一个线索指向根结点,实现左-根的遍历。根-右,要由根结点root到右子树的最左边的结点left,以使右子树的遍历顺序符合左-根-右,所以需要left存储指向root的线索。

所以对于左孩子域,如果为空,将其指向上一个结点prenode。

对于右孩子域,如果为空,指向下一个结点,需要将该结点存为prenode,等到遍历到下一个结点时将该结点的左孩子域设为线索指向prenode

template<class T>
inline void InBiThrTree<T>::InThreaded()
{
	InThreaded(root);
}
template<class T>
inline void InBiThrTree<T>::InThreaded(BiThrNode<T>* p)
{
	if (p == NULL)
		return;
	InThreaded(p->lchild);
	if (p->lchild == NULL) {  //如果左孩子域是空,设为线索,指向上一个结点
		p->ltype = THREAD;
		p->lchild = prenode;
	}
	if (p->rchild == NULL) {  //如果右孩子域是空,设为线索
		p->rtype = THREAD;
	}
	if (prenode != NULL) {
		if (prenode->rtype == THREAD)
			prenode->rchild = p;
	}
	prenode = p;
	InThreaded(p->rchild);
}
后继、前驱

根据线索求得后继结点:如果右孩子域是线索,说明该结点的下一个结点就是线索指向的结点,所以将右孩子返回即可。如果是指针,说明它的下一个结点是右孩子的最左边的结点,我们转到右孩子结点,一直往左查询,直到左孩子域不是指针而是线索,即得最左边的结点,也就是要求的后继结点。

前驱结点:与后继类似,由于左孩子域的线索指向的是前驱结点,右孩子域的线索指向的是后继,所以求前驱结点的代码左右孩子域对调了位置。

//后继
template<class T>
BiThrNode<T>* InBiThrTree<T>::GetNext(BiThrNode<T>* p)
{
	if (p->rtype == THREAD)
		return p->rchild;
	p = p->rchild;
	while (p && p->ltype == LINK && p->lchild != NULL)
		p = p->lchild;
	return p;
}
//前驱
template<class T>
inline BiThrNode<T>* InBiThrTree<T>::GetPrev(BiThrNode<T>* p)
{
	if (p->ltype == THREAD)
		return p->lchild;
	p = p->lchild;
	while (p->rtype == LINK && p->rchild != NULL)
		p = p->rchild;
	return p;
}
求父结点
//求父结点
template<class T>
BiThrNode<T>* InBiThrTree<T>::GetParent(T data)
{
	BiThrNode<T>* p = SearchParent(data);
	if (p == NULL)
		return NULL;
	BiThrNode<T>* parent = new BiThrNode<T>;
	parent = p;
	while (parent->rtype == LINK)
		parent = parent->rchild;
	parent = parent->rchild;

	if (parent && parent->lchild == p)
		return parent;

	parent = p;
	while (parent->ltype == LINK)
		parent = parent->lchild;
	parent = parent->lchild;
	return parent;
}
 遍历
//遍历
template<class T>
void InBiThrTree<T>::travese()
{
	BiThrNode<T>* p = root;
	while (p->ltype == LINK && p->lchild != NULL) {
		p = p->lchild;
	}
	while (p) {
		cout << p->data << " ";
		p = GetNext(p);
		if (p == NULL)
			break;
	}
}

main.cpp

#include"BiThrTree.h"
int main() {
	vector<char> a = { 'a', 'b', 'd', '*', '*', 'e', '*', '*', 'c', 'f', '*', '*', '*' };
	InBiThrTree<char> tree(a);
	tree.InThreaded();
	cout << "中序遍历:";
	tree.travese();
	char c;
	cout << "\n寻找()的父结点:";
	cin >> c;
	BiThrNode<char>* parent = tree.GetParent(c);
	if (parent == NULL)
      cout << "该结点不存在父结点";
    else
      cout << "parent.data=" << parent->data;
	return 0;
}

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值