2026/7/27 数据结构8(树(1))
一、树的概念和原理
树是一种非线性结构,其严格的数学定义是:如果一组数据中除了第一个节点(第一个节点称为根节点,没有直接前驱节点)之外,其余任意节点有且仅有一个直接前驱,有零个或多个直接后继,这样的一组数据形成一棵树。树中的数据元素之间的逻辑关系是一对多的。
所以树也属于数据结构的一种类型,其实树就是n个结点的有限集,当n=0的时候,此时树就被称为空树,如果是一颗非空树应该满足以下两个条件:
任意的非空树中有且只有一个特定的结点,该结点被称为根或称为根结点,也就是n = 1。(必须有一个根结点)
当n>1的时候,其余的结点可以分为m个(m>1)互不相交的有限集 T1、T2、T3.........Tm ,每个集合也被称为一棵树,就是根的子树。
对于树状结构,除了根结点之外,其余的结点都可以分为多个不相交的子树。
如果一个结点有子树,则该结点就被称为子树的“双亲”,该结点的子树就被称为结点的“孩子”,另外,具有相同结点的子树就被称为“兄弟”。从根结点到某个结点的路径上的所有结点,都被称为该结点的“祖先”,另外,以某个结点为根的子树中的所有结点都被称为该结点的“子孙”。
树是分层结构,一般把树的根结点称为第一层,其余的子结点的层次就是在上一层的基础上+1,另外一般把树的最大层数称为树的深度,树的深度也被称为树的高度。
一般把一个结点拥有子树的数量称为结点的度,把度为0的结点称为叶子结点,把度不为0的结点称为分支结点,也就是除了叶子结点之外的结点都是分支结点。

可以看到,结点A的度是2,结点B的度是1,结点H的度是2,结点C的度是3。结点D、E、F、G、I都是叶子结点,对于A、B、H、C都是分支结点。
二、二叉树
二叉树是一种树状结构,二叉树的特点就是每个结点至多有两颗子树(每个结点的度不会超过2),并且二叉树的子树是有左右之分,如果有两颗子树,就分别叫做左子树和右子树,而且二叉树的子树是有次序的,不能随意更改的,所以二叉树也属于有序树,也就意味着哪怕二叉树只有一个子树,也要区分到底是左子树还是右子树。
二叉树也是n个(n>=0)结点的有限集,一般二叉树有5种形式,分别是空树、根结点(ROOT)、有根结点和左子树以及右子树、左子树(Left Child Tree)、右子树(Right Child Tree)。如图所示。

斜树
一般只有左子树的二叉树被称为左斜树,一般只有右子树的二叉树被称为右斜树,可以看到斜树退化为线性结构,所以斜树是没有体现二叉树的性能。

满二叉树
一颗高度为h的二叉树,树的结点个数为 2h - 1个就被称为满二叉树,满二叉树所有的结点的度都是2,也就是每个结点都是有左子树和右子树,满二叉树的叶子结点的数量是最多的。另外,叶子结点都集中最下面一层。

完全二叉树
对于一颗树而言,完全二叉树指的是只有树的最下面2层的结点的度可以小于2,并且结点的编号也是按照从上到下,从左到右的顺序进行排列,最下面一层的叶子结点都连续集中在左树。

可以知道满二叉树一定是完全二叉树,但是完全二叉树不一定是满二叉树。
二叉查找树
二叉查找树,即BST树(Binary Search Tree),一般也被称为二叉搜索树或者二叉排序树,二叉查找树的结点是有键值key的,如果二叉查找树不是空树则需要遵循以下的特点:
1.如果二叉查找树有左子树,则左子树的结点的键值key要小于左子树的根结点的键值key
2.如果二叉查找树有右子树,则右子树的结点的键值key要大于右子树的根结点的键值key
3.对于二叉查找树而言,左子树和右子树也分别是二叉查找树。

可以看到,左子树的结点的键值都是小于右子树,二叉查找树的结点的键值key是不重复的。
平衡二叉树
平衡二叉树也是有序树,指的是树中任一结点的左子树和右子树的深度之差不超过1,如下图所示:

三、二叉树的性质
性质1:非空二叉树中的叶子结点数量等于双分支结点数量+1,双分支结点指的是就是度为2的结点,假设二叉树的叶子结点数量为n0,二叉树中单分支结点的数量为n1,二叉树中双分支结点的数量为n2,则二叉树中结点的总数 = n0 + n1 + n2。
性质2:二叉树的第i层上最多有2^(i-1)(i≥1)个结点,因为二叉树结点最多的情况就是满二叉树。
性质3:高度为h的二叉树最多有2^(h) -1(h≥1)个结点。满二叉树就是结点最多的二叉树,所以换句话说,满二叉树前h层结点的数量为(2^h)-1(h≥1)。
四、二叉树的存储结构
(1)顺序结构
二叉树的顺序结构就是采用一组地址连续的内存单元(数组)按照从上到下,从左到右的顺序依次存储二叉树中的结点,也就是把二叉树中编号为i的结点存储在数组下标为i-1的元素空间中。
如果按照二叉树的性质而言,满二叉树以及完全二叉树使用顺序存储比较合适,好处是可以最大程序的节约内存空间,并且可以利用数组下标查找数据。
对于一般的二叉树而言,也可以使用顺序结构进行存储,为了可以使用数组来表示结点的逻辑关系,需要数组的一些元素空间来存储空结点,会导致浪费空间。0表示不存在的空结点。

(2)链式结构
链式结构就可以有效的解决数组中存储空结点的问题,链式结构不受内存的限制,由于一个结点最多可能存在两个子结点,所以应该采用双向不循环链表的方案来实现。

五、二叉树的遍历方案
对于二叉树的遍历,指的是从根结点出发,依次访问二叉树中所有的结点,每个结点只会被访问一次,一共提供了三种方案实现二叉树结点的遍历:前序遍历、中序遍历、后序遍历。
(1)前序遍历(根结点--->左子树--->右子树)

输出顺序: A B D G H C E I F
(2)中序遍历(左子树--->根结点--->右子树)

输出顺序:G D H B A E I C F
(3)后序遍历(左子树--->右子树--->根结点)

输出顺序: G H D B I E F C A
作者:bbzhu04@gmail.com ,多有不妥之处,望批评指正
本文原创,欢迎转载;转载请在文章显著位置标明原文链接: href="https://www.cnblogs.com/zhubb/p/21972068"
保留所有权限,未经许可禁止篡改、商用发布。

浙公网安备 33010602011771号