有序表(O(logN))

平衡搜索二叉树(BST):红黑树、AVL树、SBT,
跳表,它们的时间复杂度一样
相同点:都是一棵搜索二叉树,都具有左旋和右旋操作,保持树的平衡。
不同点:左旋和右旋的实际操作不同。

何为具有平衡性的树?

介绍树的左旋
介绍树的右旋

AVL树

何时进行左旋或者右旋:在进行插入和删除时,如果左子树和右子树的高度差相差为1,进行,而且要判断当前节点的父节点的左子树和右子树的高度差相差为1,直到根结点。
旋转的时机:LL(左边的左子树过长)、RR(右边的右子树过长)、LR(左边的右子树过长)、RL(右边的左子树过长)
AbstractBinarySearchTree

  1. public class AbstractBinarySearchTree {
  2. /** Root node where whole tree starts. */
  3. public Node root;
  4. /** Tree size. */
  5. protected int size;
  6. /**
  7. * Because this is abstract class and various trees have different
  8. * additional information on different nodes subclasses uses this abstract
  9. * method to create nodes (maybe of class {@link Node} or maybe some
  10. * different node sub class).
  11. *
  12. * @param value
  13. * Value that node will have.
  14. * @param parent
  15. * Node's parent.
  16. * @param left
  17. * Node's left child.
  18. * @param right
  19. * Node's right child.
  20. * @return Created node instance.
  21. */
  22. protected Node createNode(int value, Node parent, Node left, Node right) {
  23. return new Node(value, parent, left, right);
  24. }
  25. /**
  26. * Finds a node with concrete value. If it is not found then null is
  27. * returned.
  28. *
  29. * @param element
  30. * Element value.
  31. * @return Node with value provided, or null if not found.
  32. */
  33. public Node search(int element) {
  34. Node node = root;
  35. while (node != null && node.value != null && node.value != element) {
  36. if (element < node.value) {
  37. node = node.left;
  38. } else {
  39. node = node.right;
  40. }
  41. }
  42. return node;
  43. }
  44. /**
  45. * Insert new element to tree.
  46. *
  47. * @param element
  48. * Element to insert.
  49. */
  50. public Node insert(int element) {
  51. if (root == null) {
  52. root = createNode(element, null, null, null);
  53. size++;
  54. return root;
  55. }
  56. Node insertParentNode = null;
  57. Node searchTempNode = root;
  58. while (searchTempNode != null && searchTempNode.value != null) {
  59. insertParentNode = searchTempNode;
  60. if (element < searchTempNode.value) {
  61. searchTempNode = searchTempNode.left;
  62. } else {
  63. searchTempNode = searchTempNode.right;
  64. }
  65. }
  66. Node newNode = createNode(element, insertParentNode, null, null);
  67. if (insertParentNode.value > newNode.value) {
  68. insertParentNode.left = newNode;
  69. } else {
  70. insertParentNode.right = newNode;
  71. }
  72. size++;
  73. return newNode;
  74. }
  75. /**
  76. * Removes element if node with such value exists.
  77. *
  78. * @param element
  79. * Element value to remove.
  80. *
  81. * @return New node that is in place of deleted node. Or null if element for
  82. * delete was not found.
  83. */
  84. public Node delete(int element) {
  85. Node deleteNode = search(element);
  86. if (deleteNode != null) {
  87. return delete(deleteNode);
  88. } else {
  89. return null;
  90. }
  91. }
  92. /**
  93. * Delete logic when node is already found.
  94. *
  95. * @param deleteNode
  96. * Node that needs to be deleted.
  97. *
  98. * @return New node that is in place of deleted node. Or null if element for
  99. * delete was not found.
  100. */
  101. protected Node delete(Node deleteNode) {
  102. if (deleteNode != null) {
  103. Node nodeToReturn = null;
  104. if (deleteNode != null) {
  105. if (deleteNode.left == null) {
  106. nodeToReturn = transplant(deleteNode, deleteNode.right);
  107. } else if (deleteNode.right == null) {
  108. nodeToReturn = transplant(deleteNode, deleteNode.left);
  109. } else {
  110. Node successorNode = getMinimum(deleteNode.right);
  111. if (successorNode.parent != deleteNode) {
  112. transplant(successorNode, successorNode.right);
  113. successorNode.right = deleteNode.right;
  114. successorNode.right.parent = successorNode;
  115. }
  116. transplant(deleteNode, successorNode);
  117. successorNode.left = deleteNode.left;
  118. successorNode.left.parent = successorNode;
  119. nodeToReturn = successorNode;
  120. }
  121. size--;
  122. }
  123. return nodeToReturn;
  124. }
  125. return null;
  126. }
  127. /**
  128. * Put one node from tree (newNode) to the place of another (nodeToReplace).
  129. *
  130. * @param nodeToReplace
  131. * Node which is replaced by newNode and removed from tree.
  132. * @param newNode
  133. * New node.
  134. *
  135. * @return New replaced node.
  136. */
  137. private Node transplant(Node nodeToReplace, Node newNode) {
  138. if (nodeToReplace.parent == null) {
  139. this.root = newNode;
  140. } else if (nodeToReplace == nodeToReplace.parent.left) {
  141. nodeToReplace.parent.left = newNode;
  142. } else {
  143. nodeToReplace.parent.right = newNode;
  144. }
  145. if (newNode != null) {
  146. newNode.parent = nodeToReplace.parent;
  147. }
  148. return newNode;
  149. }
  150. /**
  151. * @param element
  152. * @return true if tree contains element.
  153. */
  154. public boolean contains(int element) {
  155. return search(element) != null;
  156. }
  157. /**
  158. * @return Minimum element in tree.
  159. */
  160. public int getMinimum() {
  161. return getMinimum(root).value;
  162. }
  163. /**
  164. * @return Maximum element in tree.
  165. */
  166. public int getMaximum() {
  167. return getMaximum(root).value;
  168. }
  169. /**
  170. * Get next element element who is bigger than provided element.
  171. *
  172. * @param element
  173. * Element for whom descendand element is searched
  174. * @return Successor value.
  175. */
  176. // TODO Predecessor
  177. public int getSuccessor(int element) {
  178. return getSuccessor(search(element)).value;
  179. }
  180. /**
  181. * @return Number of elements in the tree.
  182. */
  183. public int getSize() {
  184. return size;
  185. }
  186. /**
  187. * Tree traversal with printing element values. In order method.
  188. */
  189. public void printTreeInOrder() {
  190. printTreeInOrder(root);
  191. }
  192. /**
  193. * Tree traversal with printing element values. Pre order method.
  194. */
  195. public void printTreePreOrder() {
  196. printTreePreOrder(root);
  197. }
  198. /**
  199. * Tree traversal with printing element values. Post order method.
  200. */
  201. public void printTreePostOrder() {
  202. printTreePostOrder(root);
  203. }
  204. /*-------------------PRIVATE HELPER METHODS-------------------*/
  205. private void printTreeInOrder(Node entry) {
  206. if (entry != null) {
  207. printTreeInOrder(entry.left);
  208. if (entry.value != null) {
  209. System.out.println(entry.value);
  210. }
  211. printTreeInOrder(entry.right);
  212. }
  213. }
  214. private void printTreePreOrder(Node entry) {
  215. if (entry != null) {
  216. if (entry.value != null) {
  217. System.out.println(entry.value);
  218. }
  219. printTreeInOrder(entry.left);
  220. printTreeInOrder(entry.right);
  221. }
  222. }
  223. private void printTreePostOrder(Node entry) {
  224. if (entry != null) {
  225. printTreeInOrder(entry.left);
  226. printTreeInOrder(entry.right);
  227. if (entry.value != null) {
  228. System.out.println(entry.value);
  229. }
  230. }
  231. }
  232. protected Node getMinimum(Node node) {
  233. while (node.left != null) {
  234. node = node.left;
  235. }
  236. return node;
  237. }
  238. protected Node getMaximum(Node node) {
  239. while (node.right != null) {
  240. node = node.right;
  241. }
  242. return node;
  243. }
  244. protected Node getSuccessor(Node node) {
  245. // if there is right branch, then successor is leftmost node of that
  246. // subtree
  247. if (node.right != null) {
  248. return getMinimum(node.right);
  249. } else { // otherwise it is a lowest ancestor whose left child is also
  250. // ancestor of node
  251. Node currentNode = node;
  252. Node parentNode = node.parent;
  253. while (parentNode != null && currentNode == parentNode.right) {
  254. // go up until we find parent that currentNode is not in right
  255. // subtree.
  256. currentNode = parentNode;
  257. parentNode = parentNode.parent;
  258. }
  259. return parentNode;
  260. }
  261. }
  262. // -------------------------------- TREE PRINTING
  263. // ------------------------------------
  264. public void printTree() {
  265. printSubtree(root);
  266. }
  267. public void printSubtree(Node node) {
  268. if (node.right != null) {
  269. printTree(node.right, true, "");
  270. }
  271. printNodeValue(node);
  272. if (node.left != null) {
  273. printTree(node.left, false, "");
  274. }
  275. }
  276. private void printNodeValue(Node node) {
  277. if (node.value == null) {
  278. System.out.print("<null>");
  279. } else {
  280. System.out.print(node.value.toString());
  281. }
  282. System.out.println();
  283. }
  284. private void printTree(Node node, boolean isRight, String indent) {
  285. if (node.right != null) {
  286. printTree(node.right, true, indent + (isRight ? " " : " | "));
  287. }
  288. System.out.print(indent);
  289. if (isRight) {
  290. System.out.print(" /");
  291. } else {
  292. System.out.print(" \\");
  293. }
  294. System.out.print("----- ");
  295. printNodeValue(node);
  296. if (node.left != null) {
  297. printTree(node.left, false, indent + (isRight ? " | " : " "));
  298. }
  299. }
  300. public static class Node {
  301. public Node(Integer value, Node parent, Node left, Node right) {
  302. super();
  303. this.value = value;
  304. this.parent = parent;
  305. this.left = left;
  306. this.right = right;
  307. }
  308. public Integer value;
  309. public Node parent;
  310. public Node left;
  311. public Node right;
  312. public boolean isLeaf() {
  313. return left == null && right == null;
  314. }
  315. @Override
  316. public int hashCode() {
  317. final int prime = 31;
  318. int result = 1;
  319. result = prime * result + ((value == null) ? 0 : value.hashCode());
  320. return result;
  321. }
  322. @Override
  323. public boolean equals(Object obj) {
  324. if (this == obj)
  325. return true;
  326. if (obj == null)
  327. return false;
  328. if (getClass() != obj.getClass())
  329. return false;
  330. Node other = (Node) obj;
  331. if (value == null) {
  332. if (other.value != null)
  333. return false;
  334. } else if (!value.equals(other.value))
  335. return false;
  336. return true;
  337. }
  338. }
  339. }

