Home About us Products Services Contact us Bookmark
:: wikimiki.org ::
树 (数据结构)

树 (数据结构)

树是一种数据结构,它是由n(n>=0)个有限结点组成一个具有层次关系的集合。把它叫做“树”是因为它看起来像一棵倒挂的树,也就是说它是根朝上,而叶朝下的。它具有以下的特点:
- 每个结点有零个或多个子结点;
- 每一个子结点只有一个父结点;
- 没有前驱的结点为根结点;
- 除了根结点外,每个子结点可以分为m个不相交的子树;

术语

#结点的度:一个结点含有的子树的个数称为该节点的度; #叶节点或终端结点:度为零的结点称为叶结点; #非终端结点或分支结点:度不为零的结点; #双亲节点:在含有孩子的结点中,这个结点称为孩子结点的双亲结点; #孩子节点:一个结点子树的根节点称为孩子结点; #兄弟节点:具有相同双亲结点的结点互称为兄弟节点; #树的度:一棵树中,最大的节点的度称为树的度; #结点的层次:从根开始定义起,根为第一层,根的孩子为第二层; #树的高度或深度:树中结点的最大层次; #堂兄弟:双亲在同一层的结点互为堂兄弟; #结点的祖先:从根到该结点所经分支上的所有结点; #子孙:以某结点为根的子树中任一结点都称为该结点的子孙。 #森林:由m(m>=0)棵互不相交的树的集合称为森林;

树的种类


- 无序树:树中任意节点的子结点之间没有顺序关系,这种树称为无序树;
- 有序树:树中任意节点的子结点之间有顺序关系,这种树称为有序树;
  - 二叉树:每个节点最多含有两个子树的树称为二叉树;
    - 完全二叉树
    - 满二叉树
  - 哈夫曼树带权路径最短的二叉树称为哈夫曼树或最优二叉树;

存储

双亲表示法

存储结构

 /
- 树的双亲表存储表示
- / #define MAX_TREE_SIZE 100 typedef struct PTNode; typedef struct PTree;
image:sqll.jpg

基本操作

/
- 树的双亲表存储的基本操作(14个)
- / #define ClearTree InitTree /
- 二者操作相同
- / #define DestroyTree InitTree /
- 二者操作相同
- / void InitTree(PTree
- T) typedef struct QElemType; /
- 定义队列元素类型
- / #include"c3-2.h" /
- 定义LinkQueue类型(链队列)
- / #include"bo3-2.c" /
- LinkQueue类型的基本操作
- / void CreateTree(PTree
- T) Status TreeEmpty(PTree T) int TreeDepth(PTree T) TElemType Root(PTree T) TElemType Value(PTree T,int i) Status Assign(PTree
- T,TElemType cur_e,TElemType value) TElemType Parent(PTree T,TElemType cur_e) TElemType LeftChild(PTree T,TElemType cur_e) TElemType RightSibling(PTree T,TElemType cur_e) void Print(PTree T)
 Status InsertChild(PTree 
- T,TElemType p,int i,PTree c)
Status deleted[MAX_TREE_SIZE+1]; /
- 删除标志数组(全局量)
- / void DeleteChild(PTree
- T,TElemType p,int i) void TraverseTree(PTree T,void(
- Visit)(TElemType))

孩子链表表示法

存储结构

  /
- 树的孩子链表存储表示
- / typedef struct CTNode
- ChildPtr;   typedef struct CTBox;   typedef struct CTree;
image:hzll.jpg

森林、树与二叉树的转换

二叉树相应章节 Category:数据结构 ja:木構造 (データ構造)

集合

集合(或簡稱集)是基本的数学概念,它是集合论的研究对象。最簡單的說法,即是在最原始的集合論─朴素集合論─中的定義,集合就是“一堆東西”。集合裡的“東西”,叫作元素。若然 x 是集合 A 的元素,記作 xA。 集合是现代数学中一个重要的基本概念。集合论的基本理论直到十九世纪末才被创立,现在已经是数学教育中一个普遍存在的部分,在小学时就开始学习了。这里对被数学家们称为"直观的"或"朴素的"集合论进行一个简短而基本的介绍;更详细的分析可见朴素集合论。对集合进行严格的公理推导可见公理集合论

导言

非正式的,一个集合就是将几个对象适当归类而作为一个整体。集合中的对象称作元素或成员。集合中的元素可以是任何东西:数字,人,字母,别的集合,等等。集合通常表示为大写字母 ABC,等等。两个集合 AB 相等,写作 A = B,如果它们有相同的元素。

集合的表示


- 集合可以用文字描述,比如: :A = 大于零的前三个自然数 :B = 红色、白色、蓝色和绿色
- 集合的另一种表示方法是在大括号中列出其元素,比如: :C = :D = 尽管两个集合有不同的表示,它们仍可能是相同的。比如:上述集合中,A = CB = D,因为它们正好有相同的元素。 元素列出的顺序不同,或者元素列表中有重复,都没有关系。比如:这三个集合 , 和 是相同的,同样因为它们有相同的元素。
- 集合在不严格的意义下也可以通过草图来表示,更多信息,请见文氏图

集合的元素个数

上述每一个集合都有确定的元素个数;比如:集合 A 有三个元素,而集合 B 有四个。 集合可以没有元素。这样的集合叫做空集,用符号 \varnothing 表示。比如:在2004年,集合 A 是所有住在月球上的人,它没有元素,则 A = \varnothing。就像数字零,看上去微不足道,而在数学上,空集非常重要。更多信息请看空集。 集合也可以有无穷多个元素。比如:自然数的集合是无穷大的。关于无穷大和集合的大小的更多信息请见集合的

子集

如果集合 A 的所有元素同时都是集合 B 的元素,则 A 称作是 B 的子集,写作 AB。若 AB 的子集,且 A 不等于 B,则 A 称作是 B 的真子集,写作 A ⊂ B 举例: :
- 所有男人的集合是所有人的集合的真子集。 :
- 所有自然数的集合是所有整数的集合的真子集。 :
-  ⊂  :
-  ⊆  空集是所有集合的子集,而所有集合都是其本身的子集: :
- \varnothingA :
- AA 更多信息,请见子集

