数据结构与算法—树1
声明:以下是学的尚硅谷网课并结合网上资料所记的笔记。可能会有一些错误,发现了会修改。
树的介绍
概念
树是一种数据结构,它是由n(n>=1)个有限节点组成一个具有层次关系的集合。把它叫做“树”是因为它看起来像一棵倒挂的树,也就是说它是根朝上,而叶朝下的。它具有以下的特点:每个节点有零个或多个子节点;没有父节点的节点称为根节点;每一个非根节点有且只有一个父节点;除了根节点外,每个子节点可以分为多个不相交的子树。
注: 每个节点是一个对象,可以放id,name等信息。
种类
- 无序树:树中任意节点的子结点之间没有顺序关系,这种树称为无序树,也称为自由树;
- 有序树:树中任意节点的子结点之间有顺序关系,这种树称为有序树;
- 二叉树:每个节点最多含有两个子节点的树称为二叉树;
- 满二叉树:所有叶子节点在最后一层,且节点总数为 2k-1 ,k为层数;
- 完全二叉树:二叉树的所有叶子节点在最后一层或倒数第二层,最后一层的叶子节点在左边连续,倒数第二层叶子节点在右边连续;
- 哈夫曼树(最优二叉树):带权路径最短的二叉树称为哈夫曼树或最优二叉树;
作用
可提高数据存储、读取的效率。比如二叉排序树,既可以保证数据的检索速度,也保证数据的增删改速度。其查找有点像二分查找,添加和删除时效率高,找到父节点对其left或right指针操作即可。
二叉树
二叉树:每个节点最多只能有两个子节点的一种形式的树,二叉树子节点可分为左节点和右节点。如图1所示为一个二叉树。
H,E,F,G没有子节点,为叶子节点。C是F、G的父节点,是A的子节点。
常用术语:
- 节点,根节点,父节点,子节点,叶子节点(没有子节点的节点);
- 节点的权(节点的值);
- 路径(从root节点找到某个节点的路线);
- 层,子树;
- 树的高度(最大层数);
- 森林(多颗子树构成森林)。
前序、中序、后序遍历
前序遍历: (1)先输出当前节点(初始为root节点);(2)如果左子节点不为空,则继续前序遍历;(3)如果右子节点不为空,则递归继续前序遍历。图一的前序遍历结果为: A->B->D->H->E->C->F->G。代码如下:
public void preOrder(){
//先输出父节点
System.out.println(this);
//递归向左子树前序遍历
if(this.left != null){
this.left.preOrder();
}
//递归向右子树前序遍历
if(this.right != null){
this.right.preOrder();
}
}
中序遍历:(1)如果当前节点的左子节点不为空,则递归中序遍历;(2)输出当前节点;(3)如果当前节点的右子节点不为空,则递归中序遍历。图一的中序遍历结果为: D->H->B->E->A->F->C->G。代码如下:
public void infixOrder(){
//递归向左子树中序遍历
if(this.left != null){
this.left.infixOrder();
}
//输出父节点
System.out.println(this);
//递归向右子树中序遍历
if(this.right != null){
this.right.infixOrder();
}
}
后序遍历:(1)如果当前节点的左子节点不为空,则递归后序遍历;(2)如果当前节点的右子节点不为空,则递归后序遍历;(3)输出当前节点。图一的后序遍历结果为: H->D->E->B->F->G->C->A。代码如下:
public void postOrder(){
//递归向左子树后序遍历
if(this.left != null){
this.left.postOrder();
}
//递归向右子树后序遍历
if(this.right != null){
this.right.postOrder();
}
//输出父节点
System.out.println(this);
}
前序、中序还是后序遍历可以根据父节点的输出位置来判断。
前序、中序、后序查找
前序查找思路:(1)先判断当前节点的值是否为要查找的,如果相等,返回当前节点;(2)如果不相等,判断当前节点的左子节点是否为空,不为空,则递归前序查找;(3)如果左递归查找没有找到节点,则判断当前节点的右子节点是否为空,不为空,则递归向右前序查找。
public Node preOrderSearch(int no){
if(this.no == no){ //比较当前节点是否为要查找的节点
return this;
}
Node resNode = null;
if(this.left != null){ //向左查找
resNode = this.left.preOrderSearch(no);
}
if(resNode != null){ //找到了
return resNode;
}
if(this.right != null){ //向右查找
resNode = this.right.preOrderSearch(no);
}
return resNode;
}
中序、后序查找类似,只是顺序不同。
节点的删除
思路:
- 如果只有root,等价于将二叉树置空。还要考虑树是否为空树。(首先处理)
- 判断当前节点的子节点是否为需要删除的节点,而不是判断当前节点;
- 如果当前节点的左子节点不为空,且为要删除的节点,将
this.left == null
,并返回(结束递归); - 如果当前节点的右子节点不为空,且为要删除的节点,将
this.right == null
,并返回(结束递归); - 第2,3步都没有删除节点,需要向左子树递归删除;
- 如果第4步也没有完成,则应向右子树递归删除;
--------------------------------------- 个人学习笔记----------------------------------------