目录
1、基本概念
遍历二叉树是以一定的规则将二叉树中的结点排列成一个线性序列,从而得到几种遍历序列,使得该序列中的每个结点(第一个和最后一个结点除外)都有一个直接前驱和直接后继。
传统的二叉链表存储仅能体现一种父子关系,不能直接得到结点在遍历中的前驱或后继。前面提到,在含n个结点的二叉树中,有n+1个空指针。由此设想能否利用这些空指针来存放指向其前驱或后继的指针?这样就可以像遍历单链表那样方便地遍历二叉树。引入线索二叉树正是为了加快查找结点前驱和后继的速度。
规定:若无左子树。令lchild指向其前驱结点;若无右子树,令rchild指向其后继结点。如下表所示,还需要增加两个标志域标识指针域是指向左(右)孩子还是指向前驱(后继)。
lchild | ltag | data | rtag | rchild |
其中,标志域的含义如下:
线索二叉树的存储结构描述如下:
typedef struct ThreadNodes
{
ElemType data;
struct ThreadNode *lchild,*rchild;
int ltag,rtag; //左右线索标志
}
以这种结点结构构成的二叉链表作为二叉树的存储结构,称为线索链表,其中指向结点前驱和后继的指针称为线索。加上线索的二叉树称为线索二叉树。
2、中序线索二叉树的构造
二叉树的线索化是将二叉链表中的空指针改为指向前驱或后继的线索。而前驱或后继的信息只有在遍历时才能得到,因此线索化的实质就是遍历一次二叉树。
以中序线索二叉树的建立为例。附设指针pre指向刚刚访问过的结点,指针p指向正在访问的结点,即pre指向p的前驱。在中序遍历的过程中,检查p的左指针书否为空,若为空就将它指向pre;检查pre的右指针是否为空,若为空就将它指向p,如图30-1所示
图31-1 中序线索二叉树及其二叉链表示
通过中序非递归遍历建立中序线索二叉树
template<typename DataType>
inline void BinaryTree<DataType>::CreateInThreadTree(ThreadNodes<DataType>* &root) //root是还未加线索的普通二叉树
{
ThreadNodes<DataType> * p = root;
ThreadNodes<DataType> *pre = NULL;
stack<ThreadNodes<DataType> *> myStack;
myStack.push(p);
while (!myStack.empty())
{
while (p->LChild && p->ltag != 1)
{
myStack.push(p->LChild);
p = p->LChild;
}
ThreadNodes<DataType> *node = myStack.top();
if (pre)
{
if (pre->RChild)
pre->rtag = 0;
else
{
pre->RChild = node;
pre->rtag = 1;
}
if (node->LChild)
node->ltag = 0;
else
{
node->LChild = pre;
node->ltag = 1;
}
}
myStack.pop();
cout << node->data << " ";
pre = node;
if (node->RChild && node->rtag != 1)
{
myStack.push(node->RChild);
p = myStack.top();
}
}
}
3、先序线索二叉树和后序线索二叉树
图31-2 先序线索二叉树
同理,我就不用再画后序线索二叉树了吧。
想飞上天,和大佬肩并肩,哈哈