并集

有多种方法通过现有集合来构造新的集合。 两个集合可以相"加"。AB 的并集,写作 A ∪ B,是或属于 A 的、或属于 B 的所有元素组成的集合。 子集 举例: :
-  ∪  = :
-  ∪  = :
-  ∪  = 并集的一些基本性质 :
- A ∪ B   =   B ∪ A :
- A  ⊆  A ∪ B :
- A ∪ A   =  A :
- A ∪ \varnothing   =  A 更多信息,请见并集.

交集

一个新的集合也可以通过两个集合"共"有的元素来构造。AB 的交集,写作 A ∩ B,是既属于 A 的、又属于 B 的所有元素组成的集合。 若 A ∩ B  =  \varnothing,则 AB 称作不相交。 并集 举例: :
-  ∩  = \varnothing :
-  ∩  = :
-  ∩  = 交集的一些基本性质 :
- A ∩ B   =   B ∩ A :
- A ∩ B   ⊆   A :
- A ∩ A   =   A :
- A ∩ \varnothing   =   \varnothing 更多信息,请见交集

补集

两个集合也可以相"减"。AB 中的相对补集,写作 B − A,是属于 B 的、但不属于 A 的所有元素组成的集合。 在特定情况下,所讨论的所有集合是一个给定的全集 U 的子集。这样, U − A 称作 A 的绝对补集,或简称补集,写作 A′。 全集 补集可以看作两个集合相减,有时也称作差集。 举例: :
-  −  = :
-  −  = :
-  −  = \varnothing :
- 若 U 是整数集,则奇数的补集是偶数 补集的基本性质: :
- A ∪ A′ = U :
- A ∩ A′ = \varnothing :
- (A′)′ = A :
- A − B = A ∩ B′ 更多信息,请见补集

公理集合論

把集合看作“一堆東西”會得出所謂罗素悖论。为解决罗素悖论,數學家提出公理集合論。在公理集合论中,集合是一个不加定义的概念。

在更深層的公理化数学中,集合仅仅是一种特殊的,是“良性类”,是能够成为其它类的元素的类。 类区分为两种:一种是可以顺利进行类运算的“良性类”,我们把这种“良性类”称为集合;另一种是要限制运算的“本性类”,对于本性类,类运算是并不都能进行的。 定义 类A如果满足条件“\exists B(A\in B)”,则称类A为一个集合(简称为集),记为Set(A)。否则称为本性类。 这说明,一个集合可以作为其它类的元素,但一个本性类却不能成为其它类的元素。因此可以理解为“本性类是最高层次的类”。 参见:公理化数学 -- 类的理论 -- 罗素公理体系 -- 集合代数 category:集合论 category:数据结构 ja:集合 ko:집합

二叉树

计算机科学中,二叉树是每个结点最多有两个子树有序树。通常子树的根被称作“左子樹”(left subtree)和“右子樹”(right subtree)。二叉树常被用作二叉查找树二叉堆。 二叉树的每个结点至多只有二棵子树(不存在度大于2的结点),二叉树的子树有左右之分,次序不能颠倒。二叉树的第i层至多有2^个结点;深度为k的二叉树至多有2^k-1个结点;对任何一棵二叉树T,如果其终端结点数为n_0,度为2的结点数为n_2,则n_0=n_2+1。 树和二叉树的三个主要差别: #树的结点个数至少为1,而二叉树的结点个数可以为0; #树中结点的最大度数没有限制,而二叉树结点的最大度数为2; #树的结点无左、右之分,而二叉树的结点有左、右之分。 二叉堆

图论中的定义

二叉树在图论中是这样定义的:二叉树是一个连通的无环图,并且每一个顶点的度不大于3。有根二叉树还要满足根结点的度不大于2。有了根结点之后,每个顶点定义了唯一的父结点,和最多2个子结点。然而,没有足够的信息来区分左结点和右结点。如果不考虑连通性,允许图中有多个连通分量,这样的结构叫做森林。

二叉树的类型

二叉树是一个有根,并且每个结点最多有2个子结点。 满二叉树是每个结点都有0个或2个子结点的树。 一棵有n个结点的二叉树,按满二叉树的编号方式对它进行编号,若树中所有结点和满二叉树1~n编号完全一致,则称该树为完全二叉树。 一棵深度为k且有2^k-1个结点的二叉树称为满二叉树,这种树的特点是每一层上的结点数都是最大结点数。在一棵二叉树中,除最后一层外,若其余层都是满的,并且最后一层或者是满的,或者是在右边缺少连续若干结点,则此二叉树为完全二叉树。具有n个结点的完全二叉树的深度为log_2n+1。深度为k的完全二叉树至少有2^个结点,至多有2^k-1个结点。 image:mwbitree.jpg

存储二叉树的方法

编程语言中能用多种方法来构造二叉树。在使用记录的编程语言中,二叉树通常用树结点结构来存储。有时也包含指向唯一的父节点的指针。如果一个结点的子结点个数小于2,一些子结点指针可能为空值,或者为特殊的哨兵结点。 二叉树也可以用数组来存储,而且如果这是完全二叉树,这种方法不会浪费空间。用这种紧凑排列,如果一个结点的索引为i,它的子结点能在索引2i+1和2i+2找到,并且它的父节点(如果有)能在索引floor((i-1)/2)找到(假设根节点的索引为0)。这种方法更有利于紧凑存储和更好的访问的局部性,特别是在前序遍历中。然而,它需要连续的存储空间,这样在存储高度为
hn个结点组成的树时将会浪费很多空间。
一个存储在数组中的完全二叉树

顺序存储表示

存储结构

/
- 二叉树的顺序存储表示
- / #define MAX_TREE_SIZE 100 /
- 二叉树的最大结点数
- / typedef TElemType SqBiTree[MAX_TREE_SIZE]; /
- 0号单元存储根结点
- / typedef struct position;

基本操作

