一、预备知识
1、定义树的一种自然的方式是递归的方式。一棵树是一些节点的集合,这个集合可以是空集,若不是空集,则树由称作根的节点r以及0个或多个非空的(子)树T1,T2,…,Tk组成,这些子树中每一棵的根都被来自根r的一条有向的边所连结。
2、一棵树是N个节点和N-1条边的集合,其中一个节点叫做根。每条边都将某个节点连接到它的父亲,而除去根节点外每一个节点都有一个父亲。每一个节点可以有任意多个节点,也可能是0个节点。没有儿子的节点称为树叶。具有相同父亲的节点为兄弟。
3、从每一个节点到它自己有一条长为0的路径。在一棵树中从根到每个节点恰好存在一条路径。
4、对任意节点ni,ni的深度为从根到ni的唯一的路径的长。因此,根的深度为0。ni的高是从ni到一片树叶的最长路径的长。因此,所有树叶的高都是0。一棵树的高等于它根的高。
5、树的实现
(1)实现树的一种方法可以是在每一个节点除数据外还要有一些链,使得该节点的每一个儿子都有一个链指向它。将每个节点的所有儿子都放在树节点的链表中。
(2)树节点的声明
class TreeNode{
Object element;
TreeNode firstChild;
TreeNode nextSibling;
}
6、树的遍历及应用
(1)在先序遍历中,对节点的处理工作是在它的诸儿子节点被处理之前进行的。
(2)在后序遍历中,一个节点处的工作是在它的诸儿子节点被计算后进行的。
(3)在中序遍历中,首先处理左子树,然后是当前的节点,最后处理右子树。
二、二叉树
1、二叉树是一棵树,其中每个节点都不能有多于2个的儿子。
2、二叉树的一个性质是一棵平均二叉树的深度要比节点个数N小得多,其平均深度为O(根号N),二叉查找树的深度的平均值是O(log N)。
3、实现
(1)二叉树节点声明
class BinaryNode{
Object element;
BinaryNode left;
BinaryNode right;
}
(2)表达式树的树叶是操作数,如常数或变量名,而其他的节点为操作符。
三、查找数ADT——二叉查找树
1、使二叉树成为二叉查找树的性质是,对于树中每个节点X,它的左子树中所有项的值小于X中的项,而它的右子树中所有项的值大于X中的项。
2、二叉查找树要求所有的项都能够排序。
3、contains方法
如果在树T中存在含有项X的节点,那么这个操作需要返回true,如果这样的节点不存在则返回false。如果T是空集,返回false。否则如果存储在T处的项是X,那么可以返回true。否则我们对树T的左子树或右子树进行一次递归调用。
4、findMin方法和findMax方法
这两个private例程分别返回树中包含最小元和最大元的节点的引用。为执行findMin,从根开始并且只要有左儿子就向左进行。终止点就是最小的元素。findMax例程除分支朝向右外其余过程相同。
5、insert方法
重复元的插入可以通过在节点记录中保留一个附加域以只是发生的频率来处理。
6、remove方法
(1)如果节点是一片树叶,那么它可以被立即删除。
(2)如果节点是一个儿子,则该节点可以在其父节点调整自己的链以绕过该节点后被删除。
(3)如果节点具有两个节点,一般的删除策略是用 其右子树的最小的数据代替该节点的数据并递归删除那个节点。因为右子树中的最小的节点不可能有左儿子,所以第二次remove较容易。
(4)如果删除的次数不多,通常使用的策略是懒惰删除:当一个元素要被删除时,它仍然留在树中,而只是被标记为删除。
7、平均情况分析
(1)若所有的插入序列都是等可能的,则树的所有节点的平均深度为O(log N)。
(2)一棵树的所有节点的深度的和称为内部路径长。
四、AVL树
1、AVL树是带有平衡条件的二叉查找树。这个平衡条件必须要容易保持,而且保证树的深度须是O(log N)。另一个平衡条件是要求每个节点都必须有相同高度的左子树和右子树。
2、一棵AVL树是其每个节点的左子树和右子树的高度最多差1的二叉查找树(空树的高度定义为-1)。
3、单旋转
4、双旋转
五、伸展树
1、伸展树保证从空树开始连续M次对树的操作最多花费O(M log N)时间。
2、当M次操作的序列总的最坏情形运行时间为O(M f(N))时,就说它的摊还运行时间为O(f(N))。
3、伸展树的基本思想:当一个节点被访问后,它就要经过一系列AVL树的旋转被推到根上。
六、树的遍历
1、先序遍历
2、后序遍历
3、中序遍历
4、层序遍历:所有深度为d的节点要在深度为d+1的节点之前进行处理。它不是递归的执行,它用队列,而不使用递归默认的栈。
七、B树
1、原则上B树保证只有少数的磁盘访问。
2、阶为M的B树具有的性质:
(1)数据项存储在树叶上。
(2)非叶子节点存储直到M-1个关键字以指示搜索的方向;关键字i代表子树i+1中的最小关键字。
(3)树的根或者是一片树叶,或者其儿子树在2和M之间。
(4)除根外,所有非树叶节点的儿子树在[M/2]和M之间。
(5)所有的树叶都在相同的深度上并有[L/2]和L之间个数据项。
八、标准库中的集合与映射
1、关于Set接口
(1)Set接口代表不允许重复元的Collection。由接口SortedSet给出的一种特殊类型的Set保证其中的各项处于有序的状态。
(2)对于Set,add方法如果执行成功则返回true,否则返回false,因为被添加的项已经存在。
(3)保持各项以有序状态的Set的实现是TreeSet,TreeSet类的基本操作花费对数最坏情形时间。
(4)默认情况下,排序假设TreeSet中的项实现Comparable接口。
2、关于Map接口
(1)Map是一个接口,代表由关键字以及它们的值组成的一些项的集合。关键字必须是唯一的,但是若干关键字可以映射到一些相同的值,因此,值不必是唯一的。
(2)在SortedMap接口中,映射中的关键字保持逻辑上有序状态。SortedMap接口的一种实现是TreeMap。
(3)Map的基本操作包括isEmpty、clear、size等方法。
(4)主要方法
boolean containsKey (keyType key)
ValueType get (keyType key):返回Map中与key相关的值,或当key不存在时返回null。如果在Map中不存在null值,那么必须使用containsKey。
ValueType put (keyType key , ValueType value):把关键字/值对置入Map中,或者返回null,或者返回与key相关联的老值。
(5)通过一个Map进行迭代的3中方法(Map不提供迭代器):
Set<KeyType> keySet ():返回简单的集合。
Collection<ValueType> values ():返回简单的集合。
Set<Map.Entry<KeyValue.Valuetype>> entrySet ():作为一些项而形成的Set对象被返回。
3、TreeSet类和TreeMap类的实现
(1)Java要求TreeSet和TreeMap支持基本的add、remove和contains操作以对数最坏情形时间完成。因此,基本的实现方法就是平衡二叉查找树。
(2)实现TreeSet和TreeMap提供对迭代器类的支持:
在构造迭代器时,让每个迭代器把包含如TreeSet项的数组作为该迭代器的数据存储;
让迭代器保留存储通向当前节点的路径上的节点的一个栈;
让查找数中的灭个节点除存储子节点外还要存储它的父节点;
让每个节点保留两个附加的链:一个通向下一个更小的节点,另一个通向下一个更大的节点;
只对那些具有null左链或null右链的节点保留附加的链;
(3)线索树:通过使用附加的布尔变量使得这些例程判断是一个左链正在被用作标准的二叉树左链还是一个通向下一个更小节点的链,对右链也有类似的判断。
代码:点击打开链接