definition
Definition: A BST is a binary tree in which each node contains a Comparable key (and an associated value value) and each node's key is greater than the key of any node in its left subtree and less than the key of any node in its right subtree The key of any node.
data structure
The tree consists of Node objects, each with a pair of keys, two links, and a node counter N. Each Node object is the root node of a subtree containing N nodes. Its left link points to a binary search tree consisting of all keys smaller than the node, and its right link points to a tree with keys larger than the node. A binary search tree of all keys. In the BST class, a Node object root should also be defined, pointing to the root node of the current binary tree.
public class BST<Key extends Comparable<Key>, Value> { private class Node { private Key key; //键 private Value value; //值 private Node left,right; //Left subtree and right subtree private int N; //The total number of all nodes in the subtree rooted at this node public Node(Key key, Value value, int N) { //Note that you need to take the total number of nodes N as a parameter this.key = key; this.value = value; this.N = N; } } private Node root; //root node of binary search tree private int size(Node x) { //As a private method, find the size of each subtree if(x == null) return 0; else return x.N; } public int size() { //Public method, find the total number of nodes in the entire tree return size(root); } }
Operations on binary search trees
Insert and find operations
These two operations are relatively simple, just look at the code directly:
public void put(Key key, Value value) { //Find the key, find and update its value, otherwise create a new node and get a new binary search tree root = put(root, key, value); } private Node put(Node x, Key key, Value value) { //If the key exists in the subtree rooted at x, update its value; //Otherwise insert the new node with key and value into the appropriate position of the subtree if(x == null) return new Node(key, value, 1); int cmp = key.compareTo(x.key); if(cmp < 0) x.left = put(x.left, key, value); else if(cmp > 0) x.right = put(x.right, key, value); else x.value = value; x.N = size(x.left) + size(x.right) + 1; return x; } public Value get(Key key) { return get(root, key); } private Value get(Node x, Key key) { //Find and return the value corresponding to key in the tree with x as the root node; // if not found, return null if(x == null) return null; int cmp = key.compareTo(x.key); if(cmp < 0) return get(x.left, key); else if(cmp > 0) return get(x.right, key); else return x.value; }
Here, a public method and a private method are defined to implement an operation, and the operations are implemented recursively. Note that the number of nodes must be changed.
Ordering related methods and delete operations
Max and Min keys
If the left link of the root node is empty, then the smallest key in a binary search tree is the root node; if the left link is not empty, the smallest key in the tree is the smallest key in the left subtree. The same is true for the largest key.
public Key min() { return min(root).key; } private Node min(Node x) { if(x.left == null) return x; return min(x.left); } public Key max() { return max(root).key; } private Node max(Node x) { if(x.right == null) return x; return max(x.right); }
selection and ranking
public Key select(int k) { //Return the node with rank k, starting from 1 return select(root, k).key; } private Node select(Node x, int k) { if(x == null) return null;//The ranking starts from 1 int t = size(x.left) + 1; if (t > k) return select(x.left, k); else if (t < k) return select(x.right, k - t); else return x; } public int rank(Key key) { // Given a node, return its rank return rank(root, key); } private int rank(Node x, Key key) { if(x == null) return 0; int cmp = key.compareTo(x.key); if (cmp < 0) return rank(x.left, key); else if (cmp > 0) return 1 + size(x.left) + rank(x.right, key); else return size(x.left) + 1;//The ranking starts from 1 }
In the select operation, a node with a key rank of k is found, and the rank operation is the opposite, which is to find the rank of a key.
Delete the largest key and the smallest key
Remove the smallest key:
- Recursively traverse to the left until the left link of the node is empty;
- Replace the node with the node's right node;
- Update the number of nodes N of the subtree.
public void deleteMin() { root = deleteMin(root); } private Node deleteMin(Node x) { //delete the smallest node of the subtree rooted at node x if(x.left == null) return x.right; x.left = deleteMin(x.left); x.N = size(x.left) + size(x.right) + 1; return x; } public void deleteMax() { root = deleteMax(root); } private Node deleteMax(Node x) { //delete the largest node of the subtree rooted at node x if(x.right == null) return x.left; x.right = deleteMax(x.right); x.N = size(x.left) + size(x.right) + 1; return x; }
delete operation
We can delete any node with only one child in a similar way to deleting the smallest key, but how do we delete a node with two children?
Proceed as follows:
- Save the link to the node to be deleted as t;
- Point x to its successor node min(t.right);
- Point the right link of x to deleteMin(t.right), that is, the sub-binary search tree where all nodes are still greater than x.key after deletion;
- Set the left link of x (empty in the example above) to t.left.
The link and node counters need to be updated after the recursive call.
public void delete(Key key) { root = delete(root, key); } private Node delete(Node x, Key key) { //Delete this node of key in the tree with x as the root node if(x == null) return null; int cmp = key.compareTo(x.key); if (cmp < 0) x.left = delete(x.left, key); else if (cmp > 0) x.right = delete(x.right, key); else { if(x.right == null) return x.left; if(x.left == null) return x.right; Node t = x; x = min(x.right); x.right = deleteMin(t.right); x.left = t.left; } x.N = size(x.left) + size(x.right) + 1; return x; }
The complete code of java implementation
public class BST<Key extends Comparable<Key>, Value> { private class Node { private Key key; //键 private Value value; //值 private Node left,right; //Left subtree and right subtree private int N; //The total number of all nodes in the subtree rooted at this node public Node(Key key, Value value, int N) { //Note that you need to take the total number of nodes N as a parameter this.key = key; this.value = value; this.N = N; } } private Node root; //root node of binary search tree private int size(Node x) { //As a private method, find the size of each subtree if(x == null) return 0; else return x.N; } public int size() { //Public method, find the total number of nodes in the entire tree return size(root); } public void put(Key key, Value value) { //Find the key, find and update its value, otherwise create a new node and get a new binary search tree root = put(root, key, value); } private Node put(Node x, Key key, Value value) { //If the key exists in the subtree rooted at x, update its value; //Otherwise insert the new node with key and value into the appropriate position of the subtree if(x == null) return new Node(key, value, 1); int cmp = key.compareTo(x.key); if(cmp < 0) x.left = put(x.left, key, value); else if(cmp > 0) x.right = put(x.right, key, value); else x.value = value; x.N = size(x.left) + size(x.right) + 1; return x; } public Value get(Key key) { return get(root, key); } private Value get(Node x, Key key) { //Find and return the value corresponding to key in the tree with x as the root node; // if not found, return null if(x == null) return null; int cmp = key.compareTo(x.key); if(cmp < 0) return get(x.left, key); else if(cmp > 0) return get(x.right, key); else return x.value; } public Key min() { return min(root).key; } private Node min(Node x) { if(x.left == null) return x; return min(x.left); } public Key max() { return max(root).key; } private Node max(Node x) { if(x.right == null) return x; return max(x.right); } public Key select(int k) { //Return the node with rank k, starting from 1 return select(root, k).key; } private Node select(Node x, int k) { if(x == null) return null;//The ranking starts from 1 int t = size(x.left) + 1; if (t > k) return select(x.left, k); else if (t < k) return select(x.right, k - t); else return x; } public int rank(Key key) { // Given a node, return its rank return rank(root, key); } private int rank(Node x, Key key) { if(x == null) return 0; int cmp = key.compareTo(x.key); if (cmp < 0) return rank(x.left, key); else if (cmp > 0) return 1 + size(x.left) + rank(x.right, key); else return size(x.left) + 1;//The ranking starts from 1 } public void deleteMin() { root = deleteMin(root); } private Node deleteMin(Node x) { //delete the smallest node of the subtree rooted at node x if(x.left == null) return x.right; x.left = deleteMin(x.left); x.N = size(x.left) + size(x.right) + 1; return x; } public void deleteMax() { root = deleteMax(root); } private Node deleteMax(Node x) { //delete the largest node of the subtree rooted at node x if(x.right == null) return x.left; x.right = deleteMax(x.right); x.N = size(x.left) + size(x.right) + 1; return x; } public void delete(Key key) { root = delete(root, key); } private Node delete(Node x, Key key) { //Delete this node of key in the tree with x as the root node if(x == null) return null; int cmp = key.compareTo(x.key); if (cmp < 0) x.left = delete(x.left, key); else if (cmp > 0) x.right = delete(x.right, key); else { if(x.right == null) return x.left; if(x.left == null) return x.right; Node t = x; x = min(x.right); x.right = deleteMin(t.right); x.left = t.left; } x.N = size(x.left) + size(x.right) + 1; return x; } public static void main(String[] args) { BST<String, Integer> bst = new BST<String, Integer>(); bst.put("a", 1); bst.put("f", 5); bst.put("b", 2); bst.put("c", 3); System.out.println(bst.max()); bst.delete("f"); System.out.println(bst.max()); } }