/
- 二叉树的顺序存储的基本操作(23个)
- / #define ClearBiTree InitBiTree /
- 在顺序存储结构中,两函数完全一样
- / #define DestroyBiTree InitBiTree /
- 在顺序存储结构中,两函数完全一样
- / void InitBiTree(SqBiTree T) void CreateBiTree(SqBiTree T) Status BiTreeEmpty(SqBiTree T) int BiTreeDepth(SqBiTree T) Status Root(SqBiTree T,TElemType
- e) TElemType Value(SqBiTree T,position e) Status Assign(SqBiTree T,position e,TElemType value) TElemType Parent(SqBiTree T,TElemType e) TElemType LeftChild(SqBiTree T,TElemType e) TElemType RightChild(SqBiTree T,TElemType e) TElemType LeftSibling(SqBiTree T,TElemType e) TElemType RightSibling(SqBiTree T,TElemType e) void Move(SqBiTree q,int j,SqBiTree T,int i) /
- InsertChild()用到。加
- / void InsertChild(SqBiTree T,TElemType p,int LR,SqBiTree c) typedef int QElemType; /
- 设队列元素类型为整型(序号)
- / #include "c3-2.h" /
- 链队列
- / #include "bo3-2.c" /
- 链队列的基本操作
- / Status DeleteChild(SqBiTree T,position p,int LR) void(
- VisitFunc)(TElemType); /
- 函数变量
- / void PreTraverse(SqBiTree T,int e) void PreOrderTraverse(SqBiTree T,void(
- Visit)(TElemType)) void InTraverse(SqBiTree T,int e) void InOrderTraverse(SqBiTree T,void(
- Visit)(TElemType)) void PostTraverse(SqBiTree T,int e) void PostOrderTraverse(SqBiTree T,void(
- Visit)(TElemType)) void LevelOrderTraverse(SqBiTree T,void(
- Visit)(TElemType))
 void Print(SqBiTree T)
 

二叉链表存储表示

存储结构

/
- 二叉树的二叉链表存储表示
- / typedef struct BiTNode BiTNode,
- BiTree;
image:eclb.jpg

基本操作

/
- 二叉树的二叉链表存储的基本操作(22个)
- / #define ClearBiTree DestroyBiTree /
- 清空二叉树和销毁二叉树的操作一样
- / #include"func6-3.c" /
- 包括InitBiTree()、DestroyBiTree()、PreOrderTraverse()和InOrderTraverse()4函数
- / void CreateBiTree(BiTree
- T) Status BiTreeEmpty(BiTree T) int BiTreeDepth(BiTree T) TElemType Root(BiTree T) TElemType Value(BiTree p) void Assign(BiTree p,TElemType value) typedef BiTree QElemType; /
- 设队列元素为二叉树的指针类型
- / #include"c3-2.h" /
- 链队列
- / #include"bo3-2.c" /
- 链队列的基本操作
- / TElemType Parent(BiTree T,TElemType e) BiTree Point(BiTree T,TElemType s) TElemType LeftChild(BiTree T,TElemType e) TElemType RightChild(BiTree T,TElemType e) TElemType LeftSibling(BiTree T,TElemType e) TElemType RightSibling(BiTree T,TElemType e) Status InsertChild(BiTree p,int LR,BiTree c) /
- 形参T无用
- / Status DeleteChild(BiTree p,int LR) /
- 形参T无用
- / typedef BiTree SElemType; /
- 设栈元素为二叉树的指针类型
- / #include"c3-1.h" /
- 顺序栈
- / #include"bo3-1.c" /
- 顺序栈的基本操作
- / void InOrderTraverse1(BiTree T,void(
- Visit)(TElemType)) void InOrderTraverse2(BiTree T,void(
- Visit)(TElemType)) void PostOrderTraverse(BiTree T,void(
- Visit)(TElemType)) void LevelOrderTraverse(BiTree T,void(
- Visit)(TElemType))

三叉链表存储表示

存储结构

/
- 二叉树的三叉链表存储表示
- / typedef struct BiTPNode BiTPNode,
- BiPTree; image:3clb.jpg

基本操作

/
- 二叉树的三叉链表存储的基本操作(21个)
- / #define ClearBiTree DestroyBiTree /
- 清空二叉树和销毁二叉树的操作一样
- / void InitBiTree(BiPTree
- T) void DestroyBiTree(BiPTree
- T) void CreateBiTree(BiPTree
- T) Status BiTreeEmpty(BiPTree T) int BiTreeDepth(BiPTree T) TElemType Root(BiPTree T) TElemType Value(BiPTree p) void Assign(BiPTree p,TElemType value) typedef BiPTree QElemType; /
- 设队列元素为二叉树的指针类型
- / #include"c3-2.h" /
- 链队列
- / #include"bo3-2.c" /
- 链队列的基本操作
- / BiPTree Point(BiPTree T,TElemType e) TElemType Parent(BiPTree T,TElemType e) TElemType LeftChild(BiPTree T,TElemType e) TElemType RightChild(BiPTree T,TElemType e) TElemType LeftSibling(BiPTree T,TElemType e) TElemType RightSibling(BiPTree T,TElemType e) Status InsertChild(BiPTree p,int LR,BiPTree c) /
- 形参T无用
- / Status DeleteChild(BiPTree p,int LR) /
- 形参T无用
- / void PreOrderTraverse(BiPTree T,void(
- Visit)(BiPTree)) void InOrderTraverse(BiPTree T,void(
- Visit)(BiPTree)) void PostOrderTraverse(BiPTree T,void(
- Visit)(BiPTree)) void LevelOrderTraverse(BiPTree T,void(
- Visit)(BiPTree)) 访问二叉树的方法

我们经常希望访问树中的每一个结点并且查看它的值。有很多常见的顺序来访问所有的结点,而且每一种都有有用的性质。

前(先)序、中序、后序遍历

