参考:
https://www.cnblogs.com/web424/p/6911892.html
https://blog.csdn.net/u014532217/article/details/79118023
https://www.cnblogs.com/zhangbaochong/p/5164994.html
https://blog.csdn.net/rodman177/article/details/89771156
https://blog.csdn.net/jnu_simba/article/details/8852653
https://blog.csdn.net/wannuoge4766/article/details/83998377
java数据结构之树
树定义和基本术语
定义
树(Tree)是n(n≥0)个结点的有限集T,并且当n>0时满足下列条件:
(1)有且仅有一个特定的称为根(Root)的结点;
(2)当n>1时,其余结点可以划分为m(m>0)个互不相交的有限集T1、T2 、…、Tm,每个集Ti(1≤i≤m)均为树,且称为树T的子树(SubTree)。
特别地,不含任何结点(即n=0)的树,称为空树。
如下就是一棵树的结构:
图1
基本术语
结点:存储数据元素和指向子树的链接,由数据元素和构造数据元素之间关系的引用组成。
孩子结点:树中一个结点的子树的根结点称为这个结点的孩子结点,如图1中的A的孩子结点有B、C、D
双亲结点:树中某个结点有孩子结点(即该结点的度不为0),该结点称为它孩子结点的双亲结点,也叫前驱结点。双亲结点和孩子结点是相互的,如图1中,A的孩子结点是B、C、D,B、C、D的双亲结点是A。
兄弟结点:具有相同双亲结点(即同一个前驱)的结点称为兄弟结点,如图1中B、B、D为兄弟结点。
结点的度:结点所有子树的个数称为该结点的度,如图1,A的度为3,B的度为2.
树的度:树中所有结点的度的最大值称为树的度,如图1的度为3.
叶子结点:度为0的结点称为叶子结点,也叫终端结点。如图1的K、L、F、G、M、I、J
分支结点:度不为0的结点称为分支结点,也叫非终端结点。如图1的A、B、C、D、E、H
结点的层次:从根结点到树中某结点所经路径的分支数称为该结点的层次。根结点的层次一般为1(也可以自己定义为0),这样,其它结点的层次是其双亲结点的层次加1.
树的深度:树中所有结点的层次的最大值称为该树的深度(也就是最下面那个结点的层次)。
有序树和无序树:树中任意一个结点的各子树按从左到右是有序的,称为有序树,否则称为无序树。
树的抽象数据类型描述
数据元素:具有相同特性的数据元素的集合。
结构关系:树中数据元素间的结构关系由树的定义确定。
数据结构-各种树的定义
术语
- 节点深度:对任意节点x,x节点的深度表示为根节点到x节点的路径长度。所以根节点深度为0,第二层节点深度为1,以此类推
- 节点高度:对任意节点x,叶子节点到x节点的路径长度就是节点x的高度
- 树的深度:一棵树中节点的最大深度就是树的深度,也称为高度
- 父节点:若一个节点含有子节点,则这个节点称为其子节点的父节点
- 子节点:一个节点含有的子树的根节点称为该节点的子节点
- 节点的层次:从根节点开始,根节点为第一层,根的子节点为第二层,以此类推
- 兄弟节点:拥有共同父节点的节点互称为兄弟节点
- 度:节点的子树数目就是节点的度
- 叶子节点:度为零的节点就是叶子节点
- 祖先:对任意节点x,从根节点到节点x的所有节点都是x的祖先(节点x也是自己的祖先)
- 后代:对任意节点x,从节点x到叶子节点的所有节点都是x的后代(节点x也是自己的后代)
- 森林:m颗互不相交的树构成的集合就是森林
PS:其实对于祖先和后代的定义,不同的资料有不同的解释,争论在于节点本身是否是本身的祖先或者后代,我这里的定义取得是《数据结构与算法( Java 描述)-邓俊辉》。维基百科中对于祖先和后代的定义是:
Descendant:A node reachable by repeated proceeding from parent to child.
Ancestor:A node reachable by repeated proceeding from child to parent.
树的种类
无序树
树的任意节点的子节点没有顺序关系。
有序树
树的任意节点的子节点有顺序关系。
二叉树
树的任意节点至多包含两棵子树。
满二叉树
叶子节点都在同一层并且除叶子节点外的所有节点都有两个子节点。
完全二叉树
对于一颗二叉树,假设其深度为d(d>1)。除第d层外的所有节点构成满二叉树,且第d层所有节点从左向右连续地紧密排列,这样的二叉树被称为完全二叉树;
PS:这里的满二叉树和完全二叉树取的是国内的定义,国外的定义不一样,有兴趣的可以去看看国外的定义。
平衡二叉树(AVL)
它是一 棵空树或它的左右两个子树的高度差的绝对值不超过1,并且左右两个子树都是一棵平衡二叉树,同时,平衡二叉树必定是二叉搜索树。
平衡二叉树(Balanced Binary Tree)又被称为AVL树(有别于AVL算法),且具有以下性质:它是一 棵空树或它的左右两个子树的高度差的绝对值不超过1,并且左右两个子树都是一棵平衡二叉树。这个方案很好的解决了二叉查找树退化成链表的问题,把插入,查找,删除的时间复杂度最好情况和最坏情况都维持在O(logN)。但是频繁旋转会使插入和删除牺牲掉O(logN)左右的时间,不过相对二叉查找树来说,时间上稳定了很多。
二叉查找树(二叉搜索树、BST)
若任意节点的左子树不空,则左子树上所有节点的值均小于它的根节点的值;
若任意节点的右子树不空,则右子树上所有节点的值均大于它的根节点的值;
任意节点的左、右子树也分别为二叉查找树;
没有键值相等的节点。
什么是二叉查找树:
根节点的值大于其左子树中任意一个节点的值,小于其右节点中任意一节点的值,这一规则适用于二叉查找树中的每一个节点。
有一下二叉查找树,如图:
霍夫曼树
带权路径最短的二叉树称为哈夫曼树或最优二叉树。
红黑树
红黑树是一颗特殊的二叉查找树,除了二叉查找树的要求外,它还具有以下特性:
- 每个节点或者是黑色,或者是红色。
- 根节点是黑色。
- 每个叶子节点(NIL)是黑色。 [注意:这里叶子节点,是指为空(NIL或NULL)的叶子节点!]
- 如果一个节点是红色的,则它的子节点必须是黑色的。
- 从一个节点到该节点的子孙节点的所有路径上包含相同数目的黑节点。
B-tree(B-树或者B树)
一颗m阶B树的特性:
- 根结点至少有两个子女(如果B树只有一个根节点,这个根节点的key的数量可以为[1~m-1])
- 每个非根节点所包含的关键字个数 j 满足:⌈m/2⌉ - 1 <= j <= m - 1,节点的值按非降序方式存放,即从左到右依次增加
- 除根结点以及叶子节点以外的所有结点的度数正好是关键字总数加1,故内部节点的子树个数 k 满足:⌈m/2⌉ <= k <= m
- 所有的叶子结点都位于同一层
假定:
m:B树的阶
n:非根的内部节点键的个数
t:m阶B树的节点能存在的最小的度
则有:
⌈m/2⌉ - 1 <= n <= m - 1
t - 1 <= n <= 2t -1
B+树
m阶B+树是m阶B-tree的变体,它的定义大致跟B-tree一致,不过有以下几点不同:
- 有n棵子树的结点中含有n个关键字,每个关键字不保存数据,只用来索引,所有数据都保存在叶子节点,其中⌈m/2⌉ <= n <= m
- 所有的叶子结点中包含了全部关键字的信息,及指向含这些关键字记录的指针,且叶子结点本身依关键字的大小自小而大顺序链接
- 所有的非终端结点可以看成是索引部分,结点中仅含其子树(根结点)中的最大(或最小)关键字
- 通常在B+树上有两个头指针,一个指向根结点,一个指向关键字最小的叶子结点
B*树
B*树是B+树的变体,除了B+树的要求之外,还有以下特性:
- ⌈m*2/3⌉ <= n <=m 这里的n是除根节点之外的内部节点的键
- 增加内部节点中兄弟节点的指针,由左边指向右边
数据结构:树的定义和基本概念
一、树(Tree)是n(n>=0)个结点的有限集。n=0时称为空树。在任意一棵非空树中:(1)有且仅有一个特定的称为根(root)的结点。
(2)当n>1时,其余结点可分为m(m>0)个互不相交的有限集T1,T2,....,Tm, 其中每一个集合本身又是一棵树,并且称为根的子树(SubTree),如图1所示:
树的定义之中还用到了树的概念,即递归定义。如图2中的子树T1和T2就是根结点A的子树。当然D,G,H,I 组成的的树又是B结点的子树,E,J 组成的树是C结点的子树。
图2
对于树的定义还需要注意两点:
1.n>0时根结点是唯一的,不可能存在多个根结点。
2.m>0时,子树的个数没有限制,但它们一定是互不相交的。如图3中的两个结构就不符合树的定义,因为它们都有相交的子树。
图3
二.树的结点包含一个数据元素及若干指向其子树的分支。结点拥有的子树称为结点的度(Degree)。度为0的结点称为叶结点(Leaf)或终端结点;度不为0的结点称为非终端结点或分支结点,除根结点之外,分支结点也称为内部结点。树的度是树内各结点的度的最大值。如图4,因为这棵树结点的度的最大值是结点D的度3,所以树的度也为3。
图4
结点的子树的根称为该结点的孩子(Child),相应地,该结点称为孩子的双亲(Parent),同一个双亲的孩子之间互称为兄弟(Sibling)。结点的祖先是从根到该结点所经分支上的所有结点。所以对于H来说,D,B,A都是它的祖先。反之,以某结点为根的子树中的任一结点都称为该结点的子孙。B的子孙有D,G,H,I,如图5所示。
图5
三、结点的层次(Level)从根开始定义起,根为第一层,根的孩子为第二层。其双亲在同一层的结点互为堂兄弟。显然在图6中D,E,F都是堂兄弟,而
G,H,I 与 J也是堂兄弟。树中结点的 最大层次称为树的深度(Depth)或高度,当前树的深度为4(注:也有一些书是定义为branches的个数,此时认为
深度为3)。
图6
若将树中每个结点的各子树看成是从左到右有次序的(即不能互换),则称该树为有序树(OrderedTree);否则称为无序树(UnorderedTree)。注意:若不特别指明,一般讨论的树都是有序树。
森林(Forest)是m(m≥0)棵互不相交的树的集合。对树中每个结点而言,其子树的集合即为森林。对于图1的树而言,图2的两棵子树其实就可以理解为森林。树和森林的概念相近。删去一棵树的根,就得到一个森林;反之,加上一个结点作树根,森林就变为一棵树。
对比线性表与树的结构,它们有很大不同,如图7所示。
图7
参考:《大话数据结构》
数据结构之树
1.树
在计算器科学中,树(英语:tree)是一种抽象数据类型或是实现这种抽象数据类型的数据结构,用来模拟具有树状结构性质的数据集合。它是由n(n>0)个有限节点组成一个具有层次关系的集合。把它叫做“树”是因为它看起来像一棵倒挂的树,也就是说它是根朝上,而叶朝下的。它具有以下的特点:
①每个节点有零个或多个子节点;
②没有父节点的节点称为根节点;
③每一个非根节点有且只有一个父节点;
④除了根节点外,每个子节点可以分为多个不相交的子树;
然后你要知道一大堆关于树的术语:度,叶子节点,根节点,父节点,子节点,深度,高度。
二叉树
二叉树:每个节点最多含有两个子树的树称为二叉树。(我们一般在书中试题中见到的树是二叉树,但并不意味着所有的树都是二叉树。)
在二叉树的概念下又衍生出满二叉树和完全二叉树的概念
满二叉树:除最后一层无任何子节点外,每一层上的所有结点都有两个子结点。也可以这样理解,除叶子结点外的所有结点均有两个子结点。节点数达到最大值,所有叶子结点必须在同一层上
完全二叉树:若设二叉树的深度为h,除第 h 层外,其它各层 (1~(h-1)层) 的结点数都达到最大个数,第h层所有的结点都连续集中在最左边,这就是完全二叉树。
算法实现(笑)
二叉树:
private static class TreeNode {
int val;
TreeNode left;
TreeNode right;
TreeNode(int x) { val = x; }
}
二叉树的遍历方式
先序遍历:先根节点->遍历左子树->遍历右子树
中序遍历:遍历左子树->根节点->遍历右子树
后序遍历:遍历左子树->遍历右子树->根节点
深度优先搜索(DFS)与广度优先搜索(BFS)
实现:bfs=队列,入队列,出队列 一次访问一条路径;dfs=栈,压栈,出栈 一次访问多条路径(来自知乎)
关系:用DFS解决的问题都可以用BFS解决。DFS易于编写(递归),时间消耗较少但是容易发生爆栈,而BFS可以控制队列的长度。
2.动态查找树
2.1 二叉查找树
二叉查找树是二叉树的衍生概念:
二叉查找树(英语:Binary Search Tree),也称为二叉搜索树、有序二叉树(ordered binary tree)或排序二叉树(sorted binary tree),是指一棵空树或者具有下列性质的二叉树:
1.若任意节点的左子树不空,则左子树上所有节点的值均小于它的根节点的值;
2. 若任意节点的右子树不空,则右子树上所有节点的值均大于它的根节点的值;
3.任意节点的左、右子树也分别为二叉查找树;
4.没有键值相等的节点。
二叉查找树相比于其他数据结构的优势在于查找、插入的时间复杂度较低为 O ( log n ) 。二叉查找树是基础性数据结构,用于构建更为抽象的数据结构,如集合、多重集、关联数组等。
2.2 平衡二叉树(AVL树)
平衡二叉树:当且仅当任何节点的两棵子树的高度差不大于1的二叉树;
其中AVL树是最先发明的自平衡二叉查找树,是最原始典型的平衡二叉树。
平衡二叉树是基于二叉查找树的改进。由于在某些极端的情况下(如在插入的序列是有序的时),二叉查找树将退化成近似链或链,此时,其操作的时间复杂度将退化成线性的,即O(n)。所以我们通过自平衡操作(即旋转)构建两个子树高度差不超过1的平衡二叉树。
具体可以参阅1962年G.M. Adelson-Velsky 和 E.M. Landis的论文"An algorithm for the organization of information"。(这个坑我会以后补)
2.3 红黑树
红黑树也是一种自平衡的二叉查找树。
1.每个结点要么是红的要么是黑的。(红或黑)
2.根结点是黑的。 (根黑)
3.每个叶结点(叶结点即指树尾端NIL指针或NULL结点)都是黑的。 (叶黑)
4.如果一个结点是红的,那么它的两个儿子都是黑的。 (红子黑)
5.对于任意结点而言,其到叶结点树尾端NIL指针的每条路径都包含相同数目的黑结点。(路径下黑相同)
如图就是一棵典型的红黑树。保证红黑树满足它的基本性质,就是在调整数据结构自平衡。
而红黑树自平衡的调整操作方式就有旋转和变色两种。
红黑树是一种应用很广的数据结构,如在Java集合类中TreeSet和TreeMap的底层,C++STL中set与map,以及linux中虚拟内存的管理。
2.4 哈夫曼树(Huffman Tree)
哈夫曼树是一种带权路径长度最短的二叉树,也称为最优二叉树。
一般可以按下面步骤构建:
1,将所有左,右子树都为空的作为根节点。
2,在森林中选出两棵根节点的权值最小的树作为一棵新树的左,右子树,且置新树的附加根节点的权值为其左,右子树上根节点的权值之和。注意,左子树的权值应小于右子树的权值。
3,从森林中删除这两棵树,同时把新树加入到森林中。
4,重复2,3步骤,直到森林中只有一棵树为止,此树便是哈夫曼树。
大家可能更多听说的是哈夫曼编码,其实就是哈夫曼树的应用。即如何让电文中出现较多的字符采用尽可能短的编码且保证在译码时不出现歧义。
3.多路查找树
大规模数据存储中,实现索引查询这样一个实际背景下,树节点存储的元素数量是有限的(如果元素数量非常多的话,查找就退化成节点内部的线性查找了),这样导致二叉查找树结构由于树的深度过大而造成磁盘I/O读写过于频繁,进而导致查询效率低下。
3.1 B树
B树(英语:B-tree)是一种自平衡的树,能够保持数据有序。这种数据结构能够让查找数据、顺序访问、插入数据及删除的动作,都在对数时间内完成。B树,概括来说是一个一般化的二叉查找树(binary search tree),可以拥有最多2个子节点。与自平衡二叉查找树不同,B树适用于读写相对大的数据块的存储系统,例如磁盘。
1.根结点至少有两个子女。
2.每个中间节点都包含k-1个元素和k个孩子,其中 m/2 <= k <= m
3.每一个叶子节点都包含k-1个元素,其中 m/2 <= k <= m
4.所有的叶子结点都位于同一层。
5.每个节点中的元素从小到大排列,节点当中k-1个元素正好是k个孩子包含的元素的值域分划。
如图所示就是一颗符合规范的B树,由于相比于磁盘IO的速度,内存中的耗时几乎可以省略,所以只要树的高度足够低,IO次数足够小,就可以提升查询性能。
B树的增加删除同样遵循自平衡的性质,有旋转和换位。
B树的应用是文件系统及部分非关系型数据库索引。
3.2 B+树
B+ 树是一种树数据结构,通常用于关系型数据库(如Mysql)和操作系统的文件系统中。B+ 树的特点是能够保持数据稳定有序,其插入与修改拥有较稳定的对数时间复杂度。B+ 树元素自底向上插入,这与二叉树恰好相反。
在B树基础上,为叶子结点增加链表指针(B树+叶子有序链表),所有关键字都在叶子结点 中出现,非叶子结点作为叶子结点的索引;B+树总是到叶子结点才命中。
b+树的非叶子节点不保存数据,只保存子树的临界值(最大或者最小),所以同样大小的节点,b+树相对于b树能够有更多的分支,使得这棵树更加矮胖,查询时做的IO操作次数也更少。
这通常在多数节点在次级存储比如硬盘中的时候出现。通过最大化在每个内部节点内的子节点的数目减少树的高度,平衡操作不经常发生,而且效率增加了。
3.3 B*树
B*树是B+树的变体,在B+树的非根和非叶子结点再增加指向兄弟的指针
在B+树基础上,为非叶子结点也增加链表指针,将结点的最低利用率从1/2提高到2/3。
3.4 R树
R树是用来做空间数据存储的树状数据结构。例如给地理位置,矩形和多边形这类多维数据建立索引。
R树的核心思想是聚合距离相近的节点并在树结构的上一层将其表示为这些节点的最小外接矩形(MBR),这个最小外接矩形就成为上一层的一个节点。因为所有节点都在它们的最小外接矩形中,所以跟某个矩形不相交的查询就一定跟这个矩形中的所有节点都不相交。叶子节点上的每个矩形都代表一个对象,节点都是对象的聚合,并且越往上层聚合的对象就越多。也可以把每一层看做是对数据集的近似,叶子节点层是最细粒度的近似,与数据集相似度100%,越往上层越粗糙。