AVLTree

public class AVLTree extends AbstractSelfBalancingBinarySearchTree {

    /**
     * @see trees.AbstractBinarySearchTree#insert(int)
     * 
     *      AVL tree insert method also balances tree if needed. Additional
     *      height parameter on node is used to track if one subtree is higher
     *      than other by more than one, if so AVL tree rotations is performed
     *      to regain balance of the tree.
     */
    @Override
    public Node insert(int element) {
        Node newNode = super.insert(element);
        rebalance((AVLNode)newNode);
        return newNode;
    }

    /**
     * @see trees.AbstractBinarySearchTree#delete(int)
     */
    @Override
    public Node delete(int element) {
        Node deleteNode = super.search(element);
        if (deleteNode != null) {
            Node successorNode = super.delete(deleteNode);
            if (successorNode != null) {
                // if replaced from getMinimum(deleteNode.right) then come back there and update heights
                AVLNode minimum = successorNode.right != null ? (AVLNode)getMinimum(successorNode.right) : (AVLNode)successorNode;
                recomputeHeight(minimum);
                rebalance((AVLNode)minimum);
            } else {
                recomputeHeight((AVLNode)deleteNode.parent);
                rebalance((AVLNode)deleteNode.parent);
            }
            return successorNode;
        }
        return null;
    }

