有序表所有的操作都是 的。有很多数据结构可以实现有序表,如:红黑树、AVL(Self-Balancing Binary Search Tree)、SBT(Size-Balance-Tree)、跳表(skip-List)等。
AVL,SBT,红黑树都可以参考 各种树 。
跳表
对于一个跳表来说,依次插入数据:3,20,40,50,10,30,100,15

插入 3,roll 到层高为 3,找到比 3 小的最右节点为 null,head 的层高为 0, 0<3,将 head 的层高增加到 3 层,并将每层都指向 3 节点
插入 20,roll 到层高为 5,找到比 20 小的最右节点为 3,head 的层高为 3, 3<5,将 head 的层高增加到 5 层,3 节点所有层指向 20 节点,head 节点的最高两层指向 20 节点

插入 40,roll 到层高为 4,找到比 40 小的最右节点为 20,head 的层高为 5, 5>4,head 层高不变,20 节点 4 个层指向 40 节点
插入 50,roll 到层高为 5,找到比 50 小的最右节点为 50,head 的层高为 5, 5==5,head 层高不变,40 节点所有层指向 50 节点,20 节点的最高层指向 50节点
插入 10,roll 到层高为 2,找到比 10 小的最右节点为 3,head 的层高为 5, 5>2,head 层高不变,3 节点 0、1 层指向 10 节点,10 节点的所有层指向 20节点
插入 30,roll 到层高为 1,找到比 30 小的最右节点为 20,head 的层高为 5, 5>1,head 层高不变,20 节点 0 层指向 30 节点,30 节点的所有层指向 40 节点
插入 100,roll 到层高为 6,找到比 100 小的最右节点为 50,head 的层高为 6, 5<6,head 层高增加到 6,50 节点的所层点指向 100 节点,head 节点的 5 层指向 100 节点
插入 15,roll 到层高为 4,找到比 15 小的最右节点为 10,head 的层高为 6, 6>4,head 层高不变,10 节点所有层指向 15 节点,3 节点的 2 层指向 15 节点, head 的 3 层执行 15 节点
至此,所有节点插入完成。在这个过程中,最重要的过程有两个:
- 如何找到小于插入值的最大值?
- 找到该值要插入的地方后如果修改
例如:在插入 10 节点时
- 先遍历 head 节点,从最高层遍历:
- 第 4 层 —> 20,20 > 10
- 第 3 层 —> 20,20 > 10
- 第 2 层 —> 3,3 < 10
- 开始遍历 3 节点:
- 第 2 层 —> 20,20 > 10
- 遍历结束,小于 10 的最大值为 3,就将 10 插入到 3 节点后
10 的层高为 2,3 节点的 0、1 两层要指向 10 节点,10 节点指向 20 节点
结果为:
例如:插入 15 时:
- 从 head 节点最高层开始遍历:
- 第 5 层 —> 100,100 > 15
- 第 4 层 —> 20,20 > 15
- 第 3 层 —> 20,20 > 15
- 第 2 层 —> 3,3 < 15
- 从 3 节点开始遍历:
- 第 2 层 —> 20,20 > 15
- 第 1 层 —> 10,10 < 15
- 遍历结束,15 要插入到 10 后面
15 的层高为 4,10 节点的0、1要指向 15 节点, 3 节点的 2 层要指向 15 节点,head 的 3 层要指向15 节点;15 节点指向 20 节点
结果为:
代码实现:
import java.util.ArrayList;import java.util.List;public class SkipList {public static class SkipListNode<K extends Comparable<K>, V> {public K key;public V val;public List<SkipListNode<K, V>> nextNodes;public SkipListNode(K key, V val) {this.key = key;this.val = val;nextNodes = new ArrayList<>();}/*** {@code otherKey} 是否要比 key 小** @param otherKey* @return*/public boolean isKeyLess(K otherKey) {return otherKey != null && (key == null || key.compareTo(otherKey) < 0);}/*** {@code otherKey} 是否 key 相等** @param otherKey* @return*/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<>(null, null);head.nextNodes.add(null);size = 0;maxLevel = 0;}/*** 是否包含 key** @param key* @return*/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);}/*** 新增数据** @param key* @param value*/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;// roll 层高while (Math.random() < PROBABILITY) {newNodeLevel++;}while (newNodeLevel > maxLevel) {// 新节点的层高 > 最大层高,head 需要增加层高head.nextNodes.add(null);maxLevel++;}// 新节点SkipListNode<K, V> newNode = new SkipListNode<>(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--;}}}/*** 获取 key 的节点信息** @param key* @return*/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;}/*** 删除 key** @param key*/public void remove(K key) {if (!containsKey(key)) return;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)) {pre.nextNodes.set(level, next.nextNodes.get(level));}// 判断是否影响最大层高if (level != 0 && pre == head && pre.nextNodes.get(level) == null) {head.nextNodes.remove(level);maxLevel--;}level--;}}/*** 第一个(最小)节点的 key** @return*/public K firstKey() {return head.nextNodes.get(0) != null ? head.nextNodes.get(0).key : null;}/*** 返回最后一个(最大)节点 key** @return*/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;}/*** 大于等于 key 的最小值** @param key* @return*/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;}/*** 小于等于 key 的最大值** @param key* @return*/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;}/*** 得到小于 key 的最大(最右侧)的值** @param key* @return*/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;}/*** 本层小于 {@code key} 最右的节点** @param key* @param cur* @param level* @return*/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;}}// for testpublic 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"));}}