遍历二叉树:L、D、R分别表示遍历左子树、访问根结点和遍历右子树,则先(根)序遍历二叉树的顺序是DLR,中(根)序遍历二叉树的顺序是LDR,后(根)序遍历二叉树的顺序是LRD。还有按层遍历二叉树。这些方法的时间复杂度都是O(n),n为结点个数。 如果T2是由有序树T转换而来的二叉树,那么T中结点的前序就是T2中结点的前序,T中结点的后序就是T2中结点的中序。任何一棵二叉树的叶结点在先序、中序和后序遍历中的相对次序不发改变。设n,m为一棵二叉树上的两个结点,在中序遍历时,n在m前的条件是n在m的左方。前序序列和中序序列相同的二叉树为空树或任一结点均无左孩子的非空二叉树;中序序列和后序序列相同的二叉树为空树或任一结点均无右孩子的非空二叉树;前序序列和后序序列相同的二叉树为空树或仅有一个结点的二叉树。 假设我们有一个包含值的value和指向两个子结点的leftright的树结点结构。我们可以写出这样的过程:
visit(node)
    print node.value
    if node.left  != null then visit(node.left)
    if node.right != null then visit(node.right)
这样会用中序打印出树中的值。在中序,每个结点在访问它的子结点之前访问。类似地,如果打印语句在最后,每个结点在访问他的子节点之后访问,树中的值会用后序来打印。在这两种情况中,左子树中的值比右子树中得值先打印。
visit(node)
    if node.left  != null then visit(node.left)
    print node.value
    if node.right != null then visit(node.right)
最后,上面的中序遍历,每个结点在访问左子树和右子树之间访问。这在遍历二叉搜索树时很常用,因为它能用递增的顺序来遍历所有的值。 为什么呢?如果n是二叉搜索树的结点,那么n的左子树的所有结点的值都比n的值要小,而且n的右子树的所有节点的值都比n的值要大。因此,如果我们顺序遍历左子树,然后访问n,然后顺序遍历右子树。我们就已经顺序访问了整个树。
二叉搜索树 在这个二叉树中,
- 前序遍历的结果:2, 7, 2, 6, 5, 11, 5, 9, 4
- 后序遍历的结果:2, 5, 11, 6, 7, 4, 9, 5, 2
- 中序遍历的结果:2, 7, 5, 6, 11, 2, 5, 4, 9
以上的递归算法使用与树的高度成比例的栈空间。如果我们在每个结点中存储指向父结点的指针,那样可以使用迭代算法,只使用常数空间实现所有这些遍历。然而,指向父结点的指针占用更多的空间。这只在需要指向父节点的指针或栈空间有限时才使用。例如, 这是一个中序遍历的迭代算法:
visit(root)
    prev    := null
    current := root
    next    := null
    
    while current != null
        if prev  current.parent
            prev := current
            next := current.left
        if next 

null or prev

current.left print current.value prev := current next := current.right if next

null or prev

current.right prev := current next := current.parent current := next
image:Bitree.JPG 用二叉树表示下述表达式:a+b
- (c-d)-e/f
- 先序遍历的序列是:-+a
- b-cd/ef
- 中序遍历的序列是:a+b
- c-d-e/f
- 后序遍历的序列是:abcd-
- +ef/-

深度优先遍历

在深度优先顺序中,我们希望从根结点访问最远的结点。和图的深度优先搜索不同的是,不需记住访问过的每一个结点,因为树中不会有环。前序,中序和后序遍历都是深度优先遍历的特例。参见深度优先搜索

广度优先遍历

和深度优先遍历不同,广度优先遍历会先访问离根节点最近的节点。参见广度优先搜索。 二叉树的广度优先遍历又称按层次遍历。算法借助队列实现。

将n叉树转换为二叉树

一般有序树和二叉树之间有一一映射关系,能进行相互转换。 n叉树转换为二叉树的方法:二叉树中结点x的左子结点为n叉树中结点x的左子结点;二叉树中结点x的右子结点为n叉树中结点x的第一个右边的同级结点y。 例如,在左边的树中,A有6个子结点。它能被转换成右边的二叉树。
将n叉树转换为二叉树的例子

- 将一棵树转换为二叉树的方法: #在兄弟之间加一连线; #对每个结点,除了其左孩子外,去除其与其余孩子之间的联系; #以树的根结点为轴心,将整树顺时针转45度。

存储结构与基本操作

树的二叉链表表示法(孩子兄弟表示法)是树和二叉树转换的媒介。

树的二叉链表存储表示

/
- 树的二叉链表(孩子—兄弟)存储表示
- / typedef struct CSNode CSNode,
- CSTree; image:hzxd.jpg

树的二叉链表存储的基本操作

/
- 树的二叉链表(孩子—兄弟)存储的基本操作(17个)
- / #define ClearTree DestroyTree /
- 二者操作相同
- / #include"func6-2.c" /
- 包括PreOrderTraverse()
- / void InitTree(CSTree
- T) void DestroyTree(CSTree
- T) typedef CSTree QElemType; /
- 定义队列元素类型
- / #include"c3-2.h" /
- 定义LinkQueue类型(链队列)
- / #include"bo3-2.c" /
- LinkQueue类型的基本操作
- / void CreateTree(CSTree
- T) Status TreeEmpty(CSTree T) int TreeDepth(CSTree T) TElemType Value(CSTree p) TElemType Root(CSTree T)
 CSTree Point(CSTree T,TElemType s)
 
Status Assign(CSTree
- T,TElemType cur_e,TElemType value)
 TElemType Parent(CSTree T,TElemType cur_e)
 
TElemType LeftChild(CSTree T,TElemType cur_e) TElemType RightSibling(CSTree T,TElemType cur_e) Status InsertChild(CSTree
- T,CSTree p,int i,CSTree c) Status DeleteChild(CSTree
- T,CSTree p,int i) void PostOrderTraverse(CSTree T,void(
- Visit)(TElemType)) void LevelOrderTraverse(CSTree T,void(
- Visit)(TElemType))

线索二叉树 (threaded binary tree)