    /**
     * @see trees.AbstractBinarySearchTree#createNode(int, trees.AbstractBinarySearchTree.Node, trees.AbstractBinarySearchTree.Node, trees.AbstractBinarySearchTree.Node)
     */
    @Override
    protected Node createNode(int value, Node parent, Node left, Node right) {
        return new AVLNode(value, parent, left, right);
    }

    /**
     * Go up from inserted node, and update height and balance informations if needed.
     * If some node balance reaches 2 or -2 that means that subtree must be rebalanced.
     * 
     * @param node Inserted Node.
     */
    private void rebalance(AVLNode node) {
        while (node != null) {

            Node parent = node.parent;

            int leftHeight = (node.left == null) ? -1 : ((AVLNode) node.left).height;
            int rightHeight = (node.right == null) ? -1 : ((AVLNode) node.right).height;
            int nodeBalance = rightHeight - leftHeight;
            // rebalance (-2 means left subtree outgrow, 2 means right subtree)
            if (nodeBalance == 2) {
                if (node.right.right != null) {
                    node = (AVLNode)avlRotateLeft(node);
                    break;
                } else {
                    node = (AVLNode)doubleRotateRightLeft(node);
                    break;
                }
            } else if (nodeBalance == -2) {
                if (node.left.left != null) {
                    node = (AVLNode)avlRotateRight(node);
                    break;
                } else {
                    node = (AVLNode)doubleRotateLeftRight(node);
                    break;
                }
            } else {
                updateHeight(node);
            }

            node = (AVLNode)parent;
        }
    }

