二分搜索树(校招数据结构最低要求版)Java
二分搜索树(Binary Search Tree,BST)是一种常见的数据结构,它能够高效地存储和查找数据。它的特点是每个节点都包含一个值,并且每个节点的左子树的值都小于节点的值,右子树的值都大于节点的值。
通过这种有序的排列方式,我们可以在二分搜索树中进行高效的查找操作。想象一下,如果我们要查找一个特定的值,我们可以从根节点开始比较它与当前节点的值的大小关系。如果它比当前节点的值小,我们就去左子树中继续查找;如果它比当前节点的值大,我们就去右子树中查找。通过不断地比较和移动,我们最终要么找到了目标值,要么确定它不在树中。
插入
除了查找,二分搜索树还支持插入操作。当我们要插入一个新的值时
我们从根节点开始,比较新值和当前节点的大小关系。
如果它比当前节点的值小,我们就往左子树插入;
如果它比当前节点的值大,我们就往右子树插入。
我们不断地比较和移动,直到找到一个合适的位置,然后将新值插入为一个新的叶子节点。
删除
删除操作稍微复杂一些,因为我们要保持二分搜索树的有序性质。当我们要删除一个节点时,有三种可能的情况需要考虑:
-
如果待删除节点没有子节点,我们可以直接将其删除,不会破坏树的有序性。
-
如果待删除节点只有一个子节点,我们可以将子节点提升到待删除节点的位置上,同样不会破坏有序性。
-
如果待删除节点有两个子节点,我们需要找到它的后继节点(比待删除节点大的最小节点)或前驱节点(比待删除节点小的最大节点)来替代它。我们可以选择将后继节点提升到待删除节点的位置上,或者将前驱节点提升到待删除节点的位置上,然后删除后继或前驱节点。
但是二叉树的删除相对校招并不重要,而且代码过于复杂,所以我们这里就不再细讲,这里只是为了保证知识完整性罗列一下。
前中后序遍历和层序遍历
-
前序遍历:对于每个节点,先访问它自己,然后访问它的左子树,最后访问它的右子树。(根左右)
-
中序遍历:对于每个节点,先访问它的左子树,然后访问它自己,最后访问它的右子树。(左根右)
-
后序遍历:对于每个节点,先访问它的左子树,然后访问它的右子树,最后访问它自己。(左右根)
-
层序遍历:从根节点开始,先访问根节点,然后按照从左到右的顺序依次访问每一层的节点。
这些遍历方式各有特点,适用于不同的应用场景。
前序遍历可以用于复制整个树的结构,
中序遍历可以得到一个有序的节点值序列,
后序遍历常用于释放二叉树的内存,
而层序遍历可以逐层打印树的结构。
二分搜索树的特点在于每个节点的左子树的值都小于节点的值,右子树的值都大于节点的值。这种有序性质使得二分搜索树成为了很多应用中的首选数据结构之一。
代码实现:
package com.Search;
import java.util.LinkedList;
import java.util.Queue;
/**
* @Author: 翰林猿
* @Description: 二分搜索树
**/
public class BSearchTree<E extends Comparable<E>> {
private class Node {
public E e;
public Node left, right;
public Node(E e) {
this.e = e;
left = null;
right = null;
}
}
private int size; //节点数量
private Node root; //根节点
public BSearchTree() {
size = 0;
root = null;
}
public int getSize() {
return size;
}
public boolean isEmpty() {
return size == 0;
}
/**
* @Description: 插入
**/
public void add(E e) {
root = add(root, e);
}
//向以node为根的树插入e元素,返回插入新节点之后的根。
private Node add(Node node, E e) {
if (node == null) { //如果没有该元素,直接返回一个新元素
size++;
return new Node(e);
}
if (e.compareTo(node.e) < 0) //如果小于当前根元素,就往左边递归,
node.left = add(node.left, e); //传入的参数就是左边的子节点(意思就是说,以左节点作为左边的树的树根进行判断是否为空)
else if (e.compareTo(node.e) > 0) //如果大于当前根元素,就往右边递归
node.right = add(node.right, e);
return node;
}
/**
* @Description: 查询
**/
public boolean contains(E e) {
return contains(root, e);
}
private boolean contains(Node node, E e) {
if (node == null)
return false;
if (e.compareTo(node.e) == 0)
return true;
else if (e.compareTo(node.e) > 0) //如果查找的节点大于当前节点,递归去右子树找
return contains(node.right, e);
else //e.compareTo(node.e) > 0 //如果查找的节点小于当前节点,递归去左子树找
return contains(node.left, e);
}
/**
* @Description: 前序遍历,根左右
**/
public void preOrder() {
preOrder(root);
}
private void preOrder(Node node) {
if (node != null) {
System.out.print(node.e + " ");
preOrder(node.left);
preOrder(node.right);
}
}
/**
* @Description: 中序遍历,左根右
**/
public void inOrder() {
inOrder(root);
}
private void inOrder(Node node) {
if (node != null) {
inOrder(node.left);
System.out.print(node.e + " ");
inOrder(node.right);
}
}
/**
* @Description: 后序遍历,左右根
**/
public void postOrder() {
postOrder(root);
}
private void postOrder(Node node) {
if (node != null) {
postOrder(node.left);
postOrder(node.right);
System.out.print(node.e + " ");
}
}
/**
* @Description: 层序遍历,广度优先遍历
* 1.将节点入队,进入循环
* 2.取出一个节点并打印,并将其左右子节点(如果存在)入队。
* 3.重复直到队列为空
**/
public void levelOrder() {
if (root == null) {
return;
}
Queue<Node> queue = new LinkedList<>();
queue.offer(root);
while (!queue.isEmpty()) {
Node node = queue.poll();
System.out.print(node.e + " ");
if (node.left != null) {
queue.offer(node.left);
}
if (node.right != null) {
queue.offer(node.right);
}
}
}
/**
* @Description: 测试用例
*
* 7
* / \
* 4 9
* / \ / \
* 2 5 8 10
* / \ \
* 1 3 11
**/
public static void main(String[] args) {
BSearchTree<Integer> bst = new BSearchTree<>();
bst.add(7);
bst.add(4);
bst.add(9);
bst.add(2);
bst.add(5);
bst.add(8);
bst.add(10);
bst.add(1);
bst.add(3);
bst.add(11);
System.out.println("二叉搜索树节点数量: " + bst.getSize());
System.out.println("是否存在5号节点: " + bst.contains(5));
System.out.println("是否存在100号节点: " + bst.contains(100));
System.out.print("前序遍历: ");
bst.preOrder();
System.out.println();
System.out.print("中序遍历: ");
bst.inOrder();
System.out.println();
System.out.print("后序遍历: ");
bst.postOrder();
System.out.println();
System.out.print("层序遍历: ");
bst.levelOrder();
}
}