线索二叉树(保留遍历时结点在任一序列的前驱和后继的信息):若结点有左子树,则其lchild域指示其左孩子,否则令lchild域指示其前驱;若结点有右子树,则其rchild域指示其右孩子,否则令rchild指示其后继。还需在结点结构中增加两个标志域LTag和RTag。LTag=0时,lchild域指示结点的左孩子,LTag=1时,lchild域指示结点的前驱;RTag=0时,rchild域指示结点的右孩子,RTag=1时,rchild域指示结点的后继。以这种结点结构构成的二叉链表作为二叉树的存储结构,叫做线索链表,其中指向结点前驱和后继的指针叫做线索,加上线索的二叉树称为线索二叉树。对二叉树以某种次序遍历使其变为线索二叉树的过程叫做线索化。若对二叉树进行中序遍历,则所得的线索二叉树称为中序线索二叉树,线索链表称为为中序线索链表。线索二叉树是一种物理结构。 image:tbt1.jpg 在中序线索树找结点后继的规律是:若其右标志为1,则右链为线索,指示其后继,否则遍历其右子树时访问的第一个结点(右子树最左下的结点)为其后继;找结点前驱的规律是:若其左标志为1,则左链为线索,指示其前驱,否则遍历左子树时最后访问的一个结点(左子树中最右下的结点)为其前驱。在后序线索树中找到结点的后继分三种情况: #若结点是二叉树的根,则其后继为空; #若结点是其双亲的右孩子,或是其双亲的左孩子且其双亲没有右子树,则其后继即为双亲结点; #若结点是其双亲的左孩子,且其双亲有右子树,则其后继为双亲右子树上按后序遍历列出的第一个结点。

二叉线索存储表示

存储结构

二叉树的二叉线索存储表示:在线索链表上添加一个头结点,并令其lchild域的指针指向二叉树的根结点,其rchild域的指针指向中序遍历时访问的最后一个结点。令二叉树中序序列中的第一个结点的lchild域指针和最后一个结点的rchild域的指针均指向头结点,这样就建立了一个双向线索链表 /
- 二叉树的二叉线索存储表示
- / typedef enumPointerTag; /
- Link(0):指针,Thread(1):线索
- / typedef struct BiThrNode BiThrNode,
- BiThrTree;

基本操作

/
- 二叉树的二叉线索存储的基本操作
- / void CreateBiThrTree(BiThrTree
- T) BiThrTree pre; /
- 全局变量,始终指向刚刚访问过的结点
- / void InThreading(BiThrTree p) void InOrderThreading(BiThrTree
- Thrt,BiThrTree T) void InOrderTraverse_Thr(BiThrTree T,void(
- Visit)(TElemType)) void PreThreading(BiThrTree p) void PreOrderThreading(BiThrTree
- Thrt,BiThrTree T) void PreOrderTraverse_Thr(BiThrTree T,void(
- Visit)(TElemType)) void PostThreading(BiThrTree p) void PostOrderThreading(BiThrTree
- Thrt,BiThrTree T) void DestroyBiTree(BiThrTree
- T) void DestroyBiThrTree(BiThrTree
- Thrt) Category:数据结构 Category:树结构 category:图论 ko:이진 트리


二叉树

计算机科学中,二叉树是每个结点最多有两个子树有序树。通常子树的根被称作“左子樹”(left subtree)和“右子樹”(right subtree)。二叉树常被用作二叉查找树二叉堆。 二叉树的每个结点至多只有二棵子树(不存在度大于2的结点),二叉树的子树有左右之分,次序不能颠倒。二叉树的第i层至多有2^个结点;深度为k的二叉树至多有2^k-1个结点;对任何一棵二叉树T,如果其终端结点数为n_0,度为2的结点数为n_2,则n_0=n_2+1。 树和二叉树的三个主要差别: #树的结点个数至少为1,而二叉树的结点个数可以为0; #树中结点的最大度数没有限制,而二叉树结点的最大度数为2; #树的结点无左、右之分,而二叉树的结点有左、右之分。 二叉堆

图论中的定义

二叉树在图论中是这样定义的:二叉树是一个连通的无环图,并且每一个顶点的度不大于3。有根二叉树还要满足根结点的度不大于2。有了根结点之后,每个顶点定义了唯一的父结点,和最多2个子结点。然而,没有足够的信息来区分左结点和右结点。如果不考虑连通性,允许图中有多个连通分量,这样的结构叫做森林。

二叉树的类型

二叉树是一个有根,并且每个结点最多有2个子结点。 满二叉树是每个结点都有0个或2个子结点的树。 一棵有n个结点的二叉树,按满二叉树的编号方式对它进行编号,若树中所有结点和满二叉树1~n编号完全一致,则称该树为完全二叉树。 一棵深度为k且有2^k-1个结点的二叉树称为满二叉树,这种树的特点是每一层上的结点数都是最大结点数。在一棵二叉树中,除最后一层外,若其余层都是满的,并且最后一层或者是满的,或者是在右边缺少连续若干结点,则此二叉树为完全二叉树。具有n个结点的完全二叉树的深度为log_2n+1。深度为k的完全二叉树至少有2^个结点,至多有2^k-1个结点。 image:mwbitree.jpg

存储二叉树的方法

编程语言中能用多种方法来构造二叉树。在使用记录的编程语言中,二叉树通常用树结点结构来存储。有时也包含指向唯一的父节点的指针。如果一个结点的子结点个数小于2,一些子结点指针可能为空值,或者为特殊的哨兵结点。 二叉树也可以用数组来存储,而且如果这是完全二叉树,这种方法不会浪费空间。用这种紧凑排列,如果一个结点的索引为i,它的子结点能在索引2i+1和2i+2找到,并且它的父节点(如果有)能在索引floor((i-1)/2)找到(假设根节点的索引为0)。这种方法更有利于紧凑存储和更好的访问的局部性,特别是在前序遍历中。然而,它需要连续的存储空间,这样在存储高度为
hn个结点组成的树时将会浪费很多空间。
一个存储在数组中的完全二叉树

顺序存储表示

存储结构

/
- 二叉树的顺序存储表示
- / #define MAX_TREE_SIZE 100 /
- 二叉树的最大结点数
- / typedef TElemType SqBiTree[MAX_TREE_SIZE]; /
- 0号单元存储根结点
- / typedef struct position;

基本操作

