一、二叉树
1、为什么需要树这种数据结构(数组、链表、树说明)
1) 数组存储方式的分析(缺点插入)
2) 链式存储方式的分析(缺点检索)
3) 树存储方式的分析(提高存储读取)
2、树示意图(常用术语)
3、二叉树的概念(包含满二叉树及完全二叉树)
说明:二叉树的介绍以及满二叉树和完全二叉树的介绍
、
4、二叉树遍历应用实例(前序,中序,后序)
源代码:BinaryTree.java
思路分析
注意的是这里的方法增加于上面的类中进行实现
代码实现(完整过程+测试)
源代码:BinaryTree.java
说明:分为两个类,一个为二叉树节点类包含前中后序遍历,另一个是二叉树类包含根节点以及进行前中后序的调用方法。
**
节点类
//树的节点
class TreeNode{
private String name;
private int id;
private TreeNode left;
private TreeNode right;
public TreeNode(String name, int id) {
super();
this.name = name;
this.id = id;
}
//前序遍历
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);
}
public void setName(String name) {
this.name = name;
}
public void setId(int id) {
this.id = id;
}
public void setLeft(TreeNode left) {
this.left = left;
}
public void setRight(TreeNode right) {
this.right = right;
}
@Override
public String toString() {
return "TreeNode [name=" + name + ", id=" + id + "]";
}
}
二叉树类
//二叉树
class MyBinaryTree{
//设置一个根节点
private TreeNode root;
public void setRoot(TreeNode root) {
this.root = root;
}
//前序遍历
public void preOrder() {
//判断根节点是否为空
if(root != null) {
root.preOrder();//进行前序遍历
}else {
System.out.println("根节点为空无法前序遍历!");
}
}
// 中序遍历
public void infixOrder() {
if (root != null) {
root.infixOrder();// 进行中序遍历
}else {
System.out.println("根节点为空无法中序遍历!");
}
}
// 后序遍历
public void postOrder() {
if (root != null) {
root.postOrder();// 进行后序遍历
}else {
System.out.println("根节点为空无法后序遍历!");
}
}
}
测试类
package tree;
public class BinaryTree {
public static void main(String[] args) {
//创建一个二叉树
MyBinaryTree tree = new MyBinaryTree();
//创建四个节点
TreeNode root = new TreeNode("宋江", 1);
TreeNode node2 = new TreeNode("吴用", 2);
TreeNode node3 = new TreeNode("卢俊", 3);
TreeNode node4 = new TreeNode("林冲", 4);
//将node节点存放到root中
root.setLeft(node2);
root.setRight(node3);
node3.setRight(node4);
//将root存放到二叉树中
tree.setRoot(root);
//进行前序遍历
System.out.println("前序遍历:");
tree.preOrder();
System.out.println("中序遍历:");
tree.infixOrder();
System.out.println("后序遍历:");
tree.postOrder();
}
}
运行结果:
**
小测试
说说下图的前中后遍历的结果
前序:12354
中序:21534
后序:25431
**
5、查找指定节点(前中后序)
思路分析
与之前前后序遍历几乎相同,只不过这里面增加的返回值以及比较判断的过程。
代码实现
节点类
说明:可以看到每种查找几乎都只是顺序变了而已,其中对于查找到的值使用resultNode来接收并根据实际情况返回,并且在判断比较id时才是真正开始比较,这里输出来体现。
//前序遍历查找
public TreeNode preOrderSearch(int findId) {
System.out.println("前序比较~");
if(this.id == findId) {
return this;
}
//进行向左子树进行查找
TreeNode resultNode = null;
if(this.left != null) {
resultNode = this.left.preOrderSearch(findId);//向左进行查找返回
}
if(resultNode != null) {
return resultNode;
}
//向右子树进行查找
if(this.right != null) {
resultNode = this.right.preOrderSearch(findId);//向右查找返回
}
return resultNode;//返回对应查找到的值
}
//中序遍历查找
public TreeNode infixOrderSearch(int findId) {
// 首先进行向左子树进行查找
TreeNode resultNode = null;
if (this.left != null) {
resultNode = this.left.infixOrderSearch(findId);// 向左进行查找返回
}
if(resultNode != null) {
return resultNode;
}
System.out.println("中序比较~");
if(this.id == findId) {
return this;
}
//向右子树进行查找
if(this.right != null) {
resultNode = this.right.infixOrderSearch(findId);//向右查找返回
}
return resultNode;//返回对应查找到的值
}
//后序遍历查找
public TreeNode postOrderSearch(int findId) {
// 首先进行向左子树进行查找
TreeNode resultNode = null;
if (this.left != null) {
resultNode = this.left.infixOrderSearch(findId);// 向左进行查找返回
}
if(resultNode != null) {
return resultNode;
}
//向右子树进行查找
if (this.right != null) {
resultNode = this.right.infixOrderSearch(findId);// 向右查找返回
}
if(resultNode != null) {
return resultNode;
}
System.out.println("后序比较~");
if(this.id == findId) {
return this;//进行判断值进行查找
}
return resultNode;
}
二叉树类
说明:这里只是简单的判断根节点是否为空之后就对根节点进行对应的查找方法调用
//前序遍历查找
public TreeNode preOrderSearch(int findId) {
if(root != null) {
return root.preOrderSearch(findId);
}else {
System.out.println("二叉树为空无法查找!");
return null;
}
}
// 中序遍历查找
public TreeNode infixOrderSearch(int findId) {
if (root != null) {
return root.infixOrderSearch(findId);
} else {
System.out.println("二叉树为空无法查找!");
return null;
}
}
// 后序遍历查找
public TreeNode postOrderSearch(int findId) {
if (root != null) {
return root.postOrderSearch(findId);
} else {
System.out.println("二叉树为空无法查找!");
return null;
}
}
测试类
package tree;
public class BinaryTree {
public static void main(String[] args) {
//创建一个二叉树
MyBinaryTree tree = new MyBinaryTree();
//创建四个节点
TreeNode root = new TreeNode("宋江", 1);
TreeNode node2 = new TreeNode("吴用", 2);
TreeNode node3 = new TreeNode("卢俊", 3);
TreeNode node4 = new TreeNode("林冲", 4);
TreeNode node5 = new TreeNode("关胜", 5);
//将node节点存放到root中
root.setLeft(node2);
root.setRight(node3);
node3.setRight(node4);
node3.setLeft(node5);
//将root存放到二叉树中
tree.setRoot(root);
//进行前序遍历
System.out.println("前序遍历:");
tree.preOrder();
System.out.println("中序遍历:");
tree.infixOrder();
System.out.println("后序遍历:");
tree.postOrder();
System.out.println("------------------------");
//开始前中后序遍历查找
System.out.println("前序遍历查找:");
TreeNode node = tree.preOrderSearch(5);
if(node != null) {
System.out.println("找到节点为:"+node);
}else {
System.out.println("未找到节点!");
}
System.out.println("------------------------");
//开始中序遍历查找
System.out.println("中序遍历查找:");
TreeNode node1 = tree.infixOrderSearch(5);
if (node1 != null) {
System.out.println("找到节点为:" + node1);
} else {
System.out.println("未找到节点!");
}
System.out.println("------------------------");
//开始中序遍历查找
System.out.println("后序遍历查找:");
TreeNode node6 = tree.postOrderSearch(5);
if (node6 != null) {
System.out.println("找到节点为:" + node6);
} else {
System.out.println("未找到节点!");
}
}
}
运行结果
6、删除节点
源代码:BinaryTree.java
思路分析
要求说明
1)如果删除的节点是叶子节点,则删除该节点
2) 如果删除的节点是非叶子节点,则删除该子树.
3) 测试,删除掉 5 号叶子节点 和 3 号子树.
代码实现(完整过程+测试)
说明:节点类以及二叉树类都只有各自一个删除方法,二叉树用于处理root根节点的情况,节点类处理左右两边情况
节点类
//删除节点操作
public void delNodeById(int delId) {
//首先是判断左子节点是否为空,并且左子节点的id是否为要查找的id,是的话就删除
if(this.left != null && this.left.id == delId) {
this.left = null;
System.out.println("成功删除节点,其id值为:"+delId);
return;//删除成功就结束
}
//首先是判断右子节点是否为空,并且右子节点的id是否为要查找的id,是的话就删除
if(this.right != null && this.right.id == delId) {
this.right = null;
System.out.println("成功删除节点,其id值为:"+delId);
return;//删除成功就结束
}
//运行到这里就说明该节点的左右孩子都不符合删除要求,那么进行递归操作
if(this.left != null) {
this.left.delNodeById(delId);
}
if(this.right != null) {
this.right.delNodeById(delId);
}
}
二叉树类
//删除指定id的节点
public void delNodeById(int delId) {
if(root != null) {
//来判断根节点是否为要删除的节点
if(root.getId() == delId) {
root = null;
}else {
//不为要删除的节点,那么执行删除节点的方法
root.delNodeById(delId);
}
}else {
System.out.println("树为空,无法进行删除操作!");
}
}
测试类
package tree;
public class BinaryTree {
public static void main(String[] args) {
//创建一个二叉树
MyBinaryTree tree = new MyBinaryTree();
//创建四个节点
TreeNode root = new TreeNode("宋江", 1);
TreeNode node2 = new TreeNode("吴用", 2);
TreeNode node3 = new TreeNode("卢俊", 3);
TreeNode node4 = new TreeNode("林冲", 4);
TreeNode node5 = new TreeNode("关胜", 5);
//将node节点存放到root中
root.setLeft(node2);
root.setRight(node3);
node3.setRight(node4);
node3.setLeft(node5);
// //将root存放到二叉树中
tree.setRoot(root);
//
//进行前序遍历
System.out.println("前序遍历:");
tree.preOrder();
System.out.println();
System.out.println("开始执行删除节点操作:");
tree.delNodeById(5);//执行删除操作
tree.delNodeById(3);//执行删除操作
System.out.println();
System.out.println("删除节点后前序遍历:");
tree.preOrder();
}
运行结果:
二、顺序存储二叉树
1、顺序存储二叉树的概念
基本说明
从数据存储来看,数组存储方式和树的存储方式可以相互转换,即数组可以转换成树,树也可以转换成数组,
看右面的示意图:
要求:
1) 右图的二叉树的结点,要求以数组的方式来存放 arr:[1,2,3,4,5,6,6]
2) 要求在遍历数组 arr 时,仍然可以以前序遍历,中序遍历和后序遍历的方式完成结点的遍
特点说明
说明:对一个左子节点以及右子节点、父节点的方式计算可以根据上面示例图来进行查看
2、代码实现
说明:这里使用的是前序遍历的方法
package tree;
public class ArrayBinaryTreeDemo {
public static void main(String[] args) {
int[] arr = {1,2,3,4,5,6,7};
ArrayBinaryTree tree = new ArrayBinaryTree(arr);
//开始进行前序遍历
tree.preOrder();
}
}
class ArrayBinaryTree{
private int[] arr;//用于存放数据节点的数据
public ArrayBinaryTree(int[] arr) {
super();
this.arr = arr;
}
//进行重载调用有参数的方法
public void preOrder() {
preOrder(0);
}
//进行前序遍历
public void preOrder(int index){
//不符合条件的输出
if(arr == null || arr.length == 0) {
System.out.println("数组为空,二叉树无法遍历");
return;
}
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);
}
}
}
前中后序遍历如下:
运行结果:
整理者:长路 时间:2020/8/26-2020/8/28