    /**
     * Rotates to left side.
     */
    private Node avlRotateLeft(Node node) {
        Node temp = super.rotateLeft(node);

        updateHeight((AVLNode)temp.left);
        updateHeight((AVLNode)temp);
        return temp;
    }

    /**
     * Rotates to right side.
     */
    private Node avlRotateRight(Node node) {
        Node temp = super.rotateRight(node);

        updateHeight((AVLNode)temp.right);
        updateHeight((AVLNode)temp);
        return temp;
    }

    /**
     * Take right child and rotate it to the right side first and then rotate
     * node to the left side.
     */
    protected Node doubleRotateRightLeft(Node node) {
        node.right = avlRotateRight(node.right);
        return avlRotateLeft(node);
    }

    /**
     * Take right child and rotate it to the right side first and then rotate
     * node to the left side.
     */
    protected Node doubleRotateLeftRight(Node node) {
        node.left = avlRotateLeft(node.left);
        return avlRotateRight(node);
    }

    /**
     * Recomputes height information from the node and up for all of parents. It needs to be done after delete.
     */
    private void recomputeHeight(AVLNode node) {
       while (node != null) {
          node.height = maxHeight((AVLNode)node.left, (AVLNode)node.right) + 1;
          node = (AVLNode)node.parent;
       }
    }

    /**
     * Returns higher height of 2 nodes. 
     */
    private int maxHeight(AVLNode node1, AVLNode node2) {
        if (node1 != null && node2 != null) {
            return node1.height > node2.height ? node1.height : node2.height;
        } else if (node1 == null) {
            return node2 != null ? node2.height : -1;
        } else if (node2 == null) {
            return node1 != null ? node1.height : -1;
        }
        return -1;
    }

    /**
     * Updates height and balance of the node.
     * 
     * @param node Node for which height and balance must be updated.
     */
    private static final void updateHeight(AVLNode node) {
        int leftHeight = (node.left == null) ? -1 : ((AVLNode) node.left).height;
        int rightHeight = (node.right == null) ? -1 : ((AVLNode) node.right).height;
        node.height = 1 + Math.max(leftHeight, rightHeight);
    }

    /**
     * Node of AVL tree has height and balance additional properties. If balance
     * equals 2 (or -2) that node needs to be re balanced. (Height is height of
     * the subtree starting with this node, and balance is difference between
     * left and right nodes heights).
     * 
     * @author Ignas Lelys
     * @created Jun 30, 2011
     * 
     */
    protected static class AVLNode extends Node {
        public int height;

        public AVLNode(int value, Node parent, Node left, Node right) {
            super(value, parent, left, right);
        }
    }
}

SB树

平衡性:

每棵子树的大小,不小于其兄弟的子树大小,既每棵叔叔树的大小,不小于其任何侄子树的大小

何时进行左旋和右旋?

插入和删除需要进行
LL
image.png
image.png

public class SizeBalancedTreeMap {

    public static class SBTNode<K extends Comparable<K>, V> {
        public K key;
        public V value;
        public SBTNode<K, V> l;
        public SBTNode<K, V> r;
        public int size;

        public SBTNode(K key, V value) {
            this.key = key;
            this.value = value;
            size = 1;
        }
    }

