文章目录
树
1 为什么要用树结构
- 数组的存储方式分析
优点:可以通过下标来访问元素,速度快,还可以是用二分查找提高检索速度。
缺点:如果检索某个具体的值,或者插入值会整体移动,效率较低。
- 链式存储方式的分析
优点:插入结点与删除结点效率比较高,只需要断开再连接就行了。
缺点:在进行检索时,效率仍然较低,每次需要从头结点开始遍历查找。 - 树存储方式的分析
可以提高数据存储,读取的效率,比如利用二叉排序树,既可以保证数据的检索速度,同时也可以保证数据的插入,删除,修改的速度。
2 树的示意图
树的常用术语:
4. 节点
5. 根节点
6. 父节点
7. 子节点
8. 叶子节点
9. 节点的权(节点值)
10. 路径(从root节点找到该节点的路线)
11. 层
12. 子树
13. 数的高度(最大层数)
14. 森林(多颗子树构成森林)
3 二叉树的概念
- 树有很多种,每个节点最多只能由两个子节点的一种形式成为二叉树。
- 示意图
- 如果该二叉树的所有叶子节点都在最后一层,并且节点总数为2^n-1,n为层数,那我们称之为满二叉树。
- 如果该二叉树的所有叶子节点都在最后一层或者倒数第二层,而且最后一层叶子节点在左边连续,倒数第二层的叶子节点在右边连续,我们称之为完全二叉树。
4 二叉树的创建
4.1 二叉树的结点类
根据我们对图的观察,可以发现二叉树就是由一个一个结点以及他们之间的关系组成的。每一个结点有一个左结点和右结点(都可以为空)。
节点类API设计:
代码实现
在这里插入代码片
5 二叉树的遍历
5.1 前序遍历与前序查找
前序遍历:
先输出根节点,再对左子节点继续进行前序遍历,然后对右子节点进行前序遍历。翻译:先输出根节点,若根节点的左子节点不是空则输出左子节点,继续往下走一直输出左子节点,一直到左子节点为空,然后输出右子节点;兄弟节点之间必定先输出左边的兄弟节点。
//前序遍历
public void preShow(TreeNode x){
System.out.println(x);
if(x.leftNode!=null){
preShow(x.leftNode);
}
if(x.rightNode!=null){
preShow(x.rightNode);
}
}
前序查找代码:
//前序遍历查找指定结点
public TreeNode queryNode(int key){
if(this.key==key){
return this;
}
TreeNode treeNode = null;
if(this.leftNode!=null){
treeNode = this.leftNode.queryNode(key);
}
if(treeNode!=null){
return treeNode;
}
if(this.rightNode!=null){
treeNode = this.rightNode.queryNode(key);
}
return treeNode;
}
5.2 中序遍历
先对左子节点进行中序遍历,再输出根节点,然后对右节点进行中序遍历。翻译:一个节点,如果存着左子树,那必定先输出左子树,才能再输出自己,最后输出右子节点。
//中序遍历
public void midShow(TreeNode x){
if(x.leftNode!=null){
midShow(x.leftNode);
}
System.out.println(x);
if(x.rightNode!=null){
midShow(x.rightNode);
}
}
5.3 后序遍历
先对左子节点进行后续遍历,然后对右结点进行后续遍历,最后输出根节点。翻译:一个结点若存在左子树或右子树,那必先输出它的左子树再输出它的右子树,最后才能输出它自己。
//后序遍历
public void afterShow(TreeNode x){
if (x.leftNode!=null) {
afterShow(x.leftNode);
}
if(x.rightNode!=null){
afterShow(x.rightNode);
}
System.out.println(x);
}
6 删除节点
7 顺序存储二叉树
7.1 顺序存储二叉树的基本说明
数组的存储和树的存储方式可以相互转换,及数组可以转换成树,树可以转换成数组。
要求在遍历数组的时候,仍然可以前序遍历中序遍历和后续遍历。
7.2 顺序存储二叉树的特点
- 顺序存储二叉树通常只考虑完全二叉树
- 第n(指索引)个结点的左子节点的索引为2*n+1
- 第n个节点的右子节点的索引为2*n+2
- 第n个结点的父节点为(n-1)/2