二叉树遍历时从任一节点出发只能找到左右孩子,而一般的情况下无法直接找到该结点在某种遍历序列中的前驱和后继结点,这种信息只能在遍历的动态过程中才能得到。
但是,如果在首次遍历二叉树的过程中以某种方式保存了遍历序列中的前驱和后继结点的信息,则以后就可以根据该信息,加快相应的遍历过程。
考虑到一个具有n个结点的二叉树表,在2n个指针中只有n-1个是用来存储孩子结点的地址,存在n+1个空指针,可以利用这些空指针存放指向该结点在某种遍历序列中的前驱和后继结点的指针。这些指向前驱和后继结点的指针称为线索,加上线索的二叉树称为线索二叉树。
在线索链表中,对于任意结点,若左指针为空,则用左指针域存放该结点的前驱线索,若右指针域为空,则用右指针域存放该结点的后继线索。为了区分指针域存放的是指向孩子的指针还是指向前驱或者后继的线索,每个结点再增设两个标志域ltag和rtag。若标志为0则child指向结点的左孩子,若为1则指向结点的前驱或者后继。
可用C++中的结构类型描述线索链表中的结点:
enum flag {Child, Thread};
template<typename T>
struct TBNode
{
T data;
TBNode<T> * lchild, * rchild;
flag ltag, rtag;
};
如图是某树的中序线索二叉树示意图
结点D的左线索为空,表明它是中序遍历的开始结点,结点F的右线索为空,表明它是中序遍历的终止结点。
结点是叶子结点的充要条件是它的左右标志均是1。
注意:由于二叉树的遍历有四种,故有4中意义下的前驱和后继。也就是说有4种线索二叉树。下面的讨论以中序线索二叉树为主。
template<typename T>
class ThreadBinaryTree
{
public:
ThreadBinaryTree();
~ThreadBinaryTree();
TBNode<T> * Getroot();
TBNode<T> * Prior(TBNode<T> * p); //查找结点p的前驱
TBNode<T> * Next(TBNode<T> * p); //查找结点p的后继
void InOrder(TBNode<T> * root); //遍历线索二叉树
private:
TBNode<