    public static class SizeBalancedTreeMap<K extends Comparable<K>, V> {
        private SBTNode<K, V> root;

        private SBTNode<K, V> rightRotate(SBTNode<K, V> cur) {
            SBTNode<K, V> leftNode = cur.l;
            cur.l = leftNode.r;
            leftNode.r = cur;
            leftNode.size = cur.size;
            cur.size = (cur.l != null ? cur.l.size : 0) + (cur.r != null ? cur.r.size : 0) + 1;
            return leftNode;
        }

        private SBTNode<K, V> leftRotate(SBTNode<K, V> cur) {
            SBTNode<K, V> rightNode = cur.r;
            cur.r = rightNode.l;
            rightNode.l = cur;
            rightNode.size = cur.size;
            cur.size = (cur.l != null ? cur.l.size : 0) + (cur.r != null ? cur.r.size : 0) + 1;
            return rightNode;
        }

        // 如果出现不达标的情况,调整
        private SBTNode<K, V> matain(SBTNode<K, V> cur) {
            if (cur == null) {
                return null;
            }
            if (cur.l != null && cur.l.l != null && cur.r != null && cur.l.l.size > cur.r.size) {
                cur = rightRotate(cur);
                cur.r = matain(cur.r);
                cur = matain(cur);
            } else if (cur.l != null && cur.l.r != null && cur.r != null && cur.l.r.size > cur.r.size) {
                cur.l = leftRotate(cur.l);
                cur = rightRotate(cur);
                cur.l = matain(cur.l);
                cur.r = matain(cur.r);
                cur = matain(cur);
            } else if (cur.r != null && cur.r.r != null && cur.l != null && cur.r.r.size > cur.l.size) {
                cur = leftRotate(cur);
                cur.l = matain(cur.l);
                cur = matain(cur);
            } else if (cur.r != null && cur.r.l != null && cur.l != null && cur.r.l.size > cur.l.size) {
                cur.r = rightRotate(cur.r);
                cur = leftRotate(cur);
                cur.l = matain(cur.l);
                cur.r = matain(cur.r);
                cur = matain(cur);
            }
            return cur;
        }

        private SBTNode<K, V> findLastIndex(K key) {
            SBTNode<K, V> pre = root;
            SBTNode<K, V> cur = root;
            while (cur != null) {
                pre = cur;
                if (key.compareTo(cur.key) == 0) {
                    break;
                } else if (key.compareTo(cur.key) < 0) {
                    cur = cur.l;
                } else {
                    cur = cur.r;
                }
            }
            return pre;
        }

        private SBTNode<K, V> findLastNoSmallIndex(K key) {
            SBTNode<K, V> ans = null;
            SBTNode<K, V> cur = root;
            while (cur != null) {
                if (key.compareTo(cur.key) == 0) {
                    ans = cur;
                    break;
                } else if (key.compareTo(cur.key) < 0) {
                    ans = cur;
                    cur = cur.l;
                } else {
                    cur = cur.r;
                }
            }
            return ans;
        }

        private SBTNode<K, V> findLastNoBigIndex(K key) {
            SBTNode<K, V> ans = null;
            SBTNode<K, V> cur = root;
            while (cur != null) {
                if (key.compareTo(cur.key) == 0) {
                    ans = cur;
                    break;
                } else if (key.compareTo(cur.key) < 0) {
                    cur = cur.l;
                } else {
                    ans = cur;
                    cur = cur.r;
                }
            }
            return ans;
        }

        private SBTNode<K, V> add(SBTNode<K, V> cur, K key, V value) {
            if (cur == null) {
                return new SBTNode<K, V>(key, value);
            } else {
                cur.size++;
                if (key.compareTo(cur.key) < 0) {
                    cur.l = add(cur.l, key, value);
                } else {
                    cur.r = add(cur.r, key, value);
                }
                return matain(cur);
            }
        }

