10、二分搜索树
1、二分搜索树的结构
2、实现二分搜索树
深度优先
- 前序遍历:中左右
- 中序遍历:左中右,二分搜索树的中序遍历结果是顺序的
- 后序遍历:左右中,为二分搜索树释放内存
广度优先
- 层序遍历:更快找到问题的解,常用于算法设计中 - 无权图最短路径
/**
* 二分搜索树: Binary Search Tree
* 存储的元素必须可比较
* 对重复元素不做处理
* 增、删、查: 最差 O(n), 平均 O(h), h = logN
*/
public class BST<E extends Comparable<E>> {
private class Node {
public E e;
public Node left;
public Node right;
public Node(E e) {
this.e = e;
this.left = null;
this.right = null;
}
}
private Node root;
private int size;
public BST() {
root = null;
size = 0;
}
public int size() {
return size;
}
public boolean isEmpty() {
return size == 0;
}
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;
}
public boolean contains(E e) {
return contains(root, e);
}
/**
* 在以 node 为根节点的二分搜索树中搜索是否存在元素 e
*/
private boolean contains(Node node, E e) {
if (node == null) return false;
if (e.compareTo(node.e) == 0) return true;
if (e.compareTo(node.e) < 0) return contains(node.left, e);
return contains(node.right, e);
}
public E minimum() {
if (size == 0) throw new RuntimeException("BST is empty!");
return minimum(root).e;
}
/**
* 返回以 node 为根节点的二分搜索树中的最小元素所在的节点
*/
private Node minimum(Node node) {
if (node.left == null) return node;
return minimum(node.left);
}
public E maximum() {
if (size == 0) throw new RuntimeException("BST is empty!");
return maximum(root).e;
}
/**
* 返回以 node 为根节点的二分搜索树中的最大元素所在的节点
*/
private Node maximum(Node node) {
if (node.right == null) return node;
return maximum(node.right);
}
public E removeMin() {
E min = minimum();
root = removeMin(root);
return min;
}
/**
* 删除以 node 为根节点的二分搜索树的最小元素所在的节点, 并返回新的根节点
*/
private Node removeMin(Node node) {
if (node.left == null) {
Node rightNode = node.right;
node.right = null;
size--;
return rightNode;
}
node.left = removeMin(node.left);
return node;
}
public E removeMax() {
E max = maximum();
root = removeMax(root);
return max;
}
/**
* 删除以 node 为根节点的二分搜索树的最大元素所在的节点, 并返回新的根节点
*/
private Node removeMax(Node node) {
if (node.right == null) {
Node leftNode = node.left;
node.left = null;
size--;
return leftNode;
}
node.right = removeMax(node.right);
return node;
}
public void remove(E e) {
root = remove(root, e);
}
/**
* 以 node 为根节点的二分搜索树, 删除指定元素 e 所在的节点, 并返回新的根节点
*/
private Node remove(Node node, E e) {
if (node == null) return null;
if (e.compareTo(node.e) < 0) {
node.left = remove(node.left, e);
return node;
} else if (e.compareTo(node.e) > 0) {
node.right = remove(node.right, e);
return node;
} else {
if (node.left == null) {
Node rightNode = node.right;
node.right = null;
size--;
return rightNode;
} else if (node.right == null) {
Node leftNode = node.left;
node.left = null;
size--;
return leftNode;
} else {
// 待删除节点左右子树均不为空
// 找到比待删除节点大的最小节点, 即待删除节点右子树的最小节点, 它是后继节点
// 用这个节点顶替待删除节点的位置
Node successor = minimum(node.right);
successor.right = removeMin(node.right); // 已经 size-- 了
successor.left = node.left;
node.left = node.right = null;
return successor;
}
}
}
public void preOrder() {
preOrder(root);
}
/**
* 对以 node 为根节点的二分搜索树进行前序遍历
*/
private void preOrder(Node node) {
if (node == null) return;
System.out.println(node.e);
preOrder(node.left);
preOrder(node.right);
}
public void inOrder() {
inOrder(root);
}
/**
* 对以 node 为根节点的二分搜索树进行中序遍历
*/
private void inOrder(Node node) {
if (node == null) return;
inOrder(node.left);
System.out.println(node.e);
inOrder(node.right);
}
public void postOrder() {
postOrder(root);
}
/**
* 对以 node 为根节点的二分搜索树进行后序遍历
*/
private void postOrder(Node node) {
if (node == null) return;
postOrder(node.left);
postOrder(node.right);
System.out.println(node.e);
}
/**
* 二分搜索树的层序遍历
*/
public void levelOrder() {
Queue<Node> queue = new LoopQueue<>();
queue.enqueue(root);
Node cur;
while (!queue.isEmpty()) {
cur = queue.dequeue();
System.out.println(cur.e);
if (cur.left != null) queue.enqueue(cur.left);
if (cur.right != null) queue.enqueue(cur.right);
}
}
@Override
public String toString() {
StringBuilder sb = new StringBuilder();
generateBSTString(root, 0, sb);
return sb.toString();
}
/**
* 生成以 node 为根节点, depth 为深度的描述二叉树的字符串
*/
private void generateBSTString(Node node, int depth, StringBuilder sb) {
if (node == null) {
sb.append(generateDepthString(depth)).append("null\n");
return;
}
sb.append(generateDepthString(depth)).append(node.e).append("\n");
generateBSTString(node.left, depth + 1, sb);
generateBSTString(node.right, depth + 1, sb);
}
private String generateDepthString(int depth) {
return "--".repeat(Math.max(0, depth));
}
/**
* 寻找 e 的 floor 值
* 不存在时返回 null(e 比 BST 中的最小值还小)
*/
public E floor(E e) {
if (isEmpty() || e.compareTo(minimum()) < 0) return null;
return floor(root, e).e;
}
/**
* 在以 node 为根节点的二分搜索树中搜索元素 e 的 floor 节点
*/
private Node floor(Node node, E e) {
if (node == null) return null;
if (node.e.compareTo(e) == 0) return node;
if (node.e.compareTo(e) > 0) return floor(node.left, e);
Node tempNode = floor(node.right, e);
return tempNode != null ? tempNode : node;
}
/**
* 寻找 e 的 ceil 值
* 不存在时返回 null(e 比 BST 中的最大值还大)
*/
public E ceil(E e) {
if (isEmpty() || e.compareTo(maximum()) > 0) return null;
return ceil(root, e).e;
}
/**
* 在以 node 为根节点的二分搜索树中搜索元素 e 的 ceil 节点
*/
private Node ceil(Node node, E e) {
if (node == null) return null;
if (node.e.compareTo(e) == 0) return node;
if (node.e.compareTo(e) < 0) return ceil(node.right, e);
Node tempNode = ceil(node.left, e);
return tempNode != null ? tempNode : node;
}
}
3、BST 集合
public interface Set<E> {
void add(E e);
void remove(E e);
boolean contains(E e);
int getSize();
boolean isEmpty();
}
/**
* 基于二分搜索树 BST 实现的 Set, 存储的元素必须可比较
*/
public class BSTSet<E extends Comparable<E>> implements Set<E> {
private final BST<E> bst;
public BSTSet() {
bst = new BST<>();
}
@Override
public void add(E e) {
bst.add(e);
}
@Override
public void remove(E e) {
bst.remove(e);
}
@Override
public boolean contains(E e) {
return bst.contains(e);
}
@Override
public int getSize() {
return bst.size();
}
@Override
public boolean isEmpty() {
return bst.isEmpty();
}
}
4、BST 映射
public interface Map<K, V> {
void add(K key, V value);
V remove(K key);
boolean contains(K key);
V get(K key);
void set(K key, V newValue);
int getSize();
boolean isEmpty();
}
/**
* key 不能重复, 且必须可比较
*/
public class BSTMap<K extends Comparable<K>, V> implements Map<K, V> {
private class Node {
public K key;
public V value;
public Node left;
public Node right;
public Node(K key, V value) {
this.key = key;
this.value = value;
this.left = null;
this.right = null;
}
}
private Node root;
private int size;
public BSTMap() {
root = null;
size = 0;
}
/**
* 返回以 node 为根节点的二分搜索树中, 键为 key 所在的节点
*/
private Node getNode(Node node, K key) {
if (node == null) return null;
if (key.compareTo(node.key) == 0) return node;
if (key.compareTo(node.key) < 0) return getNode(node.left, key);
return getNode(node.right, key);
}
@Override
public void add(K key, V value) {
root = add(root, key, value);
}
/**
* 向以 node 为根节点的二分搜索树中添加元素 (key, value), 并返回新的根节点
*/
private Node add(Node node, K key, V value) {
if (node == null) {
size++;
return new Node(key, value);
}
if (key.compareTo(node.key) < 0) node.left = add(node.left, key, value);
else if (key.compareTo(node.key) > 0) node.right = add(node.right, key, value);
else node.value = value;
return node;
}
/**
* 返回以 node 为根节点的二分搜索树中的最小元素所在的节点
*/
private Node minimum(Node node) {
if (node.left == null) return node;
return minimum(node.left);
}
/**
* 删除以 node 为根节点的二分搜索树的最小元素所在的节点, 并返回新的根节点
*/
private Node removeMin(Node node) {
if (node.left == null) {
Node rightNode = node.right;
node.right = null;
size--;
return rightNode;
}
node.left = removeMin(node.left);
return node;
}
@Override
public V remove(K key) {
Node node = getNode(root, key);
if (node != null) {
root = remove(root, key);
return node.value;
}
return null;
}
/**
* 以 node 为根节点的二分搜索树, 删除键为 key 所在的节点, 并返回新的根节点
*/
private Node remove(Node node, K key) {
if (node == null) return null;
if (key.compareTo(node.key) < 0) {
node.left = remove(node.left, key);
return node;
} else if (key.compareTo(node.key) > 0) {
node.right = remove(node.right, key);
return node;
} else {
if (node.left == null) {
Node rightNode = node.right;
node.right = null;
size--;
return rightNode;
} else if (node.right == null) {
Node leftNode = node.left;
node.left = null;
size--;
return leftNode;
} else {
Node successor = minimum(node.right);
successor.right = removeMin(node.right);
successor.left = node.left;
node.left = node.right = null;
return successor;
}
}
}
@Override
public boolean contains(K key) {
return getNode(root, key) != null;
}
@Override
public V get(K key) {
Node node = getNode(root, key);
return node != null ? node.value : null;
}
@Override
public void set(K key, V newValue) {
Node node = getNode(root, key);
if (node != null) node.value = newValue;
else throw new IllegalArgumentException(key + " doesn't exist!");
}
@Override
public int getSize() {
return size;
}
@Override
public boolean isEmpty() {
return size == 0;
}
}
5、链表集合
/**
* 基于链表 LinkedList 实现的 Set
*/
public class LinkedListSet<E> implements Set<E> {
private final LinkedList<E> list;
public LinkedListSet() {
list = new LinkedList<>();
}
@Override
public void add(E e) {
if (!list.contains(e)) list.addFirst(e);
}
@Override
public void remove(E e) {
list.removeElement(e);
}
@Override
public boolean contains(E e) {
return list.contains(e);
}
@Override
public int getSize() {
return list.getSize();
}
@Override
public boolean isEmpty() {
return list.isEmpty();
}
}
6、链表映射
/**
* key 不能重复
*/
public class LinkedListMap<K, V> implements Map<K, V> {
private class Node {
public K key;
public V value;
public Node next;
public Node(K key, V value, Node next) {
this.key = key;
this.value = value;
this.next = next;
}
public Node() {
this(null, null, null);
}
@Override
public String toString() {
return key.toString() + " : " + value.toString();
}
}
private final Node dummyHead;
private int size;
public LinkedListMap() {
dummyHead = new Node();
size = 0;
}
private Node getNode(K key) {
Node cur = dummyHead.next;
while (cur != null) {
if (cur.key.equals(key)) return cur;
cur = cur.next;
}
return null;
}
@Override
public void add(K key, V value) {
Node node = getNode(key);
if (node == null) {
dummyHead.next = new Node(key, value, dummyHead.next);
size++;
} else node.value = value;
}
@Override
public V remove(K key) {
Node prev = dummyHead;
while (prev.next != null) {
if (prev.next.key.equals(key)) {
Node delNode = prev.next;
prev.next = delNode.next;
delNode.next = null;
size--;
return delNode.value;
}
prev = prev.next;
}
return null;
}
@Override
public boolean contains(K key) {
return getNode(key) != null;
}
@Override
public V get(K key) {
Node node = getNode(key);
return node != null ? node.value : null;
}
@Override
public void set(K key, V newValue) {
Node node = getNode(key);
if (node != null) node.value = newValue;
else throw new IllegalArgumentException(key + " doesn't exist!");
}
@Override
public int getSize() {
return size;
}
@Override
public boolean isEmpty() {
return size == 0;
}
}
7、二分搜索树非递归
/**
* Binary Search Tree Not Recursion
*/
public class BSTNR<E extends Comparable<E>> {
private class Node {
public E e;
public Node left;
public Node right;
public Node(E e) {
this.e = e;
this.left = null;
this.right = null;
}
}
private Node root;
private int size;
public BSTNR() {
root = null;
size = 0;
}
public int size() {
return size;
}
public boolean isEmpty() {
return size == 0;
}
public void add(E e) {
if (root == null) {
root = new Node(e);
size++;
return;
}
Node parent = root;
while (true) {
if (e.compareTo(parent.e) == 0) return;
if (e.compareTo(parent.e) < 0) {
if (parent.left == null) {
parent.left = new Node(e);
size++;
return;
}
parent = parent.left;
}
if (e.compareTo(parent.e) > 0) {
if (parent.right == null) {
parent.right = new Node(e);
size++;
return;
}
parent = parent.right;
}
}
}
public boolean contains(E e) {
Node cur = root;
while (cur != null) {
if (e.compareTo(cur.e) == 0) return true;
if (e.compareTo(cur.e) < 0) cur = cur.left;
else cur = cur.right;
}
return false;
}
public void preOrder() {
Stack<Node> stack = new ArrayStack<>();
stack.push(root);
Node cur;
while (!stack.isEmpty()) {
cur = stack.pop();
System.out.println(cur.e);
if (cur.right != null) stack.push(cur.right);
if (cur.left != null) stack.push(cur.left);
}
}
public void levelOrder() {
Queue<Node> queue = new LoopQueue<>();
queue.enqueue(root);
Node cur;
while (!queue.isEmpty()) {
cur = queue.dequeue();
System.out.println(cur.e);
if (cur.left != null) queue.enqueue(cur.left);
if (cur.right != null) queue.enqueue(cur.right);
}
}
}
8、更多话题
8.1、二分搜索树的顺序性
- minimum、maximun
- predecessor、successor
- floor、ceil
- rank、select:前序遍历可以实现
8.2、更多拓展
- 维护 size 的二分搜索树
- 维护 depth 的二分搜索树
- 支持重复元素的二分搜索树
- 维护 count 的二分搜索树
本文来自博客园,作者:lidongdongdong~,转载请注明原文链接:https://www.cnblogs.com/lidong422339/p/17304822.html