/
- 二叉树的顺序存储的基本操作(23个)
- / #define ClearBiTree InitBiTree /
- 在顺序存储结构中,两函数完全一样
- / #define DestroyBiTree InitBiTree /
- 在顺序存储结构中,两函数完全一样
- / void InitBiTree(SqBiTree T) void CreateBiTree(SqBiTree T) Status BiTreeEmpty(SqBiTree T) int BiTreeDepth(SqBiTree T) Status Root(SqBiTree T,TElemType
- e) TElemType Value(SqBiTree T,position e) Status Assign(SqBiTree T,position e,TElemType value) TElemType Parent(SqBiTree T,TElemType e) TElemType LeftChild(SqBiTree T,TElemType e) TElemType RightChild(SqBiTree T,TElemType e) TElemType LeftSibling(SqBiTree T,TElemType e) TElemType RightSibling(SqBiTree T,TElemType e) void Move(SqBiTree q,int j,SqBiTree T,int i) /
- InsertChild()用到。加
- / void InsertChild(SqBiTree T,TElemType p,int LR,SqBiTree c) typedef int QElemType; /
- 设队列元素类型为整型(序号)
- / #include "c3-2.h" /
- 链队列
- / #include "bo3-2.c" /
- 链队列的基本操作
- / Status DeleteChild(SqBiTree T,position p,int LR) void(
- VisitFunc)(TElemType); /
- 函数变量
- / void PreTraverse(SqBiTree T,int e) void PreOrderTraverse(SqBiTree T,void(
- Visit)(TElemType)) void InTraverse(SqBiTree T,int e) void InOrderTraverse(SqBiTree T,void(
- Visit)(TElemType)) void PostTraverse(SqBiTree T,int e) void PostOrderTraverse(SqBiTree T,void(
- Visit)(TElemType)) void LevelOrderTraverse(SqBiTree T,void(
- Visit)(TElemType))
 void Print(SqBiTree T)
 

二叉链表存储表示

存储结构

/
- 二叉树的二叉链表存储表示
- / typedef struct BiTNode BiTNode,
- BiTree;
image:eclb.jpg

基本操作

/
- 二叉树的二叉链表存储的基本操作(22个)
- / #define ClearBiTree DestroyBiTree /
- 清空二叉树和销毁二叉树的操作一样
- / #include"func6-3.c" /
- 包括InitBiTree()、DestroyBiTree()、PreOrderTraverse()和InOrderTraverse()4函数
- / void CreateBiTree(BiTree
- T) Status BiTreeEmpty(BiTree T) int BiTreeDepth(BiTree T) TElemType Root(BiTree T) TElemType Value(BiTree p) void Assign(BiTree p,TElemType value) typedef BiTree QElemType; /
- 设队列元素为二叉树的指针类型
- / #include"c3-2.h" /
- 链队列
- / #include"bo3-2.c" /
- 链队列的基本操作
- / TElemType Parent(BiTree T,TElemType e) BiTree Point(BiTree T,TElemType s) TElemType LeftChild(BiTree T,TElemType e) TElemType RightChild(BiTree T,TElemType e) TElemType LeftSibling(BiTree T,TElemType e) TElemType RightSibling(BiTree T,TElemType e) Status InsertChild(BiTree p,int LR,BiTree c) /
- 形参T无用
- / Status DeleteChild(BiTree p,int LR) /
- 形参T无用
- / typedef BiTree SElemType; /
- 设栈元素为二叉树的指针类型
- / #include"c3-1.h" /
- 顺序栈
- / #include"bo3-1.c" /
- 顺序栈的基本操作
- / void InOrderTraverse1(BiTree T,void(
- Visit)(TElemType)) void InOrderTraverse2(BiTree T,void(
- Visit)(TElemType)) void PostOrderTraverse(BiTree T,void(
- Visit)(TElemType)) void LevelOrderTraverse(BiTree T,void(
- Visit)(TElemType))

三叉链表存储表示

存储结构

/
- 二叉树的三叉链表存储表示
- / typedef struct BiTPNode BiTPNode,
- BiPTree; image:3clb.jpg

基本操作

/
- 二叉树的三叉链表存储的基本操作(21个)
- / #define ClearBiTree DestroyBiTree /
- 清空二叉树和销毁二叉树的操作一样
- / void InitBiTree(BiPTree
- T) void DestroyBiTree(BiPTree
- T) void CreateBiTree(BiPTree
- T) Status BiTreeEmpty(BiPTree T) int BiTreeDepth(BiPTree T) TElemType Root(BiPTree T) TElemType Value(BiPTree p) void Assign(BiPTree p,TElemType value) typedef BiPTree QElemType; /
- 设队列元素为二叉树的指针类型
- / #include"c3-2.h" /
- 链队列
- / #include"bo3-2.c" /
- 链队列的基本操作
- / BiPTree Point(BiPTree T,TElemType e) TElemType Parent(BiPTree T,TElemType e) TElemType LeftChild(BiPTree T,TElemType e) TElemType RightChild(BiPTree T,TElemType e) TElemType LeftSibling(BiPTree T,TElemType e) TElemType RightSibling(BiPTree T,TElemType e) Status InsertChild(BiPTree p,int LR,BiPTree c) /
- 形参T无用
- / Status DeleteChild(BiPTree p,int LR) /
- 形参T无用
- / void PreOrderTraverse(BiPTree T,void(
- Visit)(BiPTree)) void InOrderTraverse(BiPTree T,void(
- Visit)(BiPTree)) void PostOrderTraverse(BiPTree T,void(
- Visit)(BiPTree)) void LevelOrderTraverse(BiPTree T,void(
- Visit)(BiPTree)) 访问二叉树的方法

我们经常希望访问树中的每一个结点并且查看它的值。有很多常见的顺序来访问所有的结点,而且每一种都有有用的性质。

前(先)序、中序、后序遍历

