目录
一、需求
A:利用java建立一颗二叉树,并进行前序,中序,后序的遍历;
二、分析
2.1 如何建立一棵二叉树
A:首先肯定要定义一个二叉树类,树必然有根结点,这是它本身就具有的属性,于是就定义为私有变量;
B:至于这棵树的功能,那要有前序遍历、中序遍历、后序遍历的功能;
C:而结点本身也是一个对象,也需要定义为一个类,下面讨论如何定义一个结点类;
2.2 如何定义一个结点类
A:这个要根据,现实中的能作为结点的对象来决定的,比如把英雄看作结点,那么英雄要有名字等等,这
就是结点本身的属性;
B:结点本身可能作为父结点或子结点,从而作为左结点或右结点也是该结点的一个属性;
C:而结点本身的功能,也是前序遍历、中序遍历、后序遍历;
2.3 遍历功能的位置?
A:到底是在二叉树类中定义遍历功能,还是在结点类中定义遍历功能呢?
a:每个结点都是一个具体的对象,它们之间都是有关系的;
b:以前序遍历为例,输出根结点后,递归判断有没有左子结点,有就调用遍历函数,也就是结点需要调用
方法来实现遍历;
c:二叉树中也需要定义遍历功能,本身是由二叉树对象调用的,但实质上需要的是该二叉树对象传入的结点
去调用结点中定义的遍历功能,比如传入根结点,一套套就下来了;
B:设想一下,能否在二叉树类中直接定义遍历功能的具体实现,而不是依赖于结点定义的遍历功能?
a:还是以前序遍历为例,明确返回值为void类型,参数列表应该为结点类型;
C:下面会对A,B分别用代码进行实现,在这之前先明确前序、中序、后序遍历的概念;
三、遍历方式简介
四、代码实现
4.1 结点类中定义方法
package cn.itcast_01;
/*
* 需求:
* A:实现二叉树的前序遍历,中序遍历和后序遍历
* 分析:
*/
public class BinaryTreeDemo {
public static void main(String[] args) {
// 建立一棵树
BinaryTree bt = new BinaryTree();
// 创建结点对象
HeroNode root = new HeroNode(1, "宋江");
HeroNode node2 = new HeroNode(2, "吴用");
HeroNode node3 = new HeroNode(3, "卢俊义");
HeroNode node4 = new HeroNode(4, "林冲");
// 手动将结点连起来,后期自动生成
root.setLeft(node2);
root.setRight(node3);
node3.setRight(node4);
// 把根结点传递给树对象
bt.setRoot(root);
// 前序遍历
System.out.println("前序遍历:");
bt.preOrder();
System.out.println("------------");
// 中序遍历
System.out.println("中序遍历为:");
bt.infixOrder();
System.out.println("------------");
// 后序遍历
System.out.println("后序遍历为:");
bt.postOrder();
}
}
class HeroNode {
// 英雄本身就具有的属性
private int id;
private String name;
private HeroNode left;
private HeroNode right;
// 构造方法
public HeroNode(int id, String name) {
this.id = id;
this.name = name;
}
// 自动生成get,set方法
public int getId() {
return id;
}
public void setId(int 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;
}
// toString方法
@Override
public String toString() {
return "HeroNode [id=" + id + ", name=" + name + "]";
}
// 前序遍历
public void preOrder() {
// 输出当前结点
System.out.println(this);
// 存在左子树,则递归左子树结点
if (this.left != null) {
this.left.preOrder();
}
// 存在右子树,则递归调用右子树结点
if (this.right != null) {
this.right.preOrder();
}
}
// 中序遍历
public void infixOrder() {
// 存在左子树,则递归左子树结点
if (this.left != null) {
this.left.infixOrder();
}
// 输出当前结点
System.out.println(this);
// 存在右子树,则递归右子树结点
if (this.right != null) {
this.right.infixOrder();
}
}
// 后序遍历
public void postOrder() {
if (this.left != null) {
this.left.postOrder();
}
if (this.right != null) {
this.right.postOrder();
}
System.out.println(this);
}
}
// 有了结点,那就可以建一棵树了
class BinaryTree {
// 这个树只需有个根就行,通过这个根去和其它的结点连成树
private HeroNode root;
// 生成构造方法
public BinaryTree() {
}
public void setRoot(HeroNode root) {
this.root = root;
}
// 前序遍历
public void preOrder() {
if (this.root != null) {
this.root.preOrder();
}
}
// 中序遍历
public void infixOrder() {
if (this.root != null) {
this.root.infixOrder();
}
}
// 后序遍历
public void postOrder() {
if (this.root != null) {
this.root.postOrder();
}
}
}
4.2 二叉树类中定义方法
package cn.itcast_01;
/*
* 需求:实现二叉树的前序遍历,中序遍历和后序遍历
* 分析:根左右,左根右,左右根
*/
public class BinaryTreeDemo {
public static void main(String[] args) {
// 创建二叉树
BinaryTree binaryTree = new BinaryTree();
// 创建需要的结点
HeroNode root = new HeroNode(1, "宋江");
HeroNode node2 = new HeroNode(2, "吴用");
HeroNode node3 = new HeroNode(3, "卢俊义");
HeroNode node4 = new HeroNode(4, "林冲");
// 先手动创建二叉树
root.setLeft(node2);
root.setRight(node3);
node3.setRight(node4);
binaryTree.setRoot(root);
// 前序遍历
System.out.println("前序遍历:");
binaryTree.preOrder(root);
// 中序遍历
System.out.println("中序遍历:");
binaryTree.infixOrder(root);
// 后序遍历
System.out.println("后序遍历:");
binaryTree.postOrder(root);
;
}
}
// 定义BinaryTree 二叉树
class BinaryTree {
private HeroNode root;
public void setRoot(HeroNode root) {
this.root = root;
}
// 前序遍历
public void preOrder(HeroNode node) {
if (node != null) {
System.out.println(node);
// 递归左子树
if (node.left != null) {
preOrder(node.left);
}
// 递归右子树
if (node.right != null) {
preOrder(node.right);
}
} else {
System.out.println("二叉树为空,无法遍历");
}
}
// 中序遍历
public void infixOrder(HeroNode node) {
if (node != null) {
// 递归左子树
if (node.left != null) {
infixOrder(node.left);
}
System.out.println(node);
// 递归右子树
if (node.right != null) {
infixOrder(node.right);
}
} else {
System.out.println("二叉树为空,无法遍历");
}
}
// 后序遍历
public void postOrder(HeroNode node) {
if (node != null) {
// 递归左子树
if (node.left != null) {
postOrder(node.left);
}
// 递归右子树
if (node.right != null) {
postOrder(node.right);
}
System.out.println(node);
} else {
System.out.println("二叉树为空,无法遍历");
}
}
}
// 创建结点
class HeroNode {
private int no;
private String name;
HeroNode left;
HeroNode right;
// 生成构造方法
public HeroNode(int no, String name) {
this.no = no;
this.name = name;
}
// 生成方法
public int getNo() {
return no;
}
public void setNo(int no) {
this.no = no;
}
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;
}
@Override
public String toString() {
return "HeroNode [no=" + no + ", name=" + name + "]";
}
}
五、查找
5.1 代码实现
package tree.find;
/*
* 需求:
* A:请编写前序查找,中序查找和后序查找的方法
* B:分别使用三种查找方式,查找英雄编号为5的结点
* C:分析各种查找方式,分别比较了多少次
* 分析:
* A:前序查找应该怎么写呢?
* a:在前序遍历的基础上,就不是去输出当前结点,而是判断当前结点
* 是不是要查找的值;
* b:是查找的值就返回,不是就递归查找
*/
public class FindDemo {
public static void main(String[] args) {
// 建立一棵树
BinaryTree bt = 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);
// 把根结点传递给树对象
bt.setRoot(root);
// 前序查找
System.out.println("前序查找:");
HeroNode resNode = bt.preOrder(3);
if (resNode != null) {
System.out.println(resNode);
} else {
System.out.println("没有该结点");
}
System.out.println("------------");
// 中序查找
System.out.println("中序查找:");
resNode = bt.infixOrder(5);
if (resNode != null) {
System.out.println(resNode);
} else {
System.out.println("没有该结点");
}
System.out.println("------------");
// 后序查找
System.out.println("后序遍历为:");
resNode = bt.postOrder(4);
if (resNode != null) {
System.out.println(resNode);
} else {
System.out.println("没有该结点");
}
}
}
class HeroNode {
// 英雄本身就具有的属性
private int id;
private String name;
private HeroNode left;
private HeroNode right;
// 构造方法
public HeroNode(int id, String name) {
this.id = id;
this.name = name;
}
// 自动生成get,set方法
public int getId() {
return id;
}
public void setId(int 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;
}
// toString方法
@Override
public String toString() {
return "HeroNode [id=" + id + ", name=" + name + "]";
}
// 前序查找
public HeroNode preOrder(int id) {
// 判断当前结点是否是要查找的结点
if (this.id == id) {
return this;
}
HeroNode resNode = null;
if (this.left != null) {
resNode = this.left.preOrder(id);
}
// 说明在左子树找到了
if (resNode != null) {
return resNode;
}
if (this.right != null) {
resNode = this.right.preOrder(id);
}
return resNode;
}
// 中序查找
public HeroNode infixOrder(int id) {
// 定义中间变量用于返回
HeroNode resNode = null;
// 存在左子树,则递归左子树结点
if (this.left != null) {
resNode = this.left.infixOrder(id);
}
if (resNode != null) {
return resNode;
}
// 判断当前结点是否为待查找的值
if (this.id == id) {
return this;
}
// 存在右子树,则递归右子树结点
if (this.right != null) {
resNode = this.right.infixOrder(id);
}
return resNode;
}
// 后序遍历
public HeroNode postOrder(int id) {
HeroNode resNode = null;
if (this.left != null) {
resNode = this.left.postOrder(id);
}
if (resNode != null) {
return resNode;
}
if (this.right != null) {
resNode = this.right.postOrder(id);
}
if (resNode != null) {
return resNode;
}
//在比较之前判断进入后序查找的次数
System.out.println("进入后序查找");
// 判断当前结点是否为待查找的值
if (this.id == id) {
return this;
}
return resNode;
}
}
// 有了结点,那就可以建一棵树了
class BinaryTree {
// 这个树只需有个根就行,通过这个根去和其它的结点连成树
private HeroNode root;
// 生成构造方法
public BinaryTree() {
}
public void setRoot(HeroNode root) {
this.root = root;
}
// 前序遍历
public HeroNode preOrder(int id) {
if (this.root != null) {
return this.root.preOrder(id);
} else {
return null;
}
}
// 中序遍历
public HeroNode infixOrder(int id) {
if (this.root != null) {
return this.root.infixOrder(id);
} else {
return null;
}
}
// 后序遍历
public HeroNode postOrder(int id) {
if (this.root != null) {
return this.root.postOrder(id);
} else {
return null;
}
}
}
六、删除
6.1 需求
A:如果删除的结点是叶子结点,则删除该结点;
B:如果删除的结点是非叶子结点,则删除该子树;
C:测试,删掉5号叶子结点和3号子树;
6.2 思路分析
6.3 代码实现
public class FindDemo {
public static void main(String[] args) {
// 建立一棵树
BinaryTree bt = 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);
// 把根结点传递给树对象
bt.setRoot(root);
// 删除结点前
System.out.println("删除结点前:");
bt.preOrder();
System.out.println("删除结点后:");
bt.delNode(3);
if (bt.isEmptyTree()) {
System.out.println("根结点已删,空树无法遍历!");
} else {
bt.preOrder();
}
}
}
// 定义结点类
class HeroNode {
// 英雄本身就具有的属性
private int id;
private String name;
private HeroNode left;
private HeroNode right;
// 构造方法
public HeroNode(int id, String name) {
this.id = id;
this.name = name;
}
// 自动生成get,set方法
public int getId() {
return id;
}
public void setId(int 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;
}
// toString方法
@Override
public String toString() {
return "HeroNode [id=" + id + ", name=" + name + "]";
}
// 定义删除方法
public void deleNode(int id) {
if (this.left != null && this.left.id == id) {
this.left = null;
return;
}
if (this.right != null && this.right.id == id) {
this.right = null;
return;
}
if (this.left != null) {
this.left.deleNode(id);
}
if (this.right != null) {
this.right.deleNode(id);
}
}
// 定义前序遍历方法
public void preOrder() {
// 该函数由根结点调用,在调用前判断是否为空即可
System.out.println(this);
if (this.left != null) {
this.left.preOrder();
}
if (this.right != null) {
this.right.preOrder();
}
}
}
// 有了结点,那就可以建一棵树了
class BinaryTree {
// 这个树只需有个根就行,通过这个根去和其它的结点连成树
private HeroNode root;
// 生成构造方法
public BinaryTree() {
}
public void setRoot(HeroNode root) {
this.root = root;
}
// 判断是否为空树
boolean isEmptyTree() {
if (this.root == null)
return true;
else
return false;
}
// 定义删除方法
public void delNode(int id) {
if (root != null) {
if (root.getId() == id) {
root = null;
} else {
root.deleNode(id);
}
} else {
System.out.println("空树无法删除!");
}
}
// 定义前序遍历
public void preOrder() {
this.root.preOrder();
}
}