摘要

 

按照某种遍历方式对二叉树进行遍历,可以把二叉树中所有结点排序为一个线性序列。在该序列中,除第一个结点外每个结点有且仅有一个直接前驱结点;除最后一个结点外每一个结点有且仅有一个直接后继结点。这些指向直接前驱结点和指向直接后续结点的指针被称为线索(Thread),加了线索的二叉树称为线索二叉树

编辑本段概念

n个结点的二叉链表中含有n+1(2n-(n-1)=n+1)个空指针域。利用二叉链表中的空指针域,存放指向结点在某种遍历次序下的前趋和后继结点的指针(这种附加的指针称为"线索")。
这种加上了线索的二叉链表称为线索链表,相应的二叉树称为线索二叉树(Threaded BinaryTree)。根据线索性质的不同,线索二叉树可分为前序线索二叉树、中序线索二叉树和后序线索二叉树三种。
注意:
线索链表解决了无法直接找到该结点在某种遍历序列中的前趋和后继结点的问题,出现了二叉链表找左、右孩子困难的问题。

编辑本段线索二叉树结构

二叉树的遍历本质上是将一个复杂的非线性结构转换为线性结构,使每个结点都有了唯一前驱和后继(第一个结点无前驱,最后一个结点无后继)。对于二叉树的一个结点,查找其左右子女是方便的,其前驱后继只有在遍历中得到。为了容易找到前驱和后继,有两种方法。一是在结点结构中增加向前和向后的指针fwd和bkd,这种方法增加了存储开销,不可取;二是利用二叉树的空链指针。现将二叉树的结点结构重新定义如下:
lchild
ltag
data
rtag
rchild
其中:ltag=0 时lchild指向左子女;
ltag=1 时lchild指向前驱;
rtag=0 时rchild指向右子女;
rtag=1 时rchild指向后继;

编辑本段构建

建立线索二叉树,或者说对二叉树线索化,实质上就是遍历一颗二叉树。在遍历过程中,访问结点的操作是检查当前的左,右指针域是否为空,将它们改为指向前驱结点或后续结点的线索。为实现这一过程,设指针pre始终指向刚刚访问的结点,即若指针p指向当前结点,则pre指向它的前驱,以便设线索。
另外,在对一颗二叉树加线索时,必须首先申请一个头结点,建立头结点与二叉树的根结点的指向关系,对二叉树线索化后,还需建立最后一个结点与头结点之间的线索。
下面是建立中序二叉树的递归算法,其中pre为全局变量。
BiThrNodeType *pre;
BiThrTree InOrderThr(BiThrTree T)
{ /*中序遍历二叉树T,并将其中序线索化,pre为全局变量*/
BiThrTree head;
head=(BitThrNodeType *)mallocsizeof(BiThrType));/*设申请头结点成功*/
head->ltag=0;head->rtag=1;/*建立头结点*/
head->rchild=head;/*右指针回指*/
if(!T)head->lchild=head;/*若二叉树为空,则左指针回指*/
else{head->lchild=T;pre=head;
InThreading(T);/*中序遍历进行中序线索化*/
pre->rchild=head;
pre->rtag=1;/*最后一个结点线索化*/
head->rchild=pre;
};
return head;
}
void InThreading(BiThrTree p)
{/*通过中序遍历进行中序线索化*/
if(p)
{InThreading(p->lchild);/*左子树线索化*/
if(p->lchild==NULL)/*前驱线索*/
{p->ltag=1;
p->lchild=pre;
}
else p->ltag=0;
if(p->rchild==NULL)p->rtag=1;/*后驱线索*/
else p->rtag = 0;
if(pre!=NULL && pre->rtag==1) pre->rchild=p;
pre=p;
InThreading(p->rchild);/*右子树线索化*/
}
}

编辑本段算法

进行中序线索化的算法

