引言

对于大量的输入数据,链表的线性访问时间太慢,不宜使用。本篇讨论一种简单的数据结构——树,它大部分操作的运行时间平均为数据结构——树的概述_树的概述。数据结构中有很多树的结构,其中包括二叉树、二叉搜索树、2-3树、红黑树等等。

树和森林的区别

数据结构——树的概述_树的概述_02

基本概念

树(tree) 是一些节点的集合。

该集合可以是空集,若不是空集,则树由称为根(root)​r​​ 的节点以及0个或多个非空的子树组成。

每颗子树的根就做根​​r​​的儿子(child),而​​r​​是每颗子树的根的父亲。

数据结构——树的概述_二叉树_03


上图中,A是根,节点F有一个父亲A并且有儿子K、L和M。每个节点可以有零个或任意个儿子。没有儿子的节点称为叶子节点(leaf)

上图中的B、C、H等是叶子节点。

具有相同父亲的节点称为兄弟(siblings),因此B、C、D、E、F、G都是兄弟。这种定义和家谱很像,类似地,我们可以得到祖父孙子的定义。J是A的孙子,A是I的祖父。

从节点数据结构——树的概述_B树_04数据结构——树的概述_树的概述_05的**路径(path)**定义为节点数据结构——树的概述_二叉树_06的一个序列。

这条路径的 长(length) 是为该路径上的边的条数,即数据结构——树的概述_二叉搜索树_07

从每一个节点到它自己有一条长为0的路径。注意,在一颗树中从根到每个节点恰好存在一条路径。

对任意节点数据结构——树的概述_二叉树_08深度(depth) 为从根到数据结构——树的概述_二叉树_08的唯一的路径的长。因此,根的深度为0。

数据结构——树的概述_二叉树_08高(height) 是从数据结构——树的概述_二叉树_08到叶子节点的最长路径的长。因此所有的叶子节点(树叶)高都是0.
一棵树的高等于它的根的高。

对于上文中那颗树,E的深度为1(A-E)而高为2(E-J-Q)。该树的高为3。一棵树的深度等于它的最深的树叶的深度;该深度总是等于这棵树的高。

树这种数据结构有广泛的应用,比如操作系统中用到了红黑树,数据库用到了B+树,编译器用到了语法树。下面用Java来实现各种常见的树。

二叉树

数据结构——树的概述_二叉树_12

二叉树(binary tree) 是一颗每个节点都不能多于两个孩子(儿子)的树。通常叫它的儿子为左孩子和右孩子(或左子树和右子树)。

二叉树的性质

  • 在非空二叉树中,第i层的节点总数不超过数据结构——树的概述_二叉搜索树_13,i>=1
  • 深度为h的二叉树最多有数据结构——树的概述_二叉搜索树_14个节点
  • 对于任何一颗二叉树,如果其叶子节点数位数据结构——树的概述_二叉搜索树_15,度为2(同时有两个孩子节点)的节点数为数据结构——树的概述_二叉树_16,则数据结构——树的概述_二叉搜索树_17
  • 具有n个节点的完全二叉树的深度为数据结构——树的概述_树的概述_18
  • 给定n个节点,能构成h(n)种不同的二叉树,其中h(n)为卡特兰数的第n项,数据结构——树的概述_B树_19

数据结构——树的概述_红黑树_20

满二叉树:除最后一层无任何子节点外,每一层上的所有节点都有两个子节点。

满二叉树的性质

  1. 一颗树深度为h,最大层数为k,深度与最大层数相同,k=h
  2. 叶子数为数据结构——树的概述_B树_21
  3. 第k层的节点数是:数据结构——树的概述_二叉树_22
  4. 总节点数是:数据结构——树的概述_红黑树_23,且总节点数一定是奇数

完全二叉树:若设二叉树的深度为h,除第 h 层外,其它各层 (1~(h-1)层) 的节点数都达到最大个数,第h层所有的节点都连续集中在最左边,这就是完全二叉树。

我们定义通用二叉树接口:

public interface BinaryTree<E> {
void insert(E x);

void remove(E x);

boolean contains(E x);

boolean isEmpty();

void makeEmpty();

void printTree();
}

二叉查找树

见图解二叉查找树

实现好了二叉查找树后,我们利用它来学习二叉树的遍历

二叉查找树的查询效率很依赖于树的深度。

数据结构——树的概述_二叉树_24


若生成的二叉查找树像这样,其实它就退化为链表。下面介绍一种能自动平衡左右节点的二叉查找树。

AVL树

AVL树通常被称为平衡二叉(搜索)树。

见图解AVL树

AVL树虽然能够自动平衡,但是它有如下显著的缺点:

  • 插入/删除后的旋转,成本不低
  • 删除操作,最坏情况下需要数据结构——树的概述_B树_25次旋转

伸展树

伸展树是基于AVL树的,但它并没有AVL的平衡要求,任意节点的左右子树可以相差任意深度。与二叉搜索树类似,伸展树的单次搜索也可能需要n次操作。但伸展树可以保证,m次的连续搜索操作的复杂度为mlog(n)的量级,而不是mn量级。

实现见图解伸展树

B树系列

B-树

B树也称B-树,它是一颗平衡的多路搜索树。我们描述一颗B树时需要指定它的阶数,阶数表示一个节点最多有多少个孩子节点,一般用字母m表示阶数。当m取2时,就是我们常见的二叉搜索树。

有时也称M路B树,即有M个分支的B树

多级存储系统中使用B-树,可针对外部查找,大大减少I/O次数。

数据结构——树的概述_二叉树_26


可以看到,B树是一颗矮胖的平衡多叉树。

详细图解与Java代码实现见图解B-树

红黑树

敬请期待