        private SBTNode<K, V> delete(SBTNode<K, V> cur, K key) {
            cur.size--;
            if (key.compareTo(cur.key) > 0) {
                cur.r = delete(cur.r, key);
            } else if (key.compareTo(cur.key) < 0) {
                cur.l = delete(cur.l, key);
            } else {
                if (cur.l == null && cur.r == null) {
                    // free cur memory -> C++
                    cur = null;
                } else if (cur.l == null && cur.r != null) {
                    // free cur memory -> C++
                    cur = cur.r;
                } else if (cur.l != null && cur.r == null) {
                    // free cur memory -> C++
                    cur = cur.l;
                } else {
                    SBTNode<K, V> pre = null;
                    SBTNode<K, V> des = cur.r;
                    des.size--;
                    while (des.l != null) {
                        pre = des;
                        des = des.l;
                        des.size--;
                    }
                    if (pre != null) {
                        pre.l = des.r;
                        des.r = cur.r;
                    }
                    des.l = cur.l;
                    des.size = des.l.size + des.r.size + 1;
                    // free cur memory -> C++
                    cur = des;
                }
            }
            return cur;
        }

        private SBTNode<K, V> getIndex(SBTNode<K, V> cur, int kth) {
            if (kth == (cur.l != null ? cur.l.size : 0) + 1) {
                return cur;
            } else if (kth <= (cur.l != null ? cur.l.size : 0)) {
                return getIndex(cur.l, kth);
            } else {
                return getIndex(cur.r, kth - (cur.l != null ? cur.l.size : 0) - 1);
            }
        }

        public int size() {
            return root == null ? 0 : root.size;
        }

        public boolean containsKey(K key) {
            if (key == null) {
                throw new RuntimeException("invalid parameter.");
            }
            SBTNode<K, V> lastNode = findLastIndex(key);
            return lastNode != null && key.compareTo(lastNode.key) == 0 ? true : false;
        }

        public void put(K key, V value) {
            if (key == null) {
                throw new RuntimeException("invalid parameter.");
            }
            SBTNode<K, V> lastNode = findLastIndex(key);
            if (lastNode != null && key.compareTo(lastNode.key) == 0) {
                lastNode.value = value;
            } else {
                root = add(root, key, value);
            }
        }

        public void remove(K key) {
            if (key == null) {
                throw new RuntimeException("invalid parameter.");
            }
            if (containsKey(key)) {
                root = delete(root, key);
            }
        }

        public K getIndexKey(int index) {
            if (index < 0 || index >= this.size()) {
                throw new RuntimeException("invalid parameter.");
            }
            return getIndex(root, index + 1).key;
        }

        public V getIndexValue(int index) {
            if (index < 0 || index >= this.size()) {
                throw new RuntimeException("invalid parameter.");
            }
            return getIndex(root, index + 1).value;
        }

        public V get(K key) {
            if (key == null) {
                throw new RuntimeException("invalid parameter.");
            }
            SBTNode<K, V> lastNode = findLastIndex(key);
            if (lastNode != null && key.compareTo(lastNode.key) == 0) {
                return lastNode.value;
            } else {
                return null;
            }
        }

        public K firstKey() {
            if (root == null) {
                return null;
            }
            SBTNode<K, V> cur = root;
            while (cur.l != null) {
                cur = cur.l;
            }
            return cur.key;
        }

        public K lastKey() {
            if (root == null) {
                return null;
            }
            SBTNode<K, V> cur = root;
            while (cur.r != null) {
                cur = cur.r;
            }
            return cur.key;
        }

        public K floorKey(K key) {
            if (key == null) {
                throw new RuntimeException("invalid parameter.");
            }
            SBTNode<K, V> lastNoBigNode = findLastNoBigIndex(key);
            return lastNoBigNode == null ? null : lastNoBigNode.key;
        }

        public K ceilingKey(K key) {
            if (key == null) {
                throw new RuntimeException("invalid parameter.");
            }
            SBTNode<K, V> lastNoSmallNode = findLastNoSmallIndex(key);
            return lastNoSmallNode == null ? null : lastNoSmallNode.key;
        }

    }

    // for test
    public static void printAll(SBTNode<String, Integer> head) {
        System.out.println("Binary Tree:");
        printInOrder(head, 0, "H", 17);
        System.out.println();
    }

    // for test
    public static void printInOrder(SBTNode<String, Integer> head, int height, String to, int len) {
        if (head == null) {
            return;
        }
        printInOrder(head.r, height + 1, "v", len);
        String val = to + "(" + head.key + "," + head.value + ")" + to;
        int lenM = val.length();
        int lenL = (len - lenM) / 2;
        int lenR = len - lenM - lenL;
        val = getSpace(lenL) + val + getSpace(lenR);
        System.out.println(getSpace(height * len) + val);
        printInOrder(head.l, height + 1, "^", len);
    }

