1. 为什么需要树这种数据结构?
-
数组存储方式的优缺点:
-
优点:可以直接通过下标访问元素,速度快。当是有序数组的时候,还可以使用二分查找提高查询的速度。即读取效率较高。
-
缺点:如果需要检索某个具体的值,或插入值的时候,数组会整体移动,这时候效率就较低。即存储效率较低
-
-
链式存储方式的优缺点:
-
优点:存储效率较高。例如在插入一个数值节点,只需要将插入节点链接到链表中就可以了,删除效率也较高。
-
缺点:检索效率较低,例如当需要检索某个值的时候,需要从头节点开始遍历。即读取效率较低
-
-
树存储方式
能够同时提高数据的存储和读取效率。例如二叉排序树,既可以保证数据的检索速度,同时可以保证数据的插入、删除、修改的速度。
2. 树的示意图和常用术语
2.1 树的示意图如下:
2.2 常用术语
-
节点。就是图中的ABCDEFGH对象
-
根节点
-
父节点
-
子节点
-
叶子节点(没有子节点的节点)
-
节点的权(节点的值)
-
路径(从root节点找到该节点的路线)
-
层(就是图中标注的1、2、3、4层)
-
树的高度(最大层数)
-
森林(多颗子树构成一个森林)
3. 二叉树
-
树的每个节点最多只能有两个子节点的树叫作二叉树。二叉树的子节点分为左节点和右节点。
-
如果二叉树的所有叶子节点都在最后一层,并且节点总数等于2^n - 1,其中n为层数,那么就称该树为满二叉树
- 如果二叉树的所有叶子节点都在最后一层或者倒数第二层,而且最后一层的叶子节点在左边连续,倒数第二层的叶子节点在右边连续,那么就称该树为完全二叉树。
4. 二叉树的遍历
-
前序遍历: 先输出父节点,再遍历左子树,最后遍历右子树
-
中序遍历: 先遍历左子树,再输出父节点,最后遍历右子树
-
后续遍历: 先遍历左子树,再遍历右子树,最后输出父节点
总结:看输出父节点的顺序,就确定是前序、中序还是后序。
5. 二叉树前序、中序、后序遍历的步骤
-
创建一颗二叉树
-
前序遍历
-
先输出当前节点(初始的时候是root节点)
-
如果左子节点不为空,则递归继续前序遍历
-
如果右子节点不为空,则递归继续前序遍历
-
-
中序遍历
-
如果当前节点的左子节点不为空,则递归中序遍历
-
输出当前节点
-
如果当前节点的右子节点不为空,则递归中序遍历
-
-
后序遍历
-
如果当前节点的左子节点不为空,则递归后序遍历
-
如果当前节点的右子节点不为空,则递归后序遍历
-
输出当前节点
-
6. 二叉树前序、中序、后序遍历的代码实现
-
创建一个节点,并在节点中实现前序、中序、后序遍历
//创建一个HeroNode节点 class HeroNode { private int no; private String name; private HeroNode left; private HeroNode right; public HeroNode(int no, String name) { this.no = no; this.name = name; } public int getNo() { return no; } public String getName() { return name; } public HeroNode getLeft() { return left; } public HeroNode getRight() { return right; } public void setNo(int no) { this.no = no; } public void setName(String name) { this.name = name; } public void setLeft(HeroNode left) { this.left = left; } public void setRight(HeroNode right) { this.right = right; } @Override public String toString() { return "HeroNode{" + "no=" + no + ", name='" + name + '\'' + '}'; } /** * 前序遍历的方法 */ public void preOrder() { System.out.println(this); //用递归,向左子树前序遍历 if (this.left != nul