一、线索二叉树
二叉树的遍历运算是将二叉树中结点按一定规律线性化的过程。
当以二叉链表作为存储结构时,只能找到结点的左、右孩子信息,而不能直接得到结点在遍历序列中的前驱和后继信息。
要得到这些信息可采用以下两种方法:
1、是将二叉树遍历一遍,在遍历过程中便可得到结点的前驱和后继,但这种动态访问浪费时间;
2、是充分利用二叉链表中的空链域, 将遍历过程中结点的前驱、 后继信息保存下来。
在有n个结点的二叉链表中共有2n个链域,但只有n-1个有用的非空链域,其余n+1个链域是空的。
我们可以利用剩下的n+1个空链域来存放遍历过程中结点的前驱和后继信息。
二、线索链表
线索:将二叉链表中的空指针域指向前驱结点和后继结点的指针被称为线索;
线索化:使二叉链表中结点的空链域存放其前驱或后继信息的过程称为线索化;
线索二叉树:加上线索的二叉树称为线索二叉树。
线索链表:线索二叉树的存储结构
结点结构:Itag Lchild data child rtag
Itag
=0: lchild指向该结点的左孩子
=1: lchild指向该结点的前驱结点
rtag
=0: rchild指向该结点的右孩子
=1: rchild指向该结点的后继结点
enum flag {Child, Thread};
template <class T>
struct ThrNode
{
T data;
ThrNode<T> *lchild, *rchild;
flag ltag, rtag;
};
二叉树的遍历方式有4种,故有4种意义下的前驱和后继,相应的有4种线索二叉树:
⑴ 前序线索二叉树
⑵ 中序线索二叉树
⑶ 后序线索二叉树
⑷ 层序线索二叉树
中序链表类的声明
template <class T>
class InThrBiTree{
public:
InThrBiTree();
~ InThrBiTree( );
ThrNode *Next(ThrNode<T> *p);
void InOrder(ThrNode<T> *root);
private:
ThrNode<T> *root;
ThrNode<T> * Creat();
void ThrBiTree(ThrNode<T> *root);
};
中序线索链表的建立——构造函数
分析:建立线索链表,实质上就是将二叉链表中的空指针改为指向前驱或后继的线索,而前驱或后继的信息只有在遍历该二叉树时才能得到。
template <class T>ThrNode<T>* InThrBiTree<T>::Creat( ){
ThrNode<T> *root;
T ch;
cout<<"请输入创建一棵二叉树的结点数据"<<endl;
cin>>ch;
if (ch=="#") root = NULL;
else{
root=new ThrNode<T>;
root->data = ch;
root->ltag = Child; root->rtag = Child;
root->lchild = Creat( );
root->rchild = Creat( );
}
return root;
}
中序线索化二叉树:递归实现
基本思想:
在遍历的过程中完成线索化
可以采用前序、中序、后序遍历建立前序线索二叉树、中序线索二叉树和后序线索二叉树。
中序线索二叉树的构造方法
中序线索化根结点的左子树;
对根结点进行线索化;
中序线索化根结点的右子树;
算法分析
函数设置形参root和全局变量pre,分别表示要处理的树的根结点和其前驱结点
如果root!=NULL
中序线索化root的左子树
中序线索化root本身
如果root->lchildNULL
root->left=pre,root->ltag=1;
如果root->rchildNULL,root->rtag=1,
如果pre!=NULL, 并且pre->rtag=1,
pre->rchild=root,;
pre=root
中序线索化root的右子树
template <class T> void ThrBiTree<T>::ThrBiTree (ThrNode<T>*root) {
if (root==NULL) return; //递归结束条件
ThrBiTree(root->lchild);
if (!root->lchild){ //对root的左指针进行处理
root->ltag = Thread;
root->lchild = pre; //设置pre的前驱线索
}
if (!root->rchild) root->rtag = Thread;
if(pre != NULL){
if (pre->rtag==Thread) pre->rchild = root;
}
pre = root;
ThrBiTree(root->rchild);
}
线索二叉树的建立
ThrNode<T>* pre = NULL
template <class T>
InThrBiTree<T>::InThrBiTree( )
{
//ThrNode<T>* pre = NULL;
this->root = Creat( );
ThrBiTree(root);
}
线索链表的遍历算法:中序遍历中序线索树
1、查找第一个节点
先从穿线树的根出发,一直沿左指针,找到“最左”(它一定是中序的第一个结点);
2、结点后继的确定
一个结点的右指针如果是线索,则右指针就是下一个要遍历的结点,
如果右指针不是线索,则它的中序后继是其右子树的“最左”结点
3、遍历何时停止?
一个节点的右指针==NULL
template <class T> ThrNode<T>* InThrBiTree<T>::Next(ThrNode<T>* p)
{
ThrNode<T>* q; //要查找的p的后继
if (p->rtag==Thread) q = p->rchild;
else{
q = p->rchild;
while (q->ltag==Child) {
q = q->lchild;
}
}
return q;
}