- 树
- 树的定义
- 树的结点相关概念
- 二叉树
- 二叉树的定义
- 满二叉树
- 完全二叉树
- 二叉树的性质
- 完全二叉树的两个特性
- 二叉树的存储结构
- 遍历二叉树
- 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语言版)》 严蔚敏