什么是二叉树
二叉树是指树中节点的度不大于2的有序树,也就是说这颗树有且只有一个根节点,且分支不得大于2。具体想了解树以及二叉树的朋友请看https://www.jianshu.com/p/bf73c8d50dc2,里边详细介绍了。本文中重点说明查找二叉树。本文参考https://www.cnblogs.com/yandufeng/p/10845118.html(本文和这位大佬的文章大相径庭,但我在他基础上改成我想要的结果),以及程序员小灰的公众号文章https://mp.weixin.qq.com/s/-8JFh5iLr88XA4AJ9mMf6g。
查找二叉树的条件
1.左子树上所有结点的值均小于或等于它的根结点的值。
2.右子树上所有结点的值均大于或等于它的根结点的值。
3.左、右子树也分别为二叉排序树。
如图所示,
构建二叉树
构建节点类
@Data
public class Node {
Integer id;
Node left;
Node right;
Node(Integer id){
this.id = id;
this.left = null;
this.right = null;
}
Node() {
this.id = null;
this.left = null;
this.right = null;
}
}
整体树类
包含根节点
@Data
public class BinaryTree extends Node{
private Node root;
}
添加节点
/*
首先我们必须找到新节点的位置,是为了保持树排序。从根节点开始,必须遵循下面的规则:
如果新节点小于当前的值,将会进入左子树。
如果新节点大于当前的节点,将会进入右子树。
当当前的节点是null时,我们已经到达叶子节点,我们可以添加新节点到这个位置。
*/
public Node addNode(Node currentNode, int value) {
//第一次创建,从根节点开始
if (currentNode == null){
return new Node(value);
}
if (value< currentNode.getId()){ //如果新节点小于当前的值,将会进入左子树。
currentNode.left =addNode(currentNode.left, value);
}else {
currentNode.right =addNode(currentNode.right, value);
}
return currentNode;
}
public void addNode(int value) {
root = addNode(root,value);
}
查找节点以及其子节点
public BinaryTree selectNode(int value,Node current){
BinaryTree binaryTree = new BinaryTree();
if (current == null){
return null;
}
if (value == current.id){
binaryTree.root = current;
return binaryTree;
}else {
if (value<root.id){
current=root.left;
}else {
current=root.right;
}
return selectNode(value,current);
}
}
删除节点
public Node deleteNode(Node current, int value) {
if (current == null) {
return null;
}
if (value == current.id) {
// 开启下边方法删除单个节点
// if (current.left == null && current.right == null) {
// return null;
// }
// if (current.left == null) {
// return current.right;
// }
// if (current.right == null) {
// return current.left;
// }
// int id = findNode(current.right);
// current.id = id;
// current.right = deleteNode(current.right, id);
// return current;
// 删除当前节点下的子节点
// current.left = null;
// current.right = null;
// return current;
// 删除本节点及其子节点
// return null;
}
if(value < root.id) {
current.left = deleteNode(current.left, value);
}
current.right = deleteNode(current.right, value);
return current;
}
public BinaryTree deleteNode(BinaryTree binaryTree, int value){
Node node = deleteNode(binaryTree.root, value);
if (node!=null){
binaryTree.root = node;
return binaryTree;
}
return null;
}
private int findNode(Node root) {
return root.left == null ? root.id : findNode(root.right);
}
遍历树
这个就跟那位老哥写的一样了,简单易懂。
我们将以不同的方式遍历树,以depth-first,breadth-first方式遍历树。
以Depth-First遍历树
Depth-first查询是一种在查询兄弟节点之前,尽可能的查询每个子节点。
in-order,pre-order,post-order方式都是以depth-first方式遍历树的。
in-order遍历是首先遍历左子树,然后root节点,最后是右子树。
public void traverseInOrder(Node root) {
if (root != null) {
traverseInOrder(root.left);
System.out.println(root.data);
traverseInOrder(root.right);
}
}
pre-order遍历首先是root节点,然后是左子树,最后是右子树。
public void traversePreOrder(Node root) {
if (root != null) {
System.out.println(root.data);
traversePreOrder(root.left);
traversePreOrder(root.right);
}
}
post-order遍历首先是遍历左子树,然后是右子树,最后是root节点。
public void traversePostOrder(Node root) {
if (root != null) {
traversePostOrder(root.left);
traversePostOrder(root.right);
System.out.println(root.data);
}
}
以Breadth-First遍历
它在遍历下一级的节点之前,会遍历当前级的所有节点。
这种类型的遍历也叫做level-order,遍历树从root节点开始,从左到右。
为了实现,使用队列来存储每个级别的节点。我们将会从列表中获取每个节点。然后添加他的子节点到队列中。
public void traverseLevelOrder(Node root) {
if (root == null) {
return;
}
Queue<Node> nodes = new LinkedList<Node>();
nodes.add(root);
while(!nodes.isEmpty()) {
Node node = nodes.remove();
System.out.println(node.data);
if (node.left != null) {
nodes.add(node.left);
}
if (node.right != null) {
nodes.add(node.right);
}
}
}
测试
创建树
@Test
public void Nodes() {
//创建树
BinaryTree binaryTree = new BinaryTree();
binaryTree.addNode(5 );
binaryTree.addNode(3 );
binaryTree.addNode(7);
binaryTree.addNode(2);
binaryTree.addNode(4);
binaryTree.addNode(6);
binaryTree.addNode(8);
//查询节点
BinaryTree binaryTreeSun = binaryTree.selectNode(7,binaryTree.getRoot());
System.err.println(binaryTreeSun.toString());
binaryTree.traverseLevelOrder(binaryTree.getRoot());
//删除节点
BinaryTree binaryTrees = binaryTree.deleteNode(binaryTree,7);
System.err.println(binaryTrees.toString());
}
创建树完成后树结构为
查询节点树结构为
删除节点树结构为