1.二叉树
由节点组成,并且每个节点最多有两个子节点,分别称为左子节点和右子节点,不存在子节点的节点称为叶子节点。二叉树常见的遍历方式有前序遍历、中序遍历以及后序遍历。前序遍历先遍历根节点,然后遍历左子树和右子树;中序遍历先遍历左子树,然后遍历根节点和右子树;后序遍历先遍历左子树和右子树,最后遍历根节点。
2.满|完全二叉树
如果该二叉树的所有叶子节点都在最后一层,并且结点总数=2^n-1,n 为层数,则我们称为满二叉树。
如果该二叉树的所有叶子节点都在最后一层或者倒数第二层,而且最后一层的叶子节点在左边连续,倒数第二层的叶子节点在右边连续,我们称为完全二叉树。
3.二叉树遍历
三种方式:
- 1.前序遍历
- 2.中序遍历
- 3.后序遍历
注:根据根节点的输出顺序,判断是前中后遍历~
3.1.前序遍历
前序遍历:先访问根节点,再访问左子树,最后访问右子树
1.思路分析
- 1.先输出当前节点(根节点)
- 2.若左子节点不为空,则递归继续遍历
- 3.若右子节点不为空,则递归继续遍历
2.代码实战
/**
* 前序遍历
*/
public void preOrder() {
System.out.println(this);//先输出根节点
//向左子节点递归
if (this.left != null) {
this.left.preOrder();
}
//向右子节点递归
if (this.right != null) {
this.right.preOrder();
}
3.2.中序遍历
中序遍历:先遍历左子树,再输出根节点,再遍历右子树
1.思路分析
1.若当前节点的左子节点不为空,则递归遍历
2.输出当前节点(根节点)
3.若当前节点的左子节点不为空,则递归遍历
2.代码实战
/**
* 中序遍历
*/
public void infixOrder() {
//先递归左子节点遍历
if (this.left != null) {
this.left.infixOrder();
}
//输出当前节点
System.out.println(this);
//递归右子节点遍历
if (this.right != null) {
this.right.infixOrder();
}
3.3.后序遍历
后序遍历:先遍历左子树,再遍历右子树,最后输出根节点
1.思路分析
1.若当前节点的左子节点不为空,则递归遍历
2.若当前节点的右子节点不为空,则递归遍历
3.输出当前节点(根节点)
2.代码实战
/**
* 后序遍历
*/
public void postOrder() {
if (this.left != null) {
this.left.postOrder();
}
if (this.right != null) {
this.right.postOrder();
}
System.out.println(this);
}
3.4创建二叉树遍历
/**
* 定义一个二叉树
*/
class Tree {
private HeroNode root;
public void setRoot(HeroNode root) {
this.root = root;
}
//前序遍历
public void preOrder() {
if (this.root != null) {
this.root.preOrder();
} else {
System.out.println("当前二叉树为空无法遍历");
}
}
//中序遍历
public void infixOrder() {
if (this.root != null) {
this.root.infixOrder();
} else {
System.out.println("当前二叉树为空无法遍历");
}
}
public void postOrder() {
if (this.root != null) {
this.root.postOrder();
} else {
System.out.println("当前二叉树为空无法遍历");
}
}
}
4.查找指定节点
三种方式:
- 1.前序查找
- 2.中序查找
- 3.后序查找
注:后序查找相对比较快一点~
4.1.前序查找
1.思路分析
- 1.判断当前节点是否是要查找的
- 2.若相等,则返回
- 3.若不相等,则判断当前节点的左子节点是否为空,不为空,向左递归查找
- 4.若左递归找到,则返回。否则继续判断当前节点的右子节点是否为空,若不为空,则向右递归
2.代码实现
/**
* 前序查找
*/
public HeroNode preOrderSearch(int no) {
//判断当前节点是否相等
if (this.no == no) {
return this;
}
//定义变量,接收递归返回值
HeroNode tempNode = null;
//判断左子节点是否为空,向左子节点递归
if (this.left != null) {
tempNode = this.left.preOrderSearch(no);
}
//说明左递归找到
if (tempNode != null) {
return tempNode;
}
//左递归未找到,判断右子节点是否为空,并向右递归
if (this.right != null) {
tempNode = this.right.preOrderSearch(no);
}
return tempNode;
}
4.2.中序查找
1.思路分析
1.判断当前节点的左子节点是否为空,若不为空,则向左递归
2.如果找到,则返回;
3.如果没有找到,则和当前节点比较,如果相等,则返回当前接节点,否则继续右递归
4.如果右递归找到,则返回,否则返回null
2.代码实现
/**
* 中序查找
*/
public HeroNode infixOrderSearch(int no) {
HeroNode tempNode = null;
//判断当前节点的左子节点是否为空,并递归
if (this.left != null) {
tempNode = this.left.infixOrderSearch(no);
}
//判断是否找到
if (tempNode != null) {
return tempNode;
}
//未找到,判断当前节点是否相等
if (this.no==no){
return this;
}
//不等,判断右子节点是否为空,向有递归
if (this.right!=null){
tempNode=this.right.infixOrderSearch(no);
}
return tempNode;
}
4.3.后序查找
1.思路分析
1.判断当前节点的左子节点是否为空,如果不为空,则左递归查找
2.如果找到,则返回,如果没有找到,判断当前接待的右子节点是否为空,如果不为空,则有递归查找,如果找到,则返回
3.如果有递归没有找到,就和当前节点比较,找到则返回,否则返回null
2.代码实现
/**
* 后序查找
*/
public HeroNode postOrderSearch(int no){
HeroNode tempNode=null;
//判断当前节点的左子节点
if (this.left!=null){
tempNode=this.left.postOrderSearch(no);
}
//判断是否找到
if (tempNode!=null){
return tempNode;
}
//未找到,判断右子节点是否为空,并递归
if (this.right!=null){
tempNode=this.right.postOrderSearch(no);
}
//判断有递归是否找到
if (tempNode!=null){
return tempNode;
}
//左右均未找到,比较当前节点
if (this.no==no){
return this;
}
return tempNode;
}
4.4创建二叉树查找
/**
* 定义一个二叉树
*/
class Tree {
private HeroNode root;
public void setRoot(HeroNode root) {
this.root = root;
}
//前序查找
public HeroNode preOrderSearch(int no) {
if (this.root != null) {
return this.root.preOrderSearch(no);
} else {
return null;
}
}
//中序查找
public HeroNode infixOrderSearch(int no) {
if (this.root != null) {
return this.root.infixOrderSearch(no);
} else {
return null;
}
}
//后序查找
public HeroNode postOrderSearch(int no) {
if (this.root != null) {
return this.root.postOrderSearch(no);
} else {
return null;
}
}
}
5.删除节点
- 如果删除的节点是叶子节点,则删除该节点
- 如果删除的节点是非叶子节点,则删除该子树
5.1思路分析
- 1.当前二叉树是单向的,判断当前节点的子节点是否是要删除的节点,而不能判断,当前节点是不是要删除的
- 2.如果当前节点的左子节点不为空,并且左子节点就是我们要删除的,就将this.left=null,并返回,结束;否则看右子节点
- 3.如果当前节点的右子节点不为空,并且右子节点就是要删除的节点,就将this.rigth=null,并返回,结束;
- 4.如果第二步,第三步递归都没有删除,则需要向左子树递归删除,如果左递归没有删除,则向右子树递归删除
5.2代码实现
/**
* 递归删除节点
*/
public void deleteNode(int no) {
//当前节点的左子节点不为空,并且是要删除的节点,则置为空
if (this.left != null && this.left.no == no) {
this.left = null;
return;
}
//当前节点的右子节点不为空,并且是要删除的节点,则置为空
if (this.right != null && this.right.no == no) {
this.right = null;
return;
}
//向左子树递归
if (this.left != null) {
this.left.deleteNode(no);
}
//向右子树递归
if (this.right != null) {
this.right.deleteNode(no);
}
}
5.3创建二叉树删除
/**
* 定义一个二叉树
*/
class Tree {
private HeroNode root;
public void setRoot(HeroNode root) {
this.root = root;
}
//删除指定节点
public void deleteNode(int no) {
if (this.root != null) {
//如果只有一个root节点,判断root是否是要删除的
if (root.getNo() == no) {
root = null;
return;
}else {
root.deleteNode(no);
}
} else {
System.out.println("空树无法删除");
}
}
}
6.顺序存储二叉树
顺序存储二叉树,也称为顺序存储结构,是一种二叉树的存储方法。在顺序存储结构中,将二叉树的节点按照层次顺序存储在一个数组中,使得二叉树的节点可以用数组元素来表示。通常采用广义表的形式将整棵树存储在一个一维数组中,而且该数组满足完全二叉树的特性。
1.数组方式存放arr=【1,2,3,4,5,6,7】
2.依然可以使用前序、中序、后序遍历
6.1顺序存储二叉树的特点
- 顺序二叉树通常只考虑完全二叉树
- 第n个元素的左子节点为2*n+1
- 第n个元素的右子节点为2*n+2
- 第n个元素的父节点为(n-1)/2
注:n表示二叉树中的第几个元素(下标从0开始)
6.2代码实现
/**
* 创建二叉树,实现顺序存储
*/
class ArrTree {
private int[] arr;
public ArrTree(int[] arr) {
this.arr = arr;
}
//前序存储二叉树
public void preOrder(int index) {
//如果数组为空 或者 arr.length==0
if (arr == null || arr.length == 0) {
System.out.println("数组为空,无法使用前序遍历");
}
System.out.println(arr[index]);
//向左递归
if ((index * 2 + 1) < arr.length) {
preOrder(index * 2 + 1);
}
//向右递归
if ((index * 2 + 2) < arr.length) {
preOrder(index * 2 + 2);
}
}
//中序存储二叉树
public void infixOrder(int index) {
if (arr == null || arr.length == 0) {
System.out.println();
}
if ((index * 2 + 1) < arr.length) {
infixOrder(index * 2 + 1);
}
System.out.println(arr[index]);
//向右递归
if ((index * 2 + 2) < arr.length) {
preOrder(index * 2 + 2);
}
}
//后序存储二叉树
public void postOrder(int index) {
if (arr == null || arr.length == 0) {
System.out.println();
}
if ((index * 2 + 1) < arr.length) {
infixOrder(index * 2 + 1);
}
//向右递归
if ((index * 2 + 2) < arr.length) {
preOrder(index * 2 + 2);
}
System.out.println(arr[index]);
}
}