一、简介
线索二叉树是在二叉树的基础上,把空指针加以利用,通过左右type域来标记类型。生成方法是先构造二叉树,再把二叉树线索化,线索化的过程稍候会介绍。
二、线索二叉树的节点构造
先贴代码:1
2
3
4
5
6
7
8
9enum BiThrNodeType{LINK,THREAD};
template<class T>
struct BiThrNode
{
	BiThrNodeType ltype, rtype;
	T data;
	BiThrNode<T> *lchild, *rchild;
};
明显,与二叉树相比,只是多了两个枚举类型的数据成员,通俗的解释,
- LINK标志表示接下来的是他的孩子,
- THREAD表示接下来的前驱或者后继。
同时贴上InBiThrTree的头文件,里面的函数,会在下面介绍。1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24template<class T>
class InBiThrTree
{
private:
	BiThrNode<T> *root;//根节点
	BiThrNode<T> *prenode;//前置点
	void InThreaded(BiThrNode<T> *&p);
	BiThrNode<T> *CreateByPre(vector<T> &pre, int &i);
public:
	InBiThrTree(){ root = NULL; }
	InBiThrTree(vector<T> &pre);				//根据先序序列创建二叉树
	void InThreaded();							//中序线索化
	//~InBiThrTree();								//析构函数
	BiThrNode<T> *GetNext(BiThrNode<T> *p);		//求中序遍历中的后继结点
	BiThrNode<T> *GetPrev(BiThrNode<T> *p);		//求中序遍历中的前驱结点
	void Travese();								//利用线索进行中序遍历
	BiThrNode<T>* GetParent(BiThrNode<T> *p);	//求父结点地址
	BiThrNode<T>* GetRoot(){ return root; }		//求根结点
	BiThrNode<T>* Search(T e);			//根据值e查找结点1
	BiThrNode<T>* Search(BiThrNode<T> *p,T e); //在以p为根的树查找1
	void setPre(){prenode=NULL;}		//置空前置点		
};
三、函数介绍
3.1、根据先序序列创建二叉树
说明一下,这一块和前面的树基本没有差异,只是在其中多了个对枚举类型的置空,即默认所有标志位均为孩子位。1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21//根据先序序列创建二叉树
template<class T>
InBiThrTree<T>::InBiThrTree(vector<T> &pre)
{
	int i = 0;		//向量pre的下标变量
	root = CreateByPre(pre, i);
}
template<class T>
BiThrNode<T> *InBiThrTree<T>::CreateByPre(vector<T> &pre, int &i)
{
	T e = pre[i]; i++;//提取当前数据
	if (e == '*')
		return NULL;//若是特殊数据,返回空指针
	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;
}
3.2, 二叉树的线索化
| 1 | //二叉树的中序线索化算法 | 
这边是比较关键的算法,书上是这么说的
- 如果二叉链表p为空,则空操作返回
- 对p的左子树建立线索
- 对p所指结点建立线索
若p没有左孩子,则为p加上前驱线索
若p没有右孩子,则将p右标志置为1
若结点prenode右标志为1,则为prenode加上后继线索
令prenode指向刚刚访问的结点p- 对p的右子树建立线索
下面,就是这棵树线索化前后的图片:
线索前:
线索后:
###3.3、一些查找函数
由于时间关系,下面这些函数不做详细介绍,都挺简单的。1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82//在中序线索二叉树中求结点的后继指针的算法
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;
}
//在中序线索二叉树中求结点的前驱指针的算法
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;
}
//中序遍历中序线索二叉树
string result;
template<class T>
void InBiThrTree<T>::Travese()
{
	BiThrNode<T> *p = root;
	while (p->ltype == LINK)			//找到中序遍历的起点
		p = p->lchild;
	while (p != NULL)
	{
		result+=p->data;
		cout << p->data;
		p = GetNext(p);
	}
}
//在中序线索化树中,查找结点的父结点
template<class T>
BiThrNode<T> *InBiThrTree<T>::GetParent(BiThrNode<T> *p)
{
	if (p == NULL)
		return NULL;
	BiThrNode<T> *parent;
	parent = p;
	while (parent->rtype == LINK)
		parent = parent->rchild;
	parent = parent->rchild;			//parent是*p的最右下方结点的后继指针
	if (parent && parent->lchild == p)
		return parent;					//猜测*p是否是*parent的左孩子
	parent = p;
	while (parent->ltype == LINK)
		parent = parent->lchild;
	parent = parent->lchild;			//parent是*p的最左下方结点的前驱指针
	return parent;						//parent一定是*p的父指针
}
/*根据值e查找结点*/
template <class T>
BiThrNode<T>* InBiThrTree<T>::Search(T e)
{
	return Search(root,e);
}
template<class T>
BiThrNode<T>* InBiThrTree<T>::Search(BiThrNode<T> *p,T e)
{
	if(p==NULL)			//整棵树空。查找失败,返回上一层
		return NULL;
	if(p->data==e)		//当前节点值正确,返回当前节点
		return p;
	BiThrNode <T> *q=NULL;
	if (p->ltype!=THREAD)
		q=Search(p->lchild,e);	//若此节点不空,并且此节点数据不匹配,找左子树
	if(q!=NULL)			//若左边找到了,返回找到的节点给上一层。
		return q;
	if (p->rtype!=THREAD)
		return Search(p->rchild,e); //若左边没找到,返回右子树找到的结果,可以为NULL,可以为节点、
	return NULL;
}
需要注意一点,不能把按值查找直接搬过来,需要改下判断条件就可以了,其他的函数,书本上都有,不做过多解释。
四、测试函数
| 1 | int main() | 
这边需要注意一下,在线索化之前,需要把PreNode置空,便于第一个THREAD节点的操作。
测试树是这棵:
测试结果如下:
2015年5月4日晚