一,二叉树的中序遍历序列
我们通过对二叉树的中序遍历可以得到一个线性表,我们称为中序遍历序列。
与线性表相同,除了头结点没有前驱结点,最后一个结点没有后继结点。
问题1:我们在对二叉树进行中序遍历的时候,都只能从根结点开始遍历。那我们可不可以从二叉树中的某一个结点开始,对整颗二叉树进行中序遍历。
答案:没有办法,二叉树的缺陷,结点没有办法访问前驱结点。想要进行中序遍历只能从根结点开始。
问题2:
思路:从根结点出发,重新进行一次中序遍历,指针q记录当前访问的结点,指针pre记录上一个被访问的结点
当q和p指向的是同一个结点,则pre则为其前驱结点,然后再走一步则能找到p结点的后继。
总结:重新进行中序遍历是非常不方便的。
中序线索二叉树
为了解决上面的问题,即如何快速的找到某一个结点的中序遍历序列的前后结点。
我们可以利用二叉树中没有存放指针的空链域来存放一些信息,以方便我们快速的对查找中序遍历序列。
该二叉树的中序遍历序列: DGBEAFC
由于头结点D没有前驱结点,所有其左线索为NULL,右指针域存放了指向G的指针所以没有右线索。而G结点的右线索存放其序列中的前驱结点D的指针,依次类推得到的叫做中序线索二叉树。
指向前驱,后继的指针称为“线索”。(而对于一个结点的左右指针域都存放了其左右孩子的指针如何查找其前驱和后继,我们后作讨论。)
线索二叉树的实现
相对于普通的二叉树,我们在定义的时候在结构体中多加了两个int型的变量,以区分其两个指针域存放的是左右孩子还是左右线索。
同样的也存在后序线索二叉树,前序线索二叉树
二叉树的线索化
#include <stdio.h>
//线索二叉树
ThreadNode* pre = NULL;
typedef struct ThreadNode {
int data; //数据域
ThreadNode* lchild, * rchild; //左右指针
int ltag, rtag; //判断是线索还是孩子 =1为中序前驱结点, = 0为孩子结点
}ThreadNode,*ThreeTree;
void CreateInThread(ThreadNode *T) { //中序线索化二叉树
ThreadNode* pre = NULL;
if (T != NULL) {
InThread(T);
if (pre->rchild==NULL) { //处理最后一个结点
pre->rtag = 1;
}
}
}
void visit(ThreadNode* q) { //线索化二叉树y
if (q->lchild == NULL) { //如果当前访问结点的右孩子为空,则将其指针指向中序序列的前驱结点。
q->lchild = pre;
q->ltag = 1;
}
if (pre != NULL && pre->rchild == NULL){ //如果中序序列的前驱结点的左孩子为空,则将其指针指向指向当前结点。
pre->rchild = q;
pre->rtag = 1;
}
pre = q;
}
void InThread(ThreeTree L) { //中序遍历二叉树
if (L != NULL) {
InThread(L->lchild);
visit(L);
InThread(L->rchild);
}
}
int mian() {
ThreadNode * p;
CreateInThread(p);
}