- 树
-
- 树的定义
- 树的结点相关概念
- 二叉树
-
- 二叉树的定义
-
- 满二叉树
- 完全二叉树
- 二叉树的性质
-
- 完全二叉树的两个特性
- 二叉树的存储结构
- 遍历二叉树
-
- Java实现
树是 n ( N ≥ 0 ) \mathrm{n(N\ge0)} n(N≥0)个结点的有限集。在任意一棵非空树中,
(1)有且仅有一个特定的结点(root),称为根
(2)当 n > 1 \mathrm{n>1} n>1时,其余结点可以分为 m ( m > 0 ) \mathrm{m(m>0)} m(m>0) 个互不相交的有限集,每一个集合本身也是一棵树,并且这些有限集称为根的子树。
树的结点相关概念树的结构是一个递归结构。
树的结点包含一个数据元素及若干指向其子树的分支。
结点拥有的子树的个数称为结点的度(Degree)。
度为0的节点称为叶子或者终端结点。
度不为0的结点称为非终端结点或者分支结点。
除了根结点之外的分支结点也成为内部结点。
树的度是树内各结点的度的最大值。
结点子树的根称为这个结点的孩子。
该结点也称为孩子的双亲。
同一个双亲的孩子之间互称为兄弟。
节点的祖先是从根结点到该结点所经分支上所有的节点。
以某节点为根的子树中的任一结点都称为该结点的子孙。
结点的层次,从根开始为第一层,根的孩子为第二层,层次以此类推。
双亲在同一层的节点互为堂兄弟
树中最大的层次为树的深度(depth)或高度。
有序树 树中结点的各子树从左至右是有次序的,且不能互换,
无序树 不满足有序数条件就是无序树。
二叉树 二叉树的定义二叉树是另一种树型结构,每个结点至多有两棵子树,子树有左右之分,次序不可以变。
二叉树的5种形态
- 空二叉树
- 仅有根结点的二叉树
- 右子树为空的二叉树
- 左子树为空的二叉树
- 左、右子树均非空的二叉树
一棵深度为 k \mathrm{k} k 且有 2 k − 1 \mathrm{2^k-1} 2k−1的个结点的二叉树,编号方式:从根开始自上而下,自左而右累加编号。
深度为 k
\mathrm{k} k 的,有 n
\mathrm{n} n 个节点的二叉树,当且仅当其每一个结点都与深度为 k
\mathrm{k} k 的满二叉树中编号从1至 n
\mathrm{n} n的结点意义对应时,称为完全二叉树。
- 在二叉树的第 i \mathrm{ i } i 层上最多有 2 i − 1 \mathrm{ 2^{i-1}} 2i−1个结点( i ≥ 1 \mathrm{i\geq1} i≥1)。
- 深度为 k \mathrm{ k } k 的二叉树至多有 2 k − 1 \mathrm{2^k-1} 2k−1个节点( k ≥ 1 \mathrm{k\geq1} k≥1)。
- 对任何一颗二叉树 T \mathrm{ T } T,如果其终端节点数为 n 0 \mathrm{n_0} n0,度为2的节点数为 n 2 \mathrm{n_2} n2,则 n 0 = n 2 + 1 \mathrm{n_0=n_2+1} n0=n2+1。
- 具有 n \mathrm{ n } n个节点的完全二叉树的深度为 ⌊ l o g 2 n ⌋ + 1 \mathrm{\left \lfloor log_2 n\right \rfloor+1} ⌊log2n⌋+1,按层序编号,编号为i的结点的层次在 ∣ l o g 2 i ∣ + 1 \mathrm{ \left| log_2^i \right|+1} ∣∣log2i∣∣+1
- 一棵深度为 k \mathrm{ k } k 的完全二叉树至少有 2 k − 1 \mathrm{2^{k-1}} 2k−1的节点,至多 2 k − 1 \mathrm{2^k-1} 2k−1个结点。
-
顺序存储结构
使用一组地址连续的存储单元依次自上而下、自左而右存储完全二叉树上的结点元素,即将完全二叉树上编号为 i \mathrm{ i } i 的结点元素存储在如上定义的一维数组下标为 i − 1 \mathrm{ i-1 } i−1 的分量中。这个存储结构仅仅适用完全二叉树,在最坏的情况下,一个深度为 k \mathrm{ k } k 且只有 k \mathrm{ k } k 个节点的单支树(树中不存在度为2的结点)。
-
链式存储结构
结点结构的不同,会构成不同的链式存储结构,由二叉树的定义可知,二叉树的结点拥有一个数据域和分别指向左右指针域,这种结构成为二叉链表,为了快速找到结点的双亲,会在结点结构上增加一个双亲指针域,这的结构称为三叉链表。
二叉树结点
含有两个指针域的结点机结构
含有三个指针域的结点机结构
遍历指,每个结点有且仅被访问一次
-
先序遍历
先判断空,若不为空则
- 访问根节点;
- 先序遍历左子树;
- 先序遍历右子树。
-
中序遍历
先判断空,若不为空则
- 中序遍历左子树;
- 访问根节点;
- 中序遍历右子树。
-
后序遍历
先判断空,若不为空则
- 后序遍历左子树;
- 后序遍历右子树;
- 访问根节点。
package tree; public class TreeNode { /** * 节点上的值 */ private int value; /** * 左节点 */ private TreeNode left; /** * 右节点 */ private TreeNode right; public TreeNode() { } public TreeNode(TreeNode left, TreeNode right, int value) { this.left = left; this.right = right; this.value = value; } public TreeNode(int value) { this.value = value; } public int getValue() { return value; } public void setValue(int value) { this.value = value; } public TreeNode getLeft() { return left; } public void setLeft(TreeNode left) { this.left = left; } public TreeNode getRight() { return right; } public void setRight(TreeNode right) { this.right = right; } }
package tree; import org.apache.commons.lang.StringUtils; /** * 遍历二叉树 */ public class TraversalBinaryTree { public static final StringBuilder VALUES = new StringBuilder(); public static final String SEPARATOR = "->"; public static final int SEPARATOR_LENGTH = SEPARATOR.length(); /** * 先序遍历 */ public static String prefaceReadTree(TreeNode tree) { String result = ""; if (null != tree) { VALUES.append(tree.getValue()).append(SEPARATOR); prefaceReadTree(tree.getLeft()); prefaceReadTree(tree.getRight()); } if (StringUtils.isNotBlank(VALUES.toString())) { result = VALUES.substring(0, VALUES.toString().length() - SEPARATOR_LENGTH); } return result; } /** * 中序遍历 */ public static String inorderReadTree(TreeNode tree) { String result = ""; if (null != tree) { inorderReadTree(tree.getLeft()); VALUES.append(tree.getValue()).append(SEPARATOR); inorderReadTree(tree.getRight()); } if (StringUtils.isNotBlank(VALUES.toString())) { result = VALUES.substring(0, VALUES.toString().length() - SEPARATOR_LENGTH); } return result; } /** * 后序遍历 */ public static String postorderReadTree(TreeNode tree) { String result = ""; if (null != tree) { postorderReadTree(tree.getLeft()); postorderReadTree(tree.getRight()); VALUES.append(tree.getValue()).append(SEPARATOR); } if (StringUtils.isNotBlank(VALUES.toString())) { result = VALUES.substring(0, VALUES.toString().length() - SEPARATOR_LENGTH); } return result; } }
package tree; public class Client { public static void main(String[] args) { String result = ""; TreeNode treeNode = init(); result = TraversalBinaryTree.prefaceReadTree(treeNode); System.out.println("先序结果=" + result); TraversalBinaryTree.VALUES.delete(0, result.length() + 2); result = TraversalBinaryTree.inorderReadTree(treeNode); System.out.println("中序结果=" + result); TraversalBinaryTree.VALUES.delete(0, result.length() + 2); result = TraversalBinaryTree.postorderReadTree(treeNode); System.out.println("后序结果=" + result); } /** * 构建如下的二叉树,同时是个满二叉树 * 1 * / \ * 2 3 * / \ / \ * 4 5 6 7 */ public static TreeNode init() { TreeNode root = new TreeNode(1); TreeNode treeNode2 = new TreeNode(2); TreeNode treeNode3 = new TreeNode(3); root.setLeft(treeNode2); root.setRight(treeNode3); TreeNode treeNode4 = new TreeNode(4); TreeNode treeNode5 = new TreeNode(5); TreeNode treeNode6 = new TreeNode(6); TreeNode treeNode7 = new TreeNode(7); treeNode2.setLeft(treeNode4); treeNode2.setRight(treeNode5); treeNode3.setLeft(treeNode6); treeNode3.setRight(treeNode7); return root; } }
先序结果=1->2->4->5->3->6->7 中序结果=4->2->5->1->6->3->7 后序结果=4->5->2->6->7->3->1
参考
- 《数据结构 (C语言版)》 严蔚敏