bithptr*pre; /* 全程变量*/
voidINTHREAD(bithptr *p)
{if(p!=NULL)
{ INTHREAD(p->lchild); /* 左子树线索化*/
if(p->lchild==NULL) {p->ltag=1;p->lchild=pre;}
if(p->rchild==NULL) p->rtag=1;
if(pre!=NULL && pre->rtag==1)pre->rchild=p;
pre=p; /* 前驱指向当前结点*/
INTHREAD(p->rchild); /* 右子树线索化*/
}

线索二叉树查找前驱和后继

(1)中序线索二叉树:若结点的ltag=1,lchild指向其前驱;否则,该结点的前驱是以该结点为根的左子树上按中序遍历的最后一个结点。若rtag=1,rchild指向其后继;否则,该结点的后驱是以该结点为根的右子树上按中序遍历的第一个结点。
求后继的算法如下:
bithptr *INORDERNEXT(bithptr *p)
{if (p->rtag==1)return(p->rchild);
else {q=p->rchild; /* 找右子树最先访问的结点*/
while (q->ltag==0) q=q->lchild;
return(q);
}
}
求前驱的算法如下:
bithptr *INORDERNEXT(bithptr *p)
{if (p->ltag==1)return(p->lchild);
else {q=p->lchild;/* 找左子树最后访问的结点*/
while (q->rtag==0) q=q->rchild;
return(q);
}
}
(2) 后序线索二叉树:
在后序线索二叉树中查找结点*p的前驱:若结点*p无左子树,则p->lchild指向其前驱;否则,若结点*p有左子树,当其右子树为空时,其左子树的根(即p->lrchild)为其后序前驱。当其右子树非空时,其右子树的根(即p->rchild)为其后序前驱。
在后序线索二叉树中查找结点*p的后继:若结点*p为根,则无后继;若结点*p为其双亲的右孩子,则其后继为其双亲;若结点*p为其双亲的左孩子,且双亲无右子女,则其后继为其双亲;若结点*p为其双亲的左孩子,且双亲有右子女,则结点*p的后继是其双亲的右子树中按后序遍历的第一个结点。所以,求后序线索二叉树中结点的后继要知道其双亲的信息,要使用栈,所以说后序线索二叉树是不完
(3)先序线索二叉树:
在先序线索二叉树中查找结点的后继较容易,而查找前驱要知道其双亲的信息,要使用栈,所以说先序线索二叉树也是不完善的。

线索二叉树Threaded binary tree的更多相关文章

  1. 遍历二叉树 traversing binary tree 线索二叉树 threaded binary tree 线索链表 线索化

    遍历二叉树   traversing binary tree 线索二叉树 threaded binary tree 线索链表 线索化 1. 二叉树3个基本单元组成:根节点.左子树.右子树 以L.D.R ...

  2. 数据结构《9》----Threaded Binary Tree 线索二叉树

    对于任意一棵节点数为 n 的二叉树,NULL 指针的数目为  n+1 , 线索树就是利用这些 "浪费" 了的指针的数据结构. Definition: "A binary ...

  3. 笔试算法题(41):线索二叉树(Threaded Binary Tree)

    议题:线索二叉树(Threaded Binary Tree) 分析: 为除第一个节点外的每个节点添加一个指向其前驱节点的指针,为除最后一个节点外的每个节点添加一个指向其后续节点的指针,通过这些额外的指 ...

  4. [数据结构]——二叉树(Binary Tree)、二叉搜索树(Binary Search Tree)及其衍生算法

    二叉树(Binary Tree)是最简单的树形数据结构,然而却十分精妙.其衍生出各种算法,以致于占据了数据结构的半壁江山.STL中大名顶顶的关联容器--集合(set).映射(map)便是使用二叉树实现 ...

  5. 数据结构-二叉树(Binary Tree)

    1.二叉树(Binary Tree) 是n(n>=0)个结点的有限集合,该集合或者为空集(空二叉树),或者由一个根节点和两棵互不相交的,分别称为根节点的左子树和右子树的二叉树组成.  2.特数二 ...

  6. [Swift]LeetCode105. 从前序与中序遍历序列构造二叉树 | Construct Binary Tree from Preorder and Inorder Traversal

    Given preorder and inorder traversal of a tree, construct the binary tree. Note:You may assume that ...

  7. [Swift]LeetCode106. 从中序与后序遍历序列构造二叉树 | Construct Binary Tree from Inorder and Postorder Traversal

    Given inorder and postorder traversal of a tree, construct the binary tree. Note:You may assume that ...

  8. [Swift]LeetCode226. 翻转二叉树 | Invert Binary Tree

    Invert a binary tree. Example: Input: 4 / \ 2 7 / \ / \ 1 3 6 9 Output: 4 / \ 7 2 / \ / \ 9 6 3 1 Tr ...

  9. [Swift]LeetCode654. 最大二叉树 | Maximum Binary Tree

    Given an integer array with no duplicates. A maximum tree building on this array is defined as follo ...

随机推荐

  1. apktool反编译工具

    几个报错的解决办法 apktool反编译时经常会出现下面的信息 Input file was not found or was not readable. Destination directory ...

  2. iOS开发——返回特定的控制器

    用导航控制器返回到上一页和返回到根控制器有其自带方法. 返回到特定的控制器的核心代码: popToViewController用法 方式一,不推荐[self.navigationController ...

  3. 委托和事件[delegate and event]_C#

    委托和事件: 1. 委托:一个能够表示方法的数据类型:它将方法作为对象封装起来,允许在运行时间接地绑定一个方法调用. 2. 声明委托数据类型: public delegate  bool Greate ...

  4. (转)Linux下tomcat JVM内存设置步骤

    java.lang.OutOfMemoryError: PermGen space java.lang.OutOfMemoryError: Java heap space -------------- ...

  5. Java WebService简单实例

    一.准备工作(以下为本实例使用工具) 1.MyEclipse10.7.1 2.JDK 1.6.0_22 二.创建服务端 1.创建[Web Service Project],命名为[TheService ...

  6. 服务器发布WebService返回DataTable

    初始化Datatable时,需要为Datatable命名.否则在客户端使用时,会报“datatable不能序列化...”导致表格无法从服务器端读取到. 例如: 服务器端: DataTable dt = ...

  7. 学习C++ Primer 的个人理解(一)

    <C++ Primer>这本书可以说是公认的学习C++最好的书,但我觉得不是特别适合作为教材,书中内容的顺序让人有些蛋疼.我个人认为初学此书是不能跳着看的.如果急于上手的话,我更推荐< ...

  8. 菜鸟级asp.net 与ms sql server数据库打交道的简单总结

    using System.Data.SqlClient;using System.Data; 上面是必须的 下面说的都是用存储过程 首先是webconfig里面的连接字符串: <connecti ...

  9. 动态linq表达式新方法,Dynamic LINQ Extension Method

    Remember those old posts on Dynamic LINQ? You are probably aware that Microsoft has made its impleme ...

  10. JavaScript异步获取数据解析

    <script type="text/javascript">    var xhr=false;    function createXhr() {    var x ...