BinarySearchTreeMap的實現java
1 public interface Map<K extends Comparable<K>, V> { 2 void put(K k, V v); 3 4 V get(K k); 5 6 void delete(K k); 7 8 boolean contains(K k); 9 10 boolean isEmpty(); 11 12 int size(); 13 14 int size(K lo, K hi); 15 16 K min(); 17 18 K max(); 19 20 K floor(K k); 21 22 K ceiling(K k); 23 24 // the number of keys less than key 25 int rank(K k); 26 27 K select(int k); 28 29 void deleteMin(); 30 31 void deleteMax(); 32 33 // keys in [lo , hi] in sorted order 34 Iterable<K> keys(K lo, K hi); 35 36 Iterable<K> keys(); 37 }
二叉樹的定義node
在計算機科學中,二叉樹是每一個節點最多有兩個子樹的樹結構。一般子樹被稱做「左子樹」(left subtree)和「右子樹」(right subtree)。二叉樹常被用於實現二叉查找樹和二叉堆。二叉樹的左子節點 < 父節點 < 右子節點git
這是typical的二叉樹的樣子, null 表明子節點爲空,從這張圖能夠看出,左子節點 9 小於 父節點 10 小於 右子節點 github
1 private class Node<K, V> { 2 private K k; 3 private V v; 4 private Node<K, V> left; 5 private Node<K, V> right; 6 private int size; 7 Node(K k, V v) { this.k = k; this.v = v; } 8 Node(K k, V v, int size) { this.k = k; this.v = v; this.size = size;} 9 }
二叉樹的插入操做app
假設咱們依次插入 10 , 9, 15, 5 , 7 這5個元素到二叉樹中。see what will happen 這是個動態圖less
1 @Override 2 public void put(K k, V v) { 3 root = put(root, k, v); //root 是根節點 4 } 5 6 private Node<K, V> put(Node<K, V> node, K k, V v) { 7 if (node == null) return new Node<>(k, v, 1); 8 int cmp = node.k.compareTo(k); 9 if (cmp > 0) { //node的k大一點 放到左邊的數中 10 node.left = put(node.left, k, v); 11 } else if (cmp < 0) { //node的k小一點 放到右邊的數中 12 node.right = put(node.right, k, v); 13 } else node.v = v; 14 15 node.size = size(node.left) + size(node.right) + 1; 16 return node; 17 }
二叉樹的get 方法ide
get方法簡單來講就是要找到那個key相同的對象。好比咱們要在「10 , 9, 15, 5 , 7 」上圖所示中找到 7this
1 @Override 2 public V get(K k) { 3 return get(root, k); 4 } 5
6 private V get(Node<K, V> node, K k) { 7
8 if (node == null) return null; //not find
9 else if (node.k.compareTo(k) > 0) { //node的k大一點 放到左邊的數中
10 return get(node.left, k); 11 } else if (node.k.compareTo(k) < 0) { //node的k小一點 放到右邊的數中
12 return get(node.right, k); 13 } else { //equal
14 return node.v; 15 } 16
17 }
二叉樹的刪除操做spa
其實想象一下,當你刪除一個node的時候,你須要找一個替代node來代替這個node。3d
這裏又分3種狀況。首先假設你有以下的樹結構
1.第一種狀況是這個刪除的節點的左右節點都是null。
好比我要刪除3節點。其實只要直接把3節點reset 爲null 就能夠了。變成以下
2.第二種狀況是刪除的節點的2個子節點中有一個子節點爲null
好比我要刪除15。 15 的左節點是12 右節點是 null,因此符合這個狀況
這個時候只須要直接把須要刪除的節點 reset 爲 非空的子節點就能夠了
因此在這裏只須要把15的值替代爲12
3.第三種狀況是刪除的節點的2個子節點都不爲null,
這個時候其實能夠有2個選擇,一個是把刪除的節點替換爲右子節點爲根節點的那個樹中最小的節點
好比我要刪除10, 右節點爲15(二叉樹的刪除操做的那個圖,不是上面的那個圖),15這個節點爲根節點的樹中總共有2個元素(15和12),12是最小的。因此把須要刪除的節點替換爲12。刪除後以下
另一種選擇是把左節點爲根節點的樹中最大的值取出來,把須要刪除的那個節點替換爲這個左節點最大的元素(2個選擇沒什麼區別)
1 @Override 2 public void delete(K k) { 3 delete(root, k); 4 } 5 //delete the k in the node tree and reset the size prorperty of this tree and subtrees to correct value 6 private Node<K, V> delete(Node<K, V> node, K k) { 7 if (node == null) return null; //沒有找到這個node 8 9 int cmp = node.k.compareTo(k); 10 if (cmp > 0) { 11 node.left = delete(node.left, k); 12 node.size = size(node.left) + size(node.right) + 1; 13 return node; 14 } else if (cmp < 0) { 15 node.right = delete(node.right, k); 16 node.size = size(node.left) + size(node.right) + 1; 17 return node; 18 } else { //hit the key 19 if (node.right == null) //if the right node is null then just replace this node with left node 20 return node.left; 21 else if (node.left == null) // if the left node is null then just replace this node with right node 22 return node.right; 23 else { 24 return deleteMin(node.right); // if both the subnodes are not null replace this node with the smallest node in the right sub node 25 } 26 } 27 } 28 29 //刪除從參數node開始的最小的node 30 private Node<K, V> deleteMin(Node<K, V> node) { 31 return delete(node, min(node)); 32 } 33 34 private Node<K, V> deleteMax(Node<K, V> node) { 35 return delete(node, max(node)); 36 } 37 38 @Override 39 public void deleteMin() { 40 deleteMin(root); 41 } 42 43 @Override 44 public void deleteMax() { 45 deleteMax(root); 46 } 47 48 @Override 49 public K min() { 50 return min(root); 51 } 52 53 //get the smallest node in the given node 54 private K min(Node<K, V> node) { 55 if (node == null) return null; 56 for (; node.left != null; node = node.left); 57 return node.k; 58 } 59 60 @Override 61 public K max() { 62 return max(root); 63 } 64 //get the most max node in the given node 65 private K max(Node<K, V> node) { 66 if (node == null) return null; 67 for (node = root; node.right != null; node = node.right); 68 return node.k; 69 }
分析
BinarySearchTree 有一個最大的缺點,就是若是插入的元素是ordered,好比我插入 1 2 3 4 5 6 這樣子,元素都會排在一邊。這樣子查找起來路徑很長,效率很低。
若是插入的元素是隨機的,那麼全部的get put 操做的時間複雜度應該是 和 log2(N) 成正比的
具體的實現能夠參考這個。https://github.com/Cheemion/algorithms/blob/master/src/com/algorithms/tree/BinarySearchTreeMap.java
有什麼錯誤的地方歡迎你們指正哈