Binary Tree
树(Tree)
- 树与数组& 链表对比
- 数组存储
- 优点: 通过下标访问元素, 速度快
- 缺点: 检索具体元素值, 或数组底部或元素与元素之间插入新元素或删除元素, 效率都很低
- 链式存储
- 优点: 插入和删除效率较好
- 缺点: 检索效率很低
- 树存储
- 增删改查4样性能都比较好
二叉树(Binary Tree)
- 每个节点最多只能有两个子节点, 一个左节点一个右节点
- 如果二叉树的所有叶子节点都在最后一层, 且节点总数=2^n-1, n为层数, 则称为满二叉树
- 如果二叉树的所有叶子节点都在最后一层或者倒数第二层, 且最后一层的叶子节点在左边连续, 倒数第二层的叶子节点在右边连续, 则称为完全二叉树
* 满二叉树肯定是完全二叉树, 而完全二叉树不一定是满二叉树
三种遍历
- 前序遍历:
- 先输出根节点, 再递归输出左子树, 最后递归输出右子树
- 左右子树从父节点往下遍历输出, 左节点优先于右节点. 依次
父左右
顺序输出
- 中序遍历:
- 先递归输出左子树, 再输出根节点, 最后递归输出右子树
- 左右子树从最左, 且最底节点开始输出. 依次
左父右
顺序输出
- 后序遍历:
- 先递归输出左子树, 再递归输出右子树, 最后输出根节点
- 左右子树从最左, 且最底节点开始输出. 依次
左右父
顺序输出
* 看根节点的输出顺序, 就可以确定是什么遍历了
public class BinaryTreeApp {
public static void main(String[] args) {
/** 创建二叉树实例*/
BinaryTree binaryTree = new BinaryTree();
/** 创建多个结点*/
Node node1 = new Node(1, "节点1"); // root
Node node2 = new Node(2, "节点2");
Node node3 = new Node(3, "节点3");
Node node4 = new Node(4, "节点4");
Node node5 = new Node(5, "节点5");
Node node6 = new Node(6, "节点6");
Node node7 = new Node(7, "节点7");
Node node8 = new Node(8, "节点8");
Node node9 = new Node(9, "节点9");
/** 设定根节点*/
binaryTree.setRoot(node1);
/** 手动设定各节点*/
node1.setLeft(node2);
node1.setRight(node3);
node3.setRight(node4);
node3.setLeft(node5);
node4.setLeft(node8);
node4.setRight(node9);
node5.setLeft(node6);
node5.setRight(node7);
System.out.println("前序遍历:");
binaryTree.preOrder();
System.out.println("中序遍历:");
binaryTree.infixOrder();
System.out.println("后序遍历:");
binaryTree.postOrder();
}
}
/** 定义二叉树*/
class BinaryTree {
private Node root;
public void setRoot(Node 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("二叉树为空, 无法遍历");
}
}
}
/** 定义节点*/
class Node {
private int no;
private String name;
private Node left;
private Node right;
public Node(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 Node getLeft() {
return left;
}
public void setLeft(Node left) {
this.left = left;
}
public Node getRight() {
return right;
}
public void setRight(Node right) {
this.right = right;
}
@Override
public String toString() {
return "Node [no=" + no + ", name=" + name + "]";
}
/** 前序遍历*/
public void preOrder() {
/** 1. 输出父结点*/
System.out.println(this);
/** 2. 递归向左子树前序遍历*/
if(this.left != null) {
this.left.preOrder();
}
/** 2. 递归向右子树前序遍历*/
if(this.right != null) {
this.right.preOrder();
}
}
/** 中序遍历*/
public void infixOrder() {
/** 1. 递归向左子树中序遍历*/
if(this.left != null) {
this.left.infixOrder();
}
/** 2. 输出父结点*/
System.out.println(this);
/** 3. 递归向右子树中序遍历*/
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);
}
}
输出:
> 前序遍历:
> Node [no=1, name=节点1]
> Node [no=2, name=节点2]
> Node [no=3, name=节点3]
> Node [no=5, name=节点5]
> Node [no=6, name=节点6]
> Node [no=7, name=节点7]
> Node [no=4, name=节点4]
> Node [no=8, name=节点8]
> Node [no=9, name=节点9]
> 中序遍历:
> Node [no=2, name=节点2]
> Node [no=1, name=节点1]
> Node [no=6, name=节点6]
> Node [no=5, name=节点5]
> Node [no=7, name=节点7]
> Node [no=3, name=节点3]
> Node [no=8, name=节点8]
> Node [no=4, name=节点4]
> Node [no=9, name=节点9]
> 后序遍历:
> Node [no=2, name=节点2]
> Node [no=6, name=节点6]
> Node [no=7, name=节点7]
> Node [no=5, name=节点5]
> Node [no=8, name=节点8]
> Node [no=9, name=节点9]
> Node [no=4, name=节点4]
> Node [no=3, name=节点3]
> Node [no=1, name=节点1]
查找节点
public class BinaryTreeApp {
public static void main(String[] args) {
/** 创建二叉树实例*/
BinaryTree binaryTree = new BinaryTree();
/** 创建多个结点*/
Node node1 = new Node(1, "节点1"); // root
Node node2 = new Node(2, "节点2");
Node node3 = new Node(3, "节点3");
Node node4 = new Node(4, "节点4");
Node node5 = new Node(5, "节点5");
/** 设定根节点*/
binaryTree.setRoot(node1);
/** 手动设定各节点*/
node1.setLeft(node2);
node1.setRight(node3);
node3.setRight(node4);
node3.setLeft(node5);
System.out.println("前序遍历查找:");
Node resNode = binaryTree.preOrderSearch(5);
if (resNode != null) {
System.out.printf("找到了, 信息为 no=%d name=%s\n", resNode.getNo(), resNode.getName());
} else {
System.out.printf("没有找到 no=%d", 5);
}
System.out.println("中序遍历查找:");
Node resNode2 = binaryTree.infixOrderSearch(5);
if (resNode2 != null) {
System.out.printf("找到了, 信息为 no=%d name=%s\n", resNode2.getNo(), resNode2.getName());
} else {
System.out.printf("没有找到 no=%d", 5);
}
System.out.println("后序遍历查找:");
Node resNode3 = binaryTree.postOrderSearch(5);
if (resNode3 != null) {
System.out.printf("找到了, 信息为 no=%d name=%s\n", resNode3.getNo(), resNode3.getName());
} else {
System.out.printf("没有找到 no=%d", 5);
}
}
}
/** 定义二叉树*/
class BinaryTree {
private Node root;
public void setRoot(Node root) {
this.root = root;
}
/** 前序遍历查找*/
public Node preOrderSearch(int no) {
if(root != null) {
return root.preOrderSearch(no);
} else {
return null;
}
}
/** 中序遍历查找*/
public Node infixOrderSearch(int no) {
if(root != null) {
return root.infixOrderSearch(no);
}else {
return null;
}
}
/** 后序遍历查找*/
public Node postOrderSearch(int no) {
if(root != null) {
return this.root.postOrderSearch(no);
}else {
return null;
}
}
}
/** 定义节点*/
class Node {
private int no;
private String name;
private Node left;
private Node right;
public Node(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 Node getLeft() {
return left;
}
public void setLeft(Node left) {
this.left = left;
}
public Node getRight() {
return right;
}
public void setRight(Node right) {
this.right = right;
}
@Override
public String toString() {
return "Node [no=" + no + ", name=" + name + "]";
}
/** 前序遍历查找*/
public Node preOrderSearch(int no) {
System.out.println("进入前序遍历");
/** 判断要查找的节点是否为当前节点*/
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;
}
/** 中序遍历查找*/
public Node infixOrderSearch(int no) {
Node resNode = null;
/** 左递归中序查找*/
if(this.left != null) {
resNode = this.left.infixOrderSearch(no);
}
/** 说明左子树中找到了指定节点*/
if(resNode != null) {
return resNode;
}
System.out.println("进入中序查找");
/** 判断要查找的节点是否为当前节点*/
if(this.no == no) {
return this;
}
/** 右递归中序查找*/
if(this.right != null) {
resNode = this.right.infixOrderSearch(no);
}
return resNode;
}
/** 后序遍历查找*/
public Node postOrderSearch(int no) {
Node resNode = null;
/** 左递归后序查找*/
if(this.left != null) {
resNode = this.left.postOrderSearch(no);
}
/** 说明左子树中找到了指定节点*/
if(resNode != null) {
return resNode;
}
/** 右递归后序查找*/
if(this.right != null) {
resNode = this.right.postOrderSearch(no);
}
/** 说明右子树中找到了指定节点*/
if(resNode != null) {
return resNode;
}
System.out.println("进入后序查找");
/** 判断要查找的节点是否为当前节点*/
if(this.no == no) {
return this;
}
return resNode;
}
}
输出:
> 前序遍历查找: 遍历次数为4次
> 进入前序遍历
> 进入前序遍历
> 进入前序遍历
> 进入前序遍历
> 找到了, 信息为 no=5 name=节点5
> 中序遍历查找: 遍历次数为3次
> 进入中序查找
> 进入中序查找
> 进入中序查找
> 找到了, 信息为 no=5 name=节点5
> 后序遍历查找: 遍历次数为2次
> 进入后序查找
> 进入后序查找
> 找到了, 信息为 no=5 name=节点5
删除节点
- 规则: 要删除的节点, 如果是非叶子节点, 则删除该子树
public class BinaryTreeApp {
public static void main(String[] args) {
/** 创建二叉树实例*/
BinaryTree binaryTree = new BinaryTree();
/** 创建多个结点*/
Node node1 = new Node(1, "节点1"); // root
Node node2 = new Node(2, "节点2");
Node node3 = new Node(3, "节点3");
Node node4 = new Node(4, "节点4");
Node node5 = new Node(5, "节点5");
/** 设定根节点*/
binaryTree.setRoot(node1);
/** 手动设定各节点*/
node1.setLeft(node2);
node1.setRight(node3);
node3.setRight(node4);
node3.setLeft(node5);
System.out.println("删除前, 前序遍历");
binaryTree.preOrder();
binaryTree.delNode(5);
System.out.println("删除后, 前序遍历");
binaryTree.preOrder();
}
}
/** 定义二叉树*/
class BinaryTree {
private Node root;
public void setRoot(Node root) {
this.root = root;
}
/** 删除结点*/
public void delNode(int no) {
if(root != null) {
/** 删除结点*/
if(root.getNo() == no) {
root = null;
} else {
/** 递归删除*/
root.delNode(no);
}
}else{
System.out.println("空树, 不能删除");
}
}
/** 前序遍历*/
public void preOrder() {
if(this.root != null) {
this.root.preOrder();
}else {
System.out.println("二叉树为空, 无法遍历");
}
}
}
/** 定义节点*/
class Node {
private int no;
private String name;
private Node left;
private Node right;
public Node(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 Node getLeft() {
return left;
}
public void setLeft(Node left) {
this.left = left;
}
public Node getRight() {
return right;
}
public void setRight(Node right) {
this.right = right;
}
@Override
public String toString() {
return "Node [no=" + no + ", name=" + name + "]";
}
/** 删除结点*/
public void delNode(int no) {
/** 如果当前结点的左子结点不为空, 且左子结点就是要删除结点, this.left = null; (结束递归删除)*/
if(this.left != null && this.left.no == no) {
this.left = null;
return;
}
/** 如果当前结点的右子结点不为空, 且右子结点就是要删除结点, this.right= null; (结束递归删除)*/
if(this.right != null && this.right.no == no) {
this.right = null;
return;
}
/** 向左子树进行递归删除*/
if(this.left != null) {
this.left.delNode(no);
}
/** 向右子树进行递归删除*/
if(this.right != null) {
this.right.delNode(no);
}
}
/** 前序遍历*/
public void preOrder() {
/** 输出父结点*/
System.out.println(this);
/** 递归向左子树前序遍历*/
if(this.left != null) {
this.left.preOrder();
}
/** 递归向右子树前序遍历*/
if(this.right != null) {
this.right.preOrder();
}
}
}
输出:
> 删除前, 前序遍历
> Node [no=1, name=节点1]
> Node [no=2, name=节点2]
> Node [no=3, name=节点3]
> Node [no=5, name=节点5]
> Node [no=4, name=节点4]
> 删除后, 前序遍历
> Node [no=1, name=节点1]
> Node [no=2, name=节点2]
> Node [no=3, name=节点3]
> Node [no=4, name=节点4]
如果您觉得有帮助,欢迎点赞哦 ~ 谢谢!!