    // for test
    public static String getSpace(int num) {
        String space = " ";
        StringBuffer buf = new StringBuffer("");
        for (int i = 0; i < num; i++) {
            buf.append(space);
        }
        return buf.toString();
    }

    public static void main(String[] args) {
        SizeBalancedTreeMap<String, Integer> sbt = new SizeBalancedTreeMap<String, Integer>();
        sbt.put("d", 4);
        sbt.put("c", 3);
        sbt.put("a", 1);
        sbt.put("b", 2);
        // sbt.put("e", 5);
        sbt.put("g", 7);
        sbt.put("f", 6);
        sbt.put("h", 8);
        sbt.put("i", 9);
        sbt.put("a", 111);
        System.out.println(sbt.get("a"));
        sbt.put("a", 1);
        System.out.println(sbt.get("a"));
        for (int i = 0; i < sbt.size(); i++) {
            System.out.println(sbt.getIndexKey(i) + " , " + sbt.getIndexValue(i));
        }
        printAll(sbt.root);
        System.out.println(sbt.firstKey());
        System.out.println(sbt.lastKey());
        System.out.println(sbt.floorKey("g"));
        System.out.println(sbt.ceilingKey("g"));
        System.out.println(sbt.floorKey("e"));
        System.out.println(sbt.ceilingKey("e"));
        System.out.println(sbt.floorKey(""));
        System.out.println(sbt.ceilingKey(""));
        System.out.println(sbt.floorKey("j"));
        System.out.println(sbt.ceilingKey("j"));
        sbt.remove("d");
        printAll(sbt.root);
        sbt.remove("f");
        printAll(sbt.root);
    }
}

跳表

image.png

public class SkipListMap {

    public static class SkipListNode<K extends Comparable<K>, V> {
        public K key;
        public V val;
        public ArrayList<SkipListNode<K, V>> nextNodes;

        public SkipListNode(K k, V v) {
            key = k;
            val = v;
            nextNodes = new ArrayList<SkipListNode<K, V>>();
        }

        public boolean isKeyLess(K otherKey) {
            return otherKey != null && (key == null || key.compareTo(otherKey) < 0);
        }

        public boolean isKeyEqual(K otherKey) {
            return (key == null && otherKey == null)
                    || (key != null && otherKey != null && key.compareTo(otherKey) == 0);
        }

    }

    public static class SkipListMap<K extends Comparable<K>, V> {
        private static final double PROBABILITY = 0.5;
        private SkipListNode<K, V> head;
        private int size;
        private int maxLevel;

        public SkipListMap() {
            head = new SkipListNode<K, V>(null, null);
            head.nextNodes.add(null);
            size = 0;
            maxLevel = 0;
        }

        private SkipListNode<K, V> mostRightLessNodeInTree(K key) {
            if (key == null) {
                return null;
            }
            int level = maxLevel;
            SkipListNode<K, V> cur = head;
            while (level >= 0) {
                cur = mostRightLessNodeInLevel(key, cur, level--);
            }
            return cur;
        }

        private SkipListNode<K, V> mostRightLessNodeInLevel(K key, SkipListNode<K, V> cur, int level) {
            SkipListNode<K, V> next = cur.nextNodes.get(level);
            while (next != null && next.isKeyLess(key)) {
                cur = next;
                next = cur.nextNodes.get(level);
            }
            return cur;
        }

        public boolean containsKey(K key) {
            if (key == null) {
                return false;
            }
            SkipListNode<K, V> less = mostRightLessNodeInTree(key);
            SkipListNode<K, V> next = less.nextNodes.get(0);
            return next != null && next.isKeyEqual(key);
        }

