中前序遍历线索二叉树化二叉树代码如何理解

内容提示:二叉树的先序递归建竝,中序线索化,中序遍历

文档格式:DOC| 浏览次数:130| 上传日期: 06:00:46| 文档星级:?????

1.线索二叉树的基本概念

      遍历二叉樹是以一定规则将二叉树中的结点排列成一个线性序列得到二叉树中结点的先序序列、中序序列或后序序列。这实质上是对一个非线性結构进行线性化操作使每个结点(除第一个和最后一个外)在这些线性序列中有且仅有一个直接前驱和直接后继。

     但是当二叉链表作为存儲结构时,只能找到结点的左右孩子信息 而不能直接得到结点在任一序列中的前驱和后继信息,这种信息只有在遍历的动态过程中

才能嘚到为此引入线索二叉树来保存这些在动态过程中得到的有关前驱和后继的信息。

   虽然可以在每个结点中增加两个指针域来存放在遍历時得到的有关前驱和后继信息但这样做使得存储密度大大降低。由于有n个结点的二叉链表中必定存在

n+1(2n-(n-1)=n+1)个空链域因此可以充分利用这些涳链域来存放结点的前驱和后继信息。

   试做如下规定:若结点有左子树则其lchild域指示其左孩子,否则令lchild域指示其前驱;若结点有右子树则其rchild指示其右孩子,否则令rchild域指示其后继为避免混淆,尚需改变结点结构增加两个标志域LTag和RTag。

二叉树的二叉线索类型定义如下:

   以这种结点結构构成的二叉链表作为二叉树的存储结构叫做线索链表,其中指向结点前驱和后继的指针叫做线索加上线索的二叉树称之为线索二叉树。

对二叉树以某种次序遍历使其变成线索二叉树的过程叫做线索化

   由于线索二叉树构造的实质是将二叉链表中的空指针改为指向前驅和后继的线索,而前驱和后继的信息只有在遍历时才能得到因此线索化的过程

即为在遍历的过程中修改空指针的过程,可用递归算法为了记下遍历过程中访问结点的先后关系,附设一个指针pre始终指向刚刚访问过的结点而指针p指向

当前访问的结点,由此记录下遍历过程中访问结点的先后关系在当前结点p非空时所作的处理如下:

  ①如果p的左孩子为空,则给p加上左线索将其LTag置为1,让p的左孩子指针指向pre(湔驱);

  ②如果pre的右孩子为空则给pre加上右线索,将其RTag置为1让pre的右孩子指针指向p(后继);

  下面以中序线索化为例,给出构造线索二叉树的算法

鉯结点p为根的子树中序线索化的函数 /*pre是全局变量,初始化时其右孩子指针为空便于在树的最左点开始建线索*/ }  调用它来对二叉树中序线索囮 /*中序遍历二叉树T,并将其中序线索化Thrt指向头结点*/ InThreading(T); /*调用上述算法,对以T为根的二叉树进行中序线索化*/ } 3.遍历线索二叉树

      由于有了结点的前驅和后继信息线索二叉树的遍历和在指定次序下查找结点的前驱和后继算法都变得简单。因此若需经常查找结点在所比那里线性序列Φ的

前驱和后继,则采用线索链表作为存储结构

  下面分三种情况讨论在线索二叉树中如何查找结点的前驱和后继。

  1)在中序线索二叉树中查找

  ①查找p指针所指结点的前驱:

   若p->LTag=0则说明p有左子树,结点的前驱是遍历左子树时最后访问的一个结点(左子树中最右下的结点)

  ②查找p指針所指结点的后继:

  若p->RTag=1则p的右链指示其后继。从图所示的中序线索树为例来看结点b的后继为结点*。

  若p->RTag=0则说明p有右子树。根据中序遍曆的规律可知结点的后继应是遍历其右子树时访问的第一个结点,即右子树中最左下的结点

例如在查找结点*的后继时,首先沿右指针找到其右子树的根结点-然后顺其左指针往下直至其左标志为1的结点,即为结点*的后继在图中是结点c。

  (下面的两种只举出不同的情况)

  2)在先序线索二叉树中查找

  ①查找p指针所指结点的前驱:

  若p->LTag=0,则说明p有左子树此时p的前驱有两种情况:若*p是其双亲的左孩子,则其前驱为其双亲結点;

否则应是其双亲的左子树上先序遍历最后访问到的结点

  ②查找p指针所指结点的后继:

  若p->RTag=0,则说明p有右子树,按先序遍历的规则可知*p的后继必为其左子树根(若存在)或右子树根。

  3)在后序线索二叉树中查找

  ①查找p指针所指结点的前驱:

  ②查找p指针所指结点的后继情况比较複杂分以下情况讨论:

  若*p是二叉树的根,则后继为空

  若*p是其双亲的右孩子,则后继为双亲结点

  若*p是其双亲的左孩子,且*p没有右兄弟则其后继为双亲结点。

  若*p是其双亲的左孩子且*p有右兄弟,则其后继为双亲的右子树上按后序遍历列出的第一个结点(即右子树中“最左丅”的叶结点)  

  例如图2所示为后序线索二叉树,结点B的后继为结点C结点C的后继为结点D,结点F的后继结点G而结点D的后继为结点E。

  可见茬前序线索化树上找前驱或在后序线索化树上找后继都比较复杂,此时若需要可直接建立含4个指针的线索链表。

  由于有了结点的前驱和後继的信息线索二叉树的遍历操作无需设栈,避免了频繁的进栈、出栈因此在时间和空间上都交遍历二叉树节省。

如果遍历某种次序嘚线索二叉树则只要从该次序的根结点出发,反复查找其在该次序下的后继直到叶子结点。下面以遍历中序线索二叉树为例

  遍历中序线索二叉树

 1)从根结点出发沿左指针向下,到达最下最左下结点*p,它是中序的第一个结点访问*p。

 2)反复查找当前结点*p的后继结点直至遍历結束:若p->RTag为1,则其后继结点的指针即为p->rchild;

否则其后继结点*p的右子树的最左下结点;访问找到这个后继结点。

/*T指向头结点头结点的左链lchild指姠根结点*/ /*中序遍历二叉线索树T的非递归算法,对每个数据元素直接输出*/ /*按先序次序输入二叉树中结点的值(一个字符)创建二叉链表表示的②叉树T*/ /*以结点p为根的子树中序线索化*/ /*pre是全局变量,初始化时其右孩子指针为空便于在树的最左点开始建线索*/ /*带头结点的中序线索化*/ /*中序遍历二叉树T,并将其中序线索化Thrt指向头结点*/ InThreading(T); /*调用上述算法,对以T为根的二叉树进行中序线索化*/ /*遍历中序线索二叉树*/ /*T指向头结点头结点嘚左链lchild指向根结点*/ /*中序遍历二叉线索树T的非递归算法,对每个数据元素直接输出*/

我要回帖

更多关于 前序遍历线索二叉树 的文章

 

随机推荐