package com.zzb.tree;
import java.io.Serializable;
/**
* @Auther: Administrator
* @Date: 2019/10/5 20:59
* @Description: 二叉树的
* 前序遍历
* 中序遍历
* 后序遍历
*
* 前序遍历查找指定节点
* 中序遍历查找指定节点
* 后序遍历查找指点节点
*
* 删除指定节点(删除规则:如果删除的节点是叶子节点,则删除该节点;如果删除的节点是非叶子节点,则删除该子树)
*
* 前序遍历: 先输出父节点,再遍历左子树和右子树
* 中序遍历: 先遍历左子树,再输出父节点,再遍历右子树
* 后序遍历: 先遍历左子树,再遍历右子树,最后输出父节点
* 小结: 看输出父节点的顺序,就确定是前序,中序还是后序
*
* 前序遍历步骤:(每个节点都会执行前序遍历方法中的三个动作,涉及到递归方法的压栈与弹栈)
* (1)输出当前节点(初始节点是根节点root节点)
* (2)判断如果当前节点的左子节点不为空,则当前节点的左子节点递归执行前序遍历方法进行前序遍历
* (3)判断如果当前节点的右子节点不为空,则当前节点的右子节点递归执行前序遍历方法进行前序遍历
*
* 中序遍历步骤:(每个节点都会执行中序遍历方法中的三个动作,涉及到递归方法的压栈与弹栈)
* (1)判断如果当前节点的左子节点不为空,则当前节点的左子节点递归执行中序遍历方法进行中序遍历
* (2)输出当前节点(初始节点是根节点root节点)
* (3)判断如果当前节点的右子节点不为空,则当前节点的右子节点递归执行中序遍历方法进行中序遍历
*
* 后序遍历步骤;(每个节点都会执行后序遍历方法中的三个动作,涉及到递归方法的压栈与弹栈)
* (1)判断如果当前节点的左子节点不为空,则当前节点的左子节点递归执行后序遍历方法进行后序遍历
* (2)判断如果当前节点的右子节点不为空,则当前节点的右子节点递归执行后序遍历方法进行后序遍历
* (3)输出当前节点(初始节点是根节点root节点)
*
* 前序遍历查找指定节点步骤:
* (1)根据节点的id属性判断当前节点是否是要查找的节点,是,则返回当前节点
* (2)不是,则判断如果当前节点的左子节点不为空,则当前节点的左子节点递归执行前序遍历查找方法
* (3)判断如果节点的左子节点递归执行前序遍历查找方法找到了指定的节点,则返回,没找到,则进行当前节点的右子节点的判断
* (4)判断如果当前节点的右子节点不为空,则当前节点的右子节点递归执行前序遍历查找方法
* (5)最后结果,返回null 或者 找到节点
*
* 中序遍历查找指定节点步骤:
* (1)判断如果当前节点的左子节点不为空,则当前节点的左子节点递归执行中序遍历查找方法
* (2)判断如果节点的左子节点递归执行中序遍历查找方法找到了指定的节点,则返回,没找到,则进行当前节点判断
* (3)根据节点的id属性判断当前节点是否是要查找的节点,是,则返回当前节点
* (4)不是,则判断如果当前节点的右子节点不为空,则当前节点的右子节点递归执行中序遍历查找方法
* (5)最后结果,返回null 或者 找到节点
*
* 后序遍历查找指定节点步骤:
* (1)判断如果当前节点的左子节点不为空,则当前节点的左子节点递归执行后序遍历查找方法
* (2)判断如果节点的左子节点递归执行后序遍历查找方法找到了指定的节点,则返回,没找到,则进行当前节点的右子节点的判断
* (3)判断如果当前节点的右子节点不为空,则当前节点的右子节点递归执行后序遍历查找方法,找到,则返回,没找到,则进行当前节点判断
* (4)根据节点的id属性判断当前节点是否是要查找的节点,是,则返回当前节点
* (5)不是,则返回null(最后结果,返回null 或者 找到节点)
*
*/
public class BinaryTreeDemo01 {
public static void main(String[] args) {
// 前序遍历
testPreOrder();
// 中序遍历
testInfixOrder();
// 后序遍历
testPostOrder();
// 前序遍历查找节点
testPreOrderSearch();
// 中序遍历查找节点
testInfixOrderSearch();
// 后序遍历查找节点
testPostOrderSearch();
// 删除指定节点
testDelOne();
}
// 测试前序遍历
private static void testPreOrder() {
//创建二叉树
BinaryTree binaryTree = new BinaryTree();
//创建二叉树结点
HeroNode root = new HeroNode(1, "宋江");
HeroNode node2 = new HeroNode(2, "吴用");
HeroNode node3 = new HeroNode(3, "卢俊义");
HeroNode node4 = new HeroNode(4, "林冲");
HeroNode node5 = new HeroNode(5, "关胜");
//本案例手动创建二叉树,以后使用递归的方式创建二叉树
root.setLeft(node2);
root.setRight(node3);
node3.setLeft(node5);
node3.setRight(node4);
binaryTree.setRoot(root);
// 前序遍历
System.out.println("----------------前序遍历----------------");
binaryTree.preOrder();
System.out.println();
/*----------------前序遍历----------------
HeroNode{id=1, name='宋江'}
HeroNode{id=2, name='吴用'}
HeroNode{id=3, name='卢俊义'}
HeroNode{id=5, name='关胜'}
HeroNode{id=4, name='林冲'}*/
}
// 测试中序遍历
private static void testInfixOrder() {
//创建二叉树
BinaryTree binaryTree = new BinaryTree();
//创建二叉树结点
HeroNode root = new HeroNode(1, "宋江");
HeroNode node2 = new HeroNode(2, "吴用");
HeroNode node3 = new HeroNode(3, "卢俊义");
HeroNode node4 = new HeroNode(4, "林冲");
HeroNode node5 = new HeroNode(5, "关胜");
//本案例手动创建二叉树,以后使用递归的方式创建二叉树
root.setLeft(node2);
root.setRight(node3);
node3.setLeft(node5);
node3.setRight(node4);
binaryTree.setRoot(root);
// 中序遍历
System.out.println("----------------中序遍历----------------");
binaryTree.infixOrder();
System.out.println();
/*----------------中序遍历----------------
HeroNode{id=2, name='吴用'}
HeroNode{id=1, name='宋江'}
HeroNode{id=5, name='关胜'}
HeroNode{id=3, name='卢俊义'}
HeroNode{id=4, name='林冲'}*/
}
// 测试后序遍历
private static void testPostOrder() {
//创建二叉树
BinaryTree binaryTree = new BinaryTree();
//创建二叉树结点
HeroNode root = new HeroNode(1, "宋江");
HeroNode node2 = new HeroNode(2, "吴用");
HeroNode node3 = new HeroNode(3, "卢俊义");
HeroNode node4 = new HeroNode(4, "林冲");
HeroNode node5 = new HeroNode(5, "关胜");
//本案例手动创建二叉树,以后使用递归的方式创建二叉树
root.setLeft(node2);
root.setRight(node3);
node3.setLeft(node5);
node3.setRight(node4);
binaryTree.setRoot(root);
// 后序遍历
System.out.println("----------------后序遍历----------------");
binaryTree.postOrder();
System.out.println();
/*----------------后序遍历----------------
HeroNode{id=2, name='吴用'}
HeroNode{id=5, name='关胜'}
HeroNode{id=4, name='林冲'}
HeroNode{id=3, name='卢俊义'}
HeroNode{id=1, name='宋江'}*/
}
// 测试前序遍历查找节点
private static void testPreOrderSearch() {
//创建二叉树
BinaryTree binaryTree = new BinaryTree();
//创建二叉树结点
HeroNode root = new HeroNode(1, "宋江");
HeroNode node2 = new HeroNode(2, "吴用");
HeroNode node3 = new HeroNode(3, "卢俊义");
HeroNode node4 = new HeroNode(4, "林冲");
HeroNode node5 = new HeroNode(5, "关胜");
//本案例手动创建二叉树,以后使用递归的方式创建二叉树
root.setLeft(node2);
root.setRight(node3);
node3.setLeft(node5);
node3.setRight(node4);
binaryTree.setRoot(root);
// 前序遍历查找节点
HeroNode resultNode = binaryTree.preOrderSearch(5);
System.out.println(resultNode);
/*HeroNode{id=5, name='关胜'}*/
}
// 测试中序遍历查找节点
private static void testInfixOrderSearch() {
//创建二叉树
BinaryTree binaryTree = new BinaryTree();
//创建二叉树结点
HeroNode root = new HeroNode(1, "宋江");
HeroNode node2 = new HeroNode(2, "吴用");
HeroNode node3 = new HeroNode(3, "卢俊义");
HeroNode node4 = new HeroNode(4, "林冲");
HeroNode node5 = new HeroNode(5, "关胜");
//本案例手动创建二叉树,以后使用递归的方式创建二叉树
root.setLeft(node2);
root.setRight(node3);
node3.setLeft(node5);
node3.setRight(node4);
binaryTree.setRoot(root);
// 中序遍历查找节点
HeroNode resultNode = binaryTree.infixOrderSearch(5);
System.out.println(resultNode);
/*HeroNode{id=5, name='关胜'}*/
}
// 测试后序遍历查找节点
private static void testPostOrderSearch() {
//创建二叉树
BinaryTree binaryTree = new BinaryTree();
//创建二叉树结点
HeroNode root = new HeroNode(1, "宋江");
HeroNode node2 = new HeroNode(2, "吴用");
HeroNode node3 = new HeroNode(3, "卢俊义");
HeroNode node4 = new HeroNode(4, "林冲");
HeroNode node5 = new HeroNode(5, "关胜");
//本案例手动创建二叉树,以后使用递归的方式创建二叉树
root.setLeft(node2);
root.setRight(node3);
node3.setLeft(node5);
node3.setRight(node4);
binaryTree.setRoot(root);
// 后序遍历查找节点
HeroNode resultNode = binaryTree.postOrderSearch(5);
System.out.println(resultNode);
/*HeroNode{id=5, name='关胜'}*/
}
// 测试删除指定节点
private static void testDelOne() {
//创建二叉树
BinaryTree binaryTree = new BinaryTree();
//创建二叉树结点
HeroNode root = new HeroNode(1, "宋江");
HeroNode node2 = new HeroNode(2, "吴用");
HeroNode node3 = new HeroNode(3, "卢俊义");
HeroNode node4 = new HeroNode(4, "林冲");
HeroNode node5 = new HeroNode(5, "关胜");
//本案例手动创建二叉树,以后使用递归的方式创建二叉树
root.setLeft(node2);
root.setRight(node3);
node3.setLeft(node5);
node3.setRight(node4);
binaryTree.setRoot(root);
// 删除指定节点
binaryTree.delOne(5);
// 前序遍历
System.out.println("----------------删除指定节点后的前序遍历----------------");
binaryTree.preOrder();
System.out.println();
/*----------------删除指定节点后的前序遍历----------------
HeroNode{id=1, name='宋江'}
HeroNode{id=2, name='吴用'}
HeroNode{id=3, name='卢俊义'}
HeroNode{id=4, name='林冲'}*/
}
}
// 二叉树
class BinaryTree {
private HeroNode root;
public HeroNode getRoot() {
return root;
}
public void setRoot(HeroNode root) {
this.root = root;
}
// 前序遍历
public void preOrder() {
if(this.getRoot() == null) {
System.out.println("二叉树为空,无法遍历!");
} else {
this.getRoot().preOrder();
}
}
// 中序遍历
public void infixOrder() {
if(this.getRoot() == null) {
System.out.println("二叉树为空,无法遍历!");
} else {
this.getRoot().infixOrder();
}
}
// 后序遍历
public void postOrder() {
if(this.getRoot() == null) {
System.out.println("二叉树为空,无法遍历!");
} else {
this.getRoot().postOrder();
}
}
// 前序遍历查找节点
public HeroNode preOrderSearch(Integer id) {
if(this.getRoot() == null) {
return null;
} else {
return this.getRoot().preOrderSearch(id);
}
}
// 中序遍历查找节点
public HeroNode infixOrderSearch(Integer id) {
if(this.getRoot() == null) {
return null;
} else {
return this.getRoot().infixOrderSearch(id);
}
}
// 后序遍历查找节点
public HeroNode postOrderSearch(Integer id) {
if(this.getRoot() == null) {
return null;
} else {
return this.getRoot().postOrderSearch(id);
}
}
// 删除指定节点
public void delOne(Integer id) {
if(this.getRoot() == null) {
System.out.println("空树,不能执行删除操作!");
} else {
// 如果只有一个根节点root结点, 这里立即判断root是不是就是要删除结点
if(this.getRoot().getId() == id) {
this.setRoot(null);
} else {
this.getRoot().delOne(id);
}
}
}
}
// 英雄节点类
class HeroNode implements Serializable {
private static final long serialVersionUID = -8283217516456007620L;
private Integer id;
private String name;
private HeroNode left; // 默认为null
private HeroNode right; // 默认为null
public HeroNode() {
}
public HeroNode(Integer id, String name) {
this.id = id;
this.name = name;
}
public Integer getId() {
return id;
}
public void setId(Integer id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public HeroNode getLeft() {
return left;
}
public void setLeft(HeroNode left) {
this.left = left;
}
public HeroNode getRight() {
return right;
}
public void setRight(HeroNode right) {
this.right = right;
}
/**
* 前序遍历
* 每个节点都会执行前序遍历方法中的三个动作,涉及到递归方法的压栈与弹栈
*/
public void preOrder() {
// (1)输出当前节点(初始节点是根节点root节点)
System.out.println(this);
// (2)判断如果当前节点的左子节点不为空,则当前节点的左子节点递归执行前序遍历方法进行前序遍历
if(this.getLeft() != null) {
this.getLeft().preOrder();
}
// (3)判断如果当前节点的右子节点不为空,则当前节点的右子节点递归执行前序遍历方法进行前序遍历
if(this.getRight() != null) {
this.getRight().preOrder();
}
}
/**
* 中序遍历
* 每个节点都会执行中序遍历方法中的三个动作,涉及到递归方法的压栈与弹栈
*/
public void infixOrder() {
// (1)判断如果当前节点的左子节点不为空,则当前节点的左子节点递归执行中序遍历方法进行中序遍历
if(this.getLeft() != null) {
this.getLeft().infixOrder();
}
// (2)输出当前节点(初始节点是根节点root节点)
System.out.println(this);
// (3)判断如果当前节点的右子节点不为空,则当前节点的右子节点递归执行中序遍历方法进行中序遍历
if(this.getRight() != null) {
this.getRight().infixOrder();
}
}
/**
* 后序遍历
* 每个节点都会执行后序遍历方法中的三个动作,涉及到递归方法的压栈与弹栈
*/
public void postOrder() {
// (1)判断如果当前节点的左子节点不为空,则当前节点的左子节点递归执行后序遍历方法进行后序遍历
if(this.getLeft() != null) {
this.getLeft().postOrder();
}
// (2)判断如果当前节点的右子节点不为空,则当前节点的右子节点递归执行后序遍历方法进行后序遍历
if(this.getRight() != null) {
this.getRight().postOrder();
}
// (3)输出当前节点(初始节点是根节点root节点)
System.out.println(this);
}
/**
* 根据节点id属性值前序遍历查找节点
* @param id 被查找节点的id属性
* @return 找到则返回,没找到则返回null
*/
public HeroNode preOrderSearch(Integer id) {
// 判断当前节点是否是要查找的节点
if(this.getId() == id) {
return this;
}
HeroNode resultNode = null;
// 判断如果当前节点的左子节点不为空,则当前节点的左子节点递归执行前序遍历查找方法
if(this.getLeft() != null) {
resultNode = this.getLeft().preOrderSearch(id);
}
// 判断如果节点的左子节点递归执行前序遍历查找方法找到了指定的节点,则返回
// 没找到,则进行当前节点的右子节点的判断
if(resultNode != null) {
return resultNode;
}
// 判断如果当前节点的右子节点不为空,则当前节点的右子节点递归执行前序遍历查找方法
if(this.getRight() != null) {
resultNode = this.getRight().preOrderSearch(id);
}
// 返回null 或者 找到节点
return resultNode;
}
/**
* 根据节点id属性值中序遍历查找节点
* @param id 被查找节点的id属性
* @return 找到则返回,没找到则返回null
*/
public HeroNode infixOrderSearch(Integer id) {
HeroNode resultNode = null;
// 判断如果当前节点的左子节点不为空,则当前节点的左子节点递归执行中序遍历查找方法
if(this.getLeft() != null) {
resultNode = this.getLeft().infixOrderSearch(id);
}
// 判断如果节点的左子节点递归执行中序遍历查找方法找到了指定的节点,则返回
// 没找到,则进行当前节点判断
if(resultNode != null) {
return resultNode;
}
// 判断当前节点是否是要查找的节点
if(this.getId() == id) {
return this;
}
// 判断如果当前节点的右子节点不为空,则当前节点的右子节点递归执行中序遍历查找方法
if(this.getRight() != null) {
resultNode = this.getRight().infixOrderSearch(id);
}
// 返回null 或者 找到节点
return resultNode;
}
/**
* 根据节点id属性值后序遍历查找节点
* @param id 被查找节点的id属性
* @return 找到则返回,没找到则返回null
*/
public HeroNode postOrderSearch(Integer id) {
HeroNode resultNode = null;
// 判断如果当前节点的左子节点不为空,则当前节点的左子节点递归执行后序遍历查找方法
if(this.getLeft() != null) {
resultNode = this.getLeft().postOrderSearch(id);
}
// 判断如果节点的左子节点递归执行后序遍历查找方法找到了指定的节点,则返回
// 没找到,则进行当前节点的右子节点的判断
if(resultNode != null) {
return resultNode;
}
// 判断如果当前节点的右子节点不为空,则当前节点的右子节点递归执行后序遍历查找方法
if(this.getRight() != null) {
resultNode = this.getRight().postOrderSearch(id);
}
// 判断当前节点是否是要查找的节点
if(this.getId() == id) {
return this;
}
// 返回null 或者 找到节点
return resultNode;
}
/**
* 递归删除结点
* 1、如果删除的节点是叶子节点,则删除该节点
* 2、如果删除的节点是非叶子节点,则删除该子树
* @param id 待删除节点的id属性值
*/
public void delOne(Integer id) {
/*1、因为我们的二叉树是单向的,所以我们是判断当前结点的子结点是否需要删除结点,而不能去判断当前这个结点是不是需要删除结点
2、如果当前结点的左子结点不为空,并且左子结点就是要删除结点,就将this.left = null,并且就返回(结束递归删除)
3、如果当前结点的右子结点不为空,并且右子结点就是要删除结点,就将this.right= null,并且就返回(结束递归删除)
4、如果第2和第3步没有删除结点,那么我们就需要向左子树进行递归删除
5、如果第4步也没有删除结点,则应当向右子树进行递归删除*/
// 2、如果当前结点的左子结点不为空,并且左子结点就是要删除结点,就将this.left = null,并且就返回(结束递归删除)
if(this.getLeft() != null && this.getLeft().getId() == id) {
this.setLeft(null);
return;
}
// 3、如果当前结点的右子结点不为空,并且右子结点就是要删除结点,就将this.right= null,并且就返回(结束递归删除)
if(this.getRight() != null && this.getRight().getId() == id) {
this.setRight(null);
return;
}
// 4、如果第2和第3步没有删除结点,那么我们就需要向左子树进行递归删除
if(this.getLeft() != null) {
this.getLeft().delOne(id);
}
// 5、如果第4步也没有删除结点,则应当向右子树进行递归删除
if(this.getRight() != null) {
this.getRight().delOne(id);
}
}
@Override
public String toString() {
return "HeroNode{" +
"id=" + id +
", name='" + name + '\'' +
'}';
}
}