一,树
1.1 概念
它具有以下的特点:
- 有一个特殊的结点,称为根结点,根结点没有前驱结点
- 除根结点外,其余结点被分成M(M > 0)个互不相交的集合T1、T2、......、Tm,其中每一个集合Ti (1 <= i <= m) 又是一棵与树类似的子树。每棵子树的根结点有且只有一个前驱,可以有0个或多个后继
- 树是递归定义的。
树中常用的一些概念:
结点的度 :一个结点含有子树的个数称为该结点的度;树的度 :一棵树中,所有结点度的最大值称为树的度;叶子结点或终端结点 :度为 0 的结点称为叶结点;双亲结点或父结点 :若一个结点含有子结点,则这个结点称为其子结点的父结点;孩子结点或子结点 :一个结点含有的子树的根结点称为该结点的子结点;根结点 :一棵树中,没有双亲结点的结点;结点的层次 :从根开始定义起,根为第 1 层,根的子结点为第 2 层,以此类推树的高度或深度 :树中结点的最大层次;非终端结点或分支结点 :度不为 0 的结点;兄弟结点 :具有相同父结点的结点互称为兄弟结点;堂兄弟结点 :双亲在同一层的结点互为堂兄弟;结点的祖先 :从根到该结点所经分支上的所有结点;子孙 :以某结点为根的子树中任一结点都称为该结点的子孙。森林 :由 m ( m>=0 )棵互不相交的树组成的集合称为森林
1.3 树的表示形式(了解)
树结构相对线性表就比较复杂了,要存储表示起来就比较麻烦了,实际中树有很多种表示方式,如: 双亲表示法 , 孩子表示法 、 孩子双亲表示法 、 孩子兄弟表示法 等等。我们这里就简单的了解其中最常用的 孩子兄弟表示法 。
一、双亲表示法
定义与原理:
- 用一组连续空间存储树的所有节点,同时在每个节点中,附设一个指示器指示其双亲节点在数组中的位置。
- 也就是说,每个节点除了存储自身的数据信息外,还存储一个指向其双亲节点的指针(在这种情况下,用数组下标来表示指针)
二、孩子表示法
定义与原理:
- 把每个节点的孩子节点排列成一个单链表,称为孩子链表。n 个节点有 n 个孩子链表,如果是叶子节点,则此单链表为空。然后,n 个头指针又组成一个线性表,采用顺序存储结构,存放进一个一维数组中。
- 这种存储方式便于查找某个节点的孩子节点。
三、孩子双亲表示法
定义与原理:
- 结合了双亲表示法和孩子表示法的特点,既存储每个节点的孩子链表,又存储每个节点的双亲位置。
四、孩子兄弟表示法
定义与原理:
- 又称二叉树表示法,以二叉链表作为树的存储结构。链表中每个节点设两个指针域,分别指向该节点的第一个孩子节点和下一个兄弟节点。
- 这种表示法使得任意一棵树都能转换为二叉树进行处理,方便实现各种树的操作。
二. 二叉树(重点)
2.1 概念
一棵二叉树是结点的一个有限集合,该集合:1. 或者为空2. 或者是由 一 个根节 点加上两棵别称为 左子树 和 右子树 的二叉树组成。
2.2 两种特殊的二叉树
1. 满二叉树 : 一棵二叉树,如果 每层的结点数都达到最大值,则这棵二叉树就是满二叉树 。也就是说, 如果一棵 二叉树的层数为 K ,且结点总数是 ,则它就是满二叉树 。2. 完全二叉树 : 完全二叉树是效率很高的数据结构,完全二叉树是由满二叉树而引出来的。对于深度为 K 的,有 n个结点的二叉树,当且仅当其每一个结点都与深度为K 的满二叉树中编号从 0 至 n-1 的结点一一对应时称之为完全二叉树。 要注意的是满二叉树是一种特殊的完全二叉树
2.3 二叉树的性质
1. 若规定 根结点的层数为 1 ,则一棵 非空二叉树的第 i 层上最多有2^(i-1)(i>0) 个结点2. 若规定只有 根结点的二叉树的深度为 1 ,则 深度为 K 的二叉树的最大结点数是(2^k) - 1(k>=0)3. 对任何一棵二叉树 , 如果其 叶结点个数为 n0, 度为 2 的非叶结点个数为 n2, 则有 n0 = n2 + 14. 具有 n 个结点的完全二叉树的深度 k 为 log 2(n+1) 上取整5. 对于具有 n 个结点的完全二叉树 ,如果按照 从上至下从左至右的顺序对所有节点从 0 开始编号 ,则对于 序号为 i 的结点有 :
- 若i>0,双亲序号:(i-1)/2;i=0,i为根结点编号,无双亲结点
- 若2i+1<n,左孩子序号:2i+1,否则无左孩子
- 若2i+2<n,右孩子序号:2i+2,否则无右孩子
二叉树的建立:
class TreeNode {int val;TreeNode left;TreeNode right;TreeNode(int val) {this.val = val;}
}public void insert(int value) {root = insertRec(root, value);}private TreeNode insertRec(TreeNode root, int value) {if (root == null) {return new TreeNode(value);}if (value < root.val) {root.left = insertRec(root.left, value);} else if (value > root.val) {root.right = insertRec(root.right, value);}return root;}
2.4 二叉树的遍历:
//前序递归实现:public void preorderTraversalRec(TreeNode root) {if (root == null) {return;}System.out.print(root.val + " ");preorderTraversalRec(root.left);preorderTraversalRec(root.right);}
//前序非递归实现:public void preorderTraversal(TreeNode root) {if (root == null) {return;}Stack<TreeNode> stack = new Stack<>();stack.push(root);while (!stack.isEmpty()) {TreeNode node = stack.pop();System.out.print(node.val + " ");if (node.right!= null) {stack.push(node.right);}if (node.left!= null) {stack.push(node.left);}}}
//中序递归实现:public void inorderTraversalRec(TreeNode root) {if (root == null) {return;}inorderTraversalRec(root.left);System.out.print(root.val + " ");inorderTraversalRec(root.right);}
//中序非递归实现:public void inorderTraversal(TreeNode root) {if (root == null) {return;}Stack<TreeNode> stack = new Stack<>();TreeNode current = root;while (current!= null ||!stack.isEmpty()) {while (current!= null) {stack.push(current);current = current.left;}current = stack.pop();System.out.print(current.val + " ");current = current.right;}}//后序递归实现:public void postorderTraversalRec(TreeNode root) {if (root == null) {return;}postorderTraversalRec(root.left);postorderTraversalRec(root.right);System.out.print(root.val + " ");}
//后序非递归实现:public void postorderTraversal(TreeNode root) {if (root == null) {return;}Stack<TreeNode> stack = new Stack<>();TreeNode prev = null;TreeNode current = root;while (current!= null ||!stack.isEmpty()) {while (current!= null) {stack.push(current);current = current.left;}current = stack.peek();if (current.right == null || current.right == prev) {System.out.print(current.val + " ");stack.pop();prev = current;current = null;} else {current = current.right;}}}
以下是总代码:
import java.util.Stack;
import java.util.LinkedList;
import java.util.Queue;class TreeNode {char val;TreeNode left;TreeNode right;TreeNode(char val) {this.val = val;}
}
public class MyTree {// 获取树中节点的个数public int size(TreeNode root) {if (root == null) {return 0;}return 1 + size(root.left) + size(root.right);}// 获取叶子节点的个数public int getLeafTreeNodeCount(TreeNode root) {if (root == null) {return 0;}if (root.left == null && root.right == null) {return 1;}return getLeafTreeNodeCount(root.left) + getLeafTreeNodeCount(root.right);}// 获取第 K 层节点的个数public int getKLevelTreeNodeCount(TreeNode root, int k) {if (root == null || k < 1) {return 0;}if (k == 1) {return 1;}return getKLevelTreeNodeCount(root.left, k - 1) + getKLevelTreeNodeCount(root.right, k - 1);}// 获取二叉树的高度public int getHeight(TreeNode root) {if (root == null) {return 0;}int leftHeight = getHeight(root.left);int rightHeight = getHeight(root.right);return Math.max(leftHeight, rightHeight) + 1;}// 检测值为 value 的元素是否存在public TreeNode find(TreeNode root, char val) {if (root == null) {return null;}if (root.val == val) {return root;}TreeNode leftResult = find(root.left, val);if (leftResult != null) {return leftResult;}return find(root.right, val);}// 层序遍历public void levelOrder(TreeNode root) {if (root == null) {return;}Queue<TreeNode> queue = new LinkedList<>();queue.add(root);while (!queue.isEmpty()) {TreeNode node = queue.poll();System.out.print(node.val + " ");if (node.left != null) {queue.add(node.left);}if (node.right != null) {queue.add(node.right);}}}// 判断一棵树是不是完全二叉树public boolean isCompleteTree(TreeNode root) {if (root == null) {return true;}Queue<TreeNode> queue = new LinkedList<>();queue.add(root);boolean flag = false;while (!queue.isEmpty()) {TreeNode node = queue.poll();if (node.left != null) {if (flag) {return false;}queue.add(node.left);} else {flag = true;}if (node.right != null) {if (flag) {return false;}queue.add(node.right);} else {flag = true;}}return true;}// 前序递归实现public void preorderTraversalRec(TreeNode root) {if (root == null) {return;}System.out.print(root.val + " ");preorderTraversalRec(root.left);preorderTraversalRec(root.right);}// 前序非递归实现public void preorderTraversal(TreeNode root) {if (root == null) {return;}Stack<TreeNode> stack = new Stack<>();stack.push(root);while (!stack.isEmpty()) {TreeNode node = stack.pop();System.out.print(node.val + " ");if (node.right != null) {stack.push(node.right);}if (node.left != null) {stack.push(node.left);}}}// 中序递归实现public void inorderTraversalRec(TreeNode root) {if (root == null) {return;}inorderTraversalRec(root.left);System.out.print(root.val + " ");inorderTraversalRec(root.right);}// 中序非递归实现public void inorderTraversal(TreeNode root) {if (root == null) {return;}Stack<TreeNode> stack = new Stack<>();TreeNode current = root;while (current != null || !stack.isEmpty()) {while (current != null) {stack.push(current);current = current.left;}current = stack.pop();System.out.print(current.val + " ");current = current.right;}}// 后序递归实现public void postorderTraversalRec(TreeNode root) {if (root == null) {return;}postorderTraversalRec(root.left);postorderTraversalRec(root.right);System.out.print(root.val + " ");}// 后序非递归实现public void postorderTraversal(TreeNode root) {if (root == null) {return;}Stack<TreeNode> stack = new Stack<>();TreeNode prev = null;TreeNode current = root;while (current != null || !stack.isEmpty()) {while (current != null) {stack.push(current);current = current.left;}current = stack.peek();if (current.right == null || current.right == prev) {System.out.print(current.val + " ");stack.pop();prev = current;current = null;} else {current = current.right;}}}}public class Test233 {public static void main(String[] args) {MyTree tree = new MyTree();TreeNode root = new TreeNode('A');root.left = new TreeNode('B');root.right = new TreeNode('C');root.left.left = new TreeNode('D');root.left.right = new TreeNode('E');System.out.println("前序遍历:");tree.preorderTraversalRec(root);System.out.println();System.out.println("中序遍历:");tree.inorderTraversal(root);System.out.println();System.out.println("后序遍历:");tree.postorderTraversal(root);System.out.println();TreeNode found = tree.find(root, 'A');if (found!= null) {System.out.println("找到了值为 A的节点");} else {System.out.println("未找到值为 A 的节点");}int treeHeight = tree.getHeight(root);System.out.println("树的高度为:" + treeHeight);}
}