一.相关概念
树:由根节点root和0个或多个非空子树组成。(N个节点和N-1条边)
节点相关术语:父亲、孩子、路径的长(两节点之间的边数)、节点深度(节点到根节点的路径的长,根depth为0)、节点度(节点连接的边数)
树相关术语:树的层数(=树的深度)
有很多种树:二叉树、B-树、霍夫曼树。
其中二叉树应用比较多,主要是熟悉二叉树。
B-树的话用在数据库系统里面的磁盘存储。
霍夫曼树主要是压缩算法吧
二.特殊的树–二叉树
一棵树,其中每个节点不能有多于两个的儿子(儿子可为空)。
两个重要概念:
(1)完全二叉树——只有最下面的两层结点度小于2,并且最下面一层的结点都集中在该层最左边的若干位置的二叉树;
(2)满二叉树——除了叶子节点外,每一个节点都有左右子女且叶结点都处在最底层的二叉树,。
二叉树的性质:
(1) 在二叉树中,第i层的节点总数不超过2^(i-1);
(2) 深度为h的二叉树最多有2^h-1个节点(h>=1),最少有h个节点;
(3) 对于任意一棵二叉树,如果其叶节点数为N0,而度数为2的节点总数为N2,
则N0=N2+1;
证明过程如下:
假设二叉树的0度,1度,2度结点为n0,n1,n2,总节点数为T
则有按照节点求和的
T = n0 + n1 + n2 (1)
按照边求和得:
T = n1 + 2 * n2 + 1 (2)(边数+1=节点数)
所以 (2) - (1)可得
n2 + 1 - n0 = 0
所以n0 = n2 + 1
(4) 具有N个节点的完全二叉树的深度为[log2(N)]+1
(5)有N个节点的完全二叉树各节点如果用顺序方式存储(数组实现,参照二叉树1),则节点之间有如下关系:
若I为节点编号则 如果I<>1,则其父节点的编号为I/2;
如果2*I<=N,则其左儿子(即左子树的根节点)的编号为2*I;若2*I>N,则无左儿子;
如果2*I+1<=N,则其右儿子的结点编号为2*I+1;若2*I+1>N,则无右儿子。
特殊的二叉树:
1. 二叉查找树
对于树中每个节点X,它的左子树的所有关键字值小于X的值,右子树所有关键字值大于X的值。(如果有重复可以在节点中加入附加变量存储)
查找过程:
1. 判空、
2. 小于当前递归左、大于当前递归右、否则返回当前。
插入过程递归同查找:
1. 判空(空则为当前插入数据创建新节点)、
2. 小于当前递归左、大于当前递归右、否则修改附加域。
删除的话比较麻烦:
首先,有一个慵懒删除,就是可以不删除节点,而只改变其附加域的值。
1.如果节点是叶子节点,直接删除
2.如果节点有一个儿子,用儿子代替它。
3.如果节点有两个儿子。用其最右子树的最小数据代替它,并且删除它。因为右子树的最小节点不可能有左儿子,所以它的删除比较容易。但是这样如果删除次数过多会导致左子树比右子树深度深(其实也可以每次用左子树最大值来替代,或者说交替进行以保持树的平衡,比如任何节点的深度不能过大,即所谓的平衡二叉树)
以上所有的操作都是O(d),d是关键字的节点深度。平均时间复杂度O(logN)。
参照二叉树2(二叉查找树)
2. 平衡二叉树(AVL)
是一棵二叉查找树,但是其每个节点的左子树和右子树的高度最多相差1(空树的高度定义为-1)
这时候节点需要保存高度信息,当我们利用二叉查找树算法插入一个新值时,我们需要保持平衡条件,如果平衡条件不满足,则需要调整,称旋转。
三.树的遍历
先序遍历:PreOrder(T) = T + PreOrder(T->left) + PreOrder(T->right)
中序遍历:InOrder(T) = InOrder(T->left) + T + InOrder(T->right)
后序遍历:PostOrder(T) = PostOrder(T->left) + PostOrder(T->right) + T
层次遍历:从根到叶子从上到下、从左到右输出
先序:DBACEGF
中序:ABCDEFG
后序:ACBFGED
层次:DBEACGF
先序第一个是根,后序最后一个是根,知先中可求后,知中后可求先,知先后不能求中,所以必有中才行。
参考链接:http://www.cr173.com/html/18891_1.html