        public void put(K key, V value) {
            if (key == null) {
                return;
            }
            SkipListNode<K, V> less = mostRightLessNodeInTree(key);
            SkipListNode<K, V> find = less.nextNodes.get(0);
            if (find != null && find.isKeyEqual(key)) {
                find.val = value;
            } else {
                size++;
                int newNodeLevel = 0;
                while (Math.random() < PROBABILITY) {
                    newNodeLevel++;
                }
                while (newNodeLevel > maxLevel) {
                    head.nextNodes.add(null);
                    maxLevel++;
                }
                SkipListNode<K, V> newNode = new SkipListNode<K, V>(key, value);
                for (int i = 0; i <= newNodeLevel; i++) {
                    newNode.nextNodes.add(null);
                }
                int level = maxLevel;
                SkipListNode<K, V> pre = head;
                while (level >= 0) {
                    pre = mostRightLessNodeInLevel(key, pre, level);
                    if (level <= newNodeLevel) {
                        newNode.nextNodes.set(level, pre.nextNodes.get(level));
                        pre.nextNodes.set(level, newNode);
                    }
                    level--;
                }
            }
        }

        public V get(K key) {
            if (key == null) {
                return null;
            }
            SkipListNode<K, V> less = mostRightLessNodeInTree(key);
            SkipListNode<K, V> next = less.nextNodes.get(0);
            return next != null && next.isKeyEqual(key) ? next.val : null;
        }

        public void remove(K key) {
            if (containsKey(key)) {
                size--;
                int level = maxLevel;
                SkipListNode<K, V> pre = head;
                while (level >= 0) {
                    pre = mostRightLessNodeInLevel(key, pre, level);
                    SkipListNode<K, V> next = pre.nextNodes.get(level);
                    if (next != null && next.isKeyEqual(key)) {
                        // free delete node memory -> C++
                        pre.nextNodes.set(level, next.nextNodes.get(level));
                    }
                    if (level != 0 && pre == head && pre.nextNodes.get(level) == null) {
                        head.nextNodes.remove(level);
                        maxLevel--;
                    }
                    level--;
                }
            }
        }

        public K firstKey() {
            return head.nextNodes.get(0) != null ? head.nextNodes.get(0).key : null;
        }

        public K lastKey() {
            int level = maxLevel;
            SkipListNode<K, V> cur = head;
            while (level >= 0) {
                SkipListNode<K, V> next = cur.nextNodes.get(level);
                while (next != null) {
                    cur = next;
                    next = cur.nextNodes.get(level);
                }
                level--;
            }
            return cur.key;
        }

        public K ceillingKey(K key) {
            if (key == null) {
                return null;
            }
            SkipListNode<K, V> less = mostRightLessNodeInTree(key);
            SkipListNode<K, V> next = less.nextNodes.get(0);
            return next != null ? next.key : null;
        }

        public K floorKey(K key) {
            if (key == null) {
                return null;
            }
            SkipListNode<K, V> less = mostRightLessNodeInTree(key);
            SkipListNode<K, V> next = less.nextNodes.get(0);
            return next != null && next.isKeyEqual(key) ? next.key : less.key;
        }

        public int size() {
            return size;
        }

    }

    // for test
    public static void printAll(SkipListMap<String, String> obj) {
        for (int i = obj.maxLevel; i >= 0; i--) {
            System.out.print("Level " + i + " : ");
            SkipListNode<String, String> cur = obj.head;
            while (cur.nextNodes.get(i) != null) {
                SkipListNode<String, String> next = cur.nextNodes.get(i);
                System.out.print("(" + next.key + " , " + next.val + ") ");
                cur = next;
            }
            System.out.println();
        }
    }

    public static void main(String[] args) {
        SkipListMap<String, String> test = new SkipListMap<>();
        printAll(test);
        System.out.println("======================");
        test.put("A", "10");
        printAll(test);
        System.out.println("======================");
        test.remove("A");
        printAll(test);
        System.out.println("======================");
        test.put("E", "E");
        test.put("B", "B");
        test.put("A", "A");
        test.put("F", "F");
        test.put("C", "C");
        test.put("D", "D");
        printAll(test);
        System.out.println("======================");
        System.out.println(test.containsKey("B"));
        System.out.println(test.containsKey("Z"));
        System.out.println(test.firstKey());
        System.out.println(test.lastKey());
        System.out.println(test.floorKey("D"));
        System.out.println(test.ceillingKey("D"));
        System.out.println("======================");
        test.remove("D");
        printAll(test);
        System.out.println("======================");
        System.out.println(test.floorKey("D"));
        System.out.println(test.ceillingKey("D"));
    }
}