遍历二叉树:L、D、R分别表示遍历左子树、访问根结点和遍历右子树,则先(根)序遍历二叉树的顺序是DLR,中(根)序遍历二叉树的顺序是LDR,后(根)序遍历二叉树的顺序是LRD。还有按层遍历二叉树。这些方法的时间复杂度都是O(n),n为结点个数。 如果T2是由有序树T转换而来的二叉树,那么T中结点的前序就是T2中结点的前序,T中结点的后序就是T2中结点的中序。任何一棵二叉树的叶结点在先序、中序和后序遍历中的相对次序不发改变。设n,m为一棵二叉树上的两个结点,在中序遍历时,n在m前的条件是n在m的左方。前序序列和中序序列相同的二叉树为空树或任一结点均无左孩子的非空二叉树;中序序列和后序序列相同的二叉树为空树或任一结点均无右孩子的非空二叉树;前序序列和后序序列相同的二叉树为空树或仅有一个结点的二叉树。 假设我们有一个包含值的value和指向两个子结点的leftright的树结点结构。我们可以写出这样的过程:
visit(node)
    print node.value
    if node.left  != null then visit(node.left)
    if node.right != null then visit(node.right)
这样会用中序打印出树中的值。在中序,每个结点在访问它的子结点之前访问。类似地,如果打印语句在最后,每个结点在访问他的子节点之后访问,树中的值会用后序来打印。在这两种情况中,左子树中的值比右子树中得值先打印。
visit(node)
    if node.left  != null then visit(node.left)
    print node.value
    if node.right != null then visit(node.right)
最后,上面的中序遍历,每个结点在访问左子树和右子树之间访问。这在遍历二叉搜索树时很常用,因为它能用递增的顺序来遍历所有的值。 为什么呢?如果n是二叉搜索树的结点,那么n的左子树的所有结点的值都比n的值要小,而且n的右子树的所有节点的值都比n的值要大。因此,如果我们顺序遍历左子树,然后访问n,然后顺序遍历右子树。我们就已经顺序访问了整个树。
二叉搜索树 在这个二叉树中,
- 前序遍历的结果:2, 7, 2, 6, 5, 11, 5, 9, 4
- 后序遍历的结果:2, 5, 11, 6, 7, 4, 9, 5, 2
- 中序遍历的结果:2, 7, 5, 6, 11, 2, 5, 4, 9
以上的递归算法使用与树的高度成比例的栈空间。如果我们在每个结点中存储指向父结点的指针,那样可以使用迭代算法,只使用常数空间实现所有这些遍历。然而,指向父结点的指针占用更多的空间。这只在需要指向父节点的指针或栈空间有限时才使用。例如, 这是一个中序遍历的迭代算法:
visit(root)
    prev    := null
    current := root
    next    := null
    
    while current != null
        if prev  current.parent
            prev := current
            next := current.left
        if next 

null or prev

current.left print current.value prev := current next := current.right if next

null or prev

current.right prev := current next := current.parent current := next
image:Bitree.JPG 用二叉树表示下述表达式:a+b
- (c-d)-e/f
- 先序遍历的序列是:-+a
- b-cd/ef
- 中序遍历的序列是:a+b
- c-d-e/f
- 后序遍历的序列是:abcd-
- +ef/-

深度优先遍历

在深度优先顺序中,我们希望从根结点访问最远的结点。和图的深度优先搜索不同的是,不需记住访问过的每一个结点,因为树中不会有环。前序,中序和后序遍历都是深度优先遍历的特例。参见深度优先搜索

广度优先遍历

和深度优先遍历不同,广度优先遍历会先访问离根节点最近的节点。参见广度优先搜索。 二叉树的广度优先遍历又称按层次遍历。算法借助队列实现。

将n叉树转换为二叉树

一般有序树和二叉树之间有一一映射关系,能进行相互转换。 n叉树转换为二叉树的方法:二叉树中结点x的左子结点为n叉树中结点x的左子结点;二叉树中结点x的右子结点为n叉树中结点x的第一个右边的同级结点y。 例如,在左边的树中,A有6个子结点。它能被转换成右边的二叉树。
将n叉树转换为二叉树的例子

- 将一棵树转换为二叉树的方法: #在兄弟之间加一连线; #对每个结点,除了其左孩子外,去除其与其余孩子之间的联系; #以树的根结点为轴心,将整树顺时针转45度。

存储结构与基本操作

树的二叉链表表示法(孩子兄弟表示法)是树和二叉树转换的媒介。

树的二叉链表存储表示

/
- 树的二叉链表(孩子—兄弟)存储表示
- / typedef struct CSNode CSNode,
- CSTree; image:hzxd.jpg

树的二叉链表存储的基本操作

/
- 树的二叉链表(孩子—兄弟)存储的基本操作(17个)
- / #define ClearTree DestroyTree /
- 二者操作相同
- / #include"func6-2.c" /
- 包括PreOrderTraverse()
- / void InitTree(CSTree
- T) void DestroyTree(CSTree
- T) typedef CSTree QElemType; /
- 定义队列元素类型
- / #include"c3-2.h" /
- 定义LinkQueue类型(链队列)
- / #include"bo3-2.c" /
- LinkQueue类型的基本操作
- / void CreateTree(CSTree
- T) Status TreeEmpty(CSTree T) int TreeDepth(CSTree T) TElemType Value(CSTree p) TElemType Root(CSTree T)
 CSTree Point(CSTree T,TElemType s)
 
Status Assign(CSTree
- T,TElemType cur_e,TElemType value)
 TElemType Parent(CSTree T,TElemType cur_e)
 
TElemType LeftChild(CSTree T,TElemType cur_e) TElemType RightSibling(CSTree T,TElemType cur_e) Status InsertChild(CSTree
- T,CSTree p,int i,CSTree c) Status DeleteChild(CSTree
- T,CSTree p,int i) void PostOrderTraverse(CSTree T,void(
- Visit)(TElemType)) void LevelOrderTraverse(CSTree T,void(
- Visit)(TElemType))

线索二叉树 (threaded binary tree)

线索二叉树(保留遍历时结点在任一序列的前驱和后继的信息):若结点有左子树,则其lchild域指示其左孩子,否则令lchild域指示其前驱;若结点有右子树,则其rchild域指示其右孩子,否则令rchild指示其后继。还需在结点结构中增加两个标志域LTag和RTag。LTag=0时,lchild域指示结点的左孩子,LTag=1时,lchild域指示结点的前驱;RTag=0时,rchild域指示结点的右孩子,RTag=1时,rchild域指示结点的后继。以这种结点结构构成的二叉链表作为二叉树的存储结构,叫做线索链表,其中指向结点前驱和后继的指针叫做线索,加上线索的二叉树称为线索二叉树。对二叉树以某种次序遍历使其变为线索二叉树的过程叫做线索化。若对二叉树进行中序遍历,则所得的线索二叉树称为中序线索二叉树,线索链表称为为中序线索链表。线索二叉树是一种物理结构。 image:tbt1.jpg 在中序线索树找结点后继的规律是:若其右标志为1,则右链为线索,指示其后继,否则遍历其右子树时访问的第一个结点(右子树最左下的结点)为其后继;找结点前驱的规律是:若其左标志为1,则左链为线索,指示其前驱,否则遍历左子树时最后访问的一个结点(左子树中最右下的结点)为其前驱。在后序线索树中找到结点的后继分三种情况: #若结点是二叉树的根,则其后继为空; #若结点是其双亲的右孩子,或是其双亲的左孩子且其双亲没有右子树,则其后继即为双亲结点; #若结点是其双亲的左孩子,且其双亲有右子树,则其后继为双亲右子树上按后序遍历列出的第一个结点。

二叉线索存储表示

存储结构

二叉树的二叉线索存储表示:在线索链表上添加一个头结点,并令其lchild域的指针指向二叉树的根结点,其rchild域的指针指向中序遍历时访问的最后一个结点。令二叉树中序序列中的第一个结点的lchild域指针和最后一个结点的rchild域的指针均指向头结点,这样就建立了一个双向线索链表 /
- 二叉树的二叉线索存储表示
- / typedef enumPointerTag; /
- Link(0):指针,Thread(1):线索
- / typedef struct BiThrNode BiThrNode,
- BiThrTree;

基本操作

/
- 二叉树的二叉线索存储的基本操作
- / void CreateBiThrTree(BiThrTree
- T) BiThrTree pre; /
- 全局变量,始终指向刚刚访问过的结点
- / void InThreading(BiThrTree p) void InOrderThreading(BiThrTree
- Thrt,BiThrTree T) void InOrderTraverse_Thr(BiThrTree T,void(
- Visit)(TElemType)) void PreThreading(BiThrTree p) void PreOrderThreading(BiThrTree
- Thrt,BiThrTree T) void PreOrderTraverse_Thr(BiThrTree T,void(
- Visit)(TElemType)) void PostThreading(BiThrTree p) void PostOrderThreading(BiThrTree
- Thrt,BiThrTree T) void DestroyBiTree(BiThrTree
- T) void DestroyBiThrTree(BiThrTree
- Thrt) Category:数据结构 Category:树结构 category:图论 ko:이진 트리


Category:数据结构

Category:计算机科学基础理论计算机科学中,数据结构是在计算机中存储数据的方法,使数据能跟有效地使用。一般情况下,精心挑选的数据结构能产生有效的算法。在选择数据结构前必须选择一种抽象数据结构ja:Category:データ構造 ko:분류:자료구조

Socialist Worker

Socialist Worker on brittien laajalevikkisin vallankumouksellinen sanomalehti. Se ilmestyy joka lauantai pitäen sisällään uutiset työväenluokan kamppailuista niin paikallisesti kuin kansainvälisestikin. Lehteä julkaisee Socialist Workers Party, joka on osa International Socialist -suuntausta. Sosialistiliitto on IS:n Suomen osasto.

Aiheesta muualla


- [http://www.socialistworker.co.uk Socialist worker] Luokka:Sanomalehdet

jastrzbia gra pensjonat kaway aminokwasy cukrzyca Odszkodowanie










































:: RELATED NEWS ::
Living will
A living will, also called will to live, advance health directive, or advance health care directive, is a specific type of power of attorney or health care proxy or advance directive. It is a legal instrument that usually is witnessed or notarized. These
Proprietary
Proprietary indicates that a party exercises private ownership, control or use over an item of property, usually to the exclusion of other parties. Where a party holds or claims proprietary interests in relation to certain types of property (eg. a creative literary work, or software), that property may also be the subject of intellectual property law (eg. <
Thomas Corneille
Thomas Corneille (August 20, 1625 - December 8, 1709) was a French dramatist. He was the brother of Pierre Corneille. Born in Rouen being nearly twenty years after his brother, the "great Corneille", T
Zhuangzi
Zhuāngzǐ (pinyin), Chuang Tzu (W-G), or Chuang Tse (Chinese 庄子/莊子, literally meaning "Master Zhuang") was a famous philosopher in ancient China who lived around the 4th century BCE during the Warring States Pe
Copyright law of the United Kingdom
The current copyright law of the United Kingdom is to be found in the Copyright, Designs and Patents Act of 1988 (the 1988 Act), with later amendments. The 1988 Act came into force on 1 August 1989 for the most part, except for some minor provisions that were brought into force through 1990 and 1991. Various amendments have been made to the original statute, mos
University of North Carolina at Asheville
The University of North Carolina at Asheville (known for short as UNC Asheville or UNCA) is a public liberal arts university in Asheville, North Carolina. It is the designated liberal arts institution in the University of North Carolina System.

History

UNC Asheville was founded in
Larry Mullen, Jr.
Larry Mullen, Jr. (born October 31, 1961 in Artane, Dublin, Ireland) is the drummer for the Irish rock band U2.

Biography

Larry grew up with his two siste
Paul McGuinness
:For the musician Paul McGuinness see Shane MacGowan and the Popes. Paul McGuinness is the main shareholder and founder of Principle Management Limited, one of the worlds leading artist management companies who have managed U2 from the start of their successful career. His career has been spent working in the entertainment industry and he is well known throughout the world in both the film and music business. He is the manager of U2,
Henry Ward Beecher
Henry Ward Beecher (June 24, 1813 - March 8, 1887) was a theologically liberal American Congregationalist clergyman and reformer, and author who was born in
Pontus de Tyard
Pontus de Tyard (c. 1521 - September 23, 1605) was a French poet and priest, a member of "La Pléiade". He was born at Bissy in Burgundy, of which he was seigneur, but the exact year of his birth is uncertain. He became a friend of
All Rights Reserved 2005 wikimiki.org