二分搜索树
今天我们尝试构建一颗二分搜索树,很多同学只有理论,并没有对树有其编码实践。通过一步步的实现一颗二分搜索树,加深对数据结构树的理解。
二分搜索树,又名二分排序树,有人也叫它二分查找树。
特点
二分搜索树是二叉树, 每个节点的值大于所有左子树节点的值;小于所有右子树节点的值。
每一课子树都是二分搜索树。
二分搜索树java实现
定义树中的节点
public class Node<E>{public E data;public Node<E> left;public Node<E> right;public Node(E data) {this.data = data;}public E getData() {return data;}public void setData(E data) {this.data = data;}public Node<E> getLeft() {return left;}public void setLeft(Node<E> left) {this.left = left;}public Node<E> getRight() {return right;}public void setRight(Node<E> right) {this.right = right;}@Overridepublic String toString() {return "Node{" +"data=" + data +", left=" + left +", right=" + right +'}';}
}
构建树模型
第一种方式
使用递归的方式插入节点,构建二分搜索树模型
public class BinaryTree<E extends Comparable<E>> {private int size; //定义树中的节点数量public Node<E> insert(Node<E> root, E data) {if (root == null) {root = new Node<>(data);size++;return root;}if (data.compareTo(root.data) < 0) {root.left = insert(root.left, data);}if (data.compareTo(root.data) > 0) {root.right = insert(root.right, data);}return root;}
测试程序
Node<Integer> root = new Node<>(35);BinaryTree<Integer> bst = new BinaryTree<>();
bst.insert(root, 32);
bst.insert(root, 12);
bst.insert(root, 55);
bst.insert(root, 10);
bst.insert(root, 77);
bst.insert(root, 11);
bst.insert(root, 6);
bst.insert(root, 72);
bst.insert(root, 53);new TreePrint<Integer>().print(root);
第二种方式
使用循环的方式检查是否存在节点,如果没有节点则添加节点。
public class BinaryTreex<E extends Comparable<E>> {private Node<E> root;public BinaryTreex(E data) {this.root = new Node<>(data);}public Node<E> getRoot(){return this.root;}public void insert(E data) {Node<E> currNode = root;while (currNode != null) {if (data.compareTo(currNode.data) > 0) {if (currNode.right == null) {currNode.right = new Node<>(data);return;}currNode = currNode.right;} else {if (currNode.left == null) {currNode.left = new Node<>(data);return;}currNode = currNode.left;}}}
}
运行结构
附录:图形打印二叉树
参考引用来自:https://blog.csdn.net/m0_37550986/article/details/126013196。稍作修改
我们采用中序方式遍历所有节点,使用层序方式从上到下打印节点。
package com.ffyc.tree.bst;import java.util.*;/*** 中序图形效果打印** @param <E>*/
public class TreePrint<E> {private final List<Node<E>> mid = new ArrayList<>();//记录bst树的节点private final Map<Node<E>, Integer> map = new HashMap<>();//记录节点及位置private Queue<E> queue = new ArrayDeque<>();private Node<E> root;public TreePrint() {}public TreePrint(Node<E> root) {this.root = root;}/*** 中序遍历** @param root 树的根节点*/public void inOrder(Node<E> root) {if (root == null) {return;}inOrder(root.left);mid.add(root);inOrder(root.right);}/*** 使用Map记录节点及位置** @param root*/public void init(Node<E> root) {if (root == null) {return;}inOrder(root);for (int i = 0; i < mid.size(); i++) {map.put(mid.get(i), i);}}/*** 打印同一层的节点,使用|线和值进行拼接打印** @param nodes*/void printLevelNodes(List<Node<E>> nodes) {StringBuilder VLine = new StringBuilder();StringBuilder dataLine = new StringBuilder();StringBuilder line = new StringBuilder();int lastNodeIndex = 0;int lastRightIndex = 0;for (Node<E> node : nodes) {int x = map.get(node);String addEmpty = getEmpty(x - lastNodeIndex);lastNodeIndex = x;VLine.append(addEmpty).append("|");//竖线拼接dataLine.append(addEmpty).append(node.data); //值拼接Node<E> left = node.left;Node<E> right = node.right;String leftLine = null;String rightLine = null;int leftIndex = -1;int rightIndex = -1;if (left != null) {leftIndex = map.get(left);leftLine = getLineToChildren(x - leftIndex);}if (right != null) {rightIndex = map.get(right);rightLine = getLineToChildren(rightIndex - x);}String curLine = (leftLine == null ? "" : leftLine) + "|" + (rightLine == null ? "" : rightLine);if (leftLine == null && rightLine == null) curLine = "";//线段之间的间隔int dif = (leftIndex == -1 ? x : leftIndex) - lastRightIndex;String difEmpty = getEmpty(dif);line.append(difEmpty).append(curLine);//拼接线段lastRightIndex = rightIndex == -1 ? x : rightIndex;}System.out.println(VLine + "\n" + dataLine + "\n" + line);}String getEmpty(int x) {StringBuilder empty = new StringBuilder();for (int i = 0; i < x; i++) {empty.append("\t");}return empty.toString();}//链接子线段的长度String getLineToChildren(int end) {StringBuilder line = new StringBuilder();if (end == 0) return line.toString();for (int i = 0; i < end; i++) {line.append("____");}return line.toString();}/*** 扫描每一行中每一个节点的左右节点** @param lineNodes 每一行的节点*/public void topToDownLevelPrint(List<Node<E>> lineNodes) {if (lineNodes.isEmpty()) return;printLevelNodes(lineNodes);//打印同一层的节点List<Node<E>> children = new ArrayList<>(); //记录当前节点下的所有子节点//记录当前节点下的所有左右节点for (Node<E> currentNode : lineNodes) {if (currentNode.left != null) children.add(currentNode.left);if (currentNode.right != null) children.add(currentNode.right);}topToDownLevelPrint(children);//递归打印下一层节点}/*** 调用此方法完成二分搜索树打印* @param root : 根节点*/public void print(Node<E> root) {init(root);topToDownLevelPrint(new ArrayList<Node<E>>() {{add(root);}});}
}