轉載自【算法導論33】跳躍表(Skip list)原理與java實現
package com.java.algorithm.test; import java.util.Random; public class SkipListTest { /** * 跳躍表的節點,包括key-value和上下左右4個指針 * 參考:http://www.acmerblog.com/skip-list-impl-java-5773.html */ static class SkipListNode<T> { public int key; public T value; public SkipListNode<T> up, down, left, right; // 上下左右 四個指針 public static final int HEAD_KEY = Integer.MIN_VALUE; // 負無窮 public static final int TAIL_KEY = Integer.MAX_VALUE; // 正無窮 public int pos; // 主要爲了打印鏈表用 public SkipListNode(int k, T v) { // TODO Auto-generated constructor stub key = k; value = v; } public int getKey() { return key; } public void setKey(int key) { this.key = key; } public T getValue() { return value; } public void setValue(T value) { this.value = value; } public boolean equals(Object o) { if (this == o) { return true; } if (o == null) { return false; } if (!(o instanceof SkipListNode<?>)) { return false; } SkipListNode<T> ent; try { ent = (SkipListNode<T>) o; // 檢測類型 } catch (ClassCastException ex) { return false; } return (ent.getKey() == key) && (ent.getValue() == value); } @Override public String toString() { // TODO Auto-generated method stub return "key-value:" + key + "-" + value; } } /** * 不固定層級的跳躍表 參考:http://www.acmerblog.com/skip-list-impl-java-5773.html */ static class SkipList<T> { private SkipListNode<T> head, tail; private int nodes;// 節點總數 private int listLevel;// 層數 private Random random;// 用於投擲硬幣 private static final double PROBABILITY = 0.5;// 向上提升一個的概率 public SkipList() { random = new Random(); clear(); } /** * 清空跳躍表 */ public void clear() { head = new SkipListNode<T>(SkipListNode.HEAD_KEY, null); tail = new SkipListNode<T>(SkipListNode.TAIL_KEY, null); horizontalLink(head, tail); listLevel = 0; nodes = 0; } public boolean isEmpty() { return nodes == 0; } public int size() { return nodes; } /** * 在最下面一層,找到要插入的位置前面的那個key */ private SkipListNode<T> findNode(int key) { SkipListNode<T> p = head; while (true) { while (p.right.key != SkipListNode.TAIL_KEY && p.right.key <= key) { p = p.right; } if (p.down != null) { p = p.down; } else { break; } } return p; } /** * 查找是否存儲key,存在則返回該節點,否則返回null */ public SkipListNode<T> search(int key) { SkipListNode<T> p = findNode(key); if (key == p.getKey()) { return p; } else { return null; } } /** * 向跳躍表中添加key-value * */ public void put(int k, T v) { SkipListNode<T> p = findNode(k); // 如果key值相同,替換原來的vaule即可結束 if (k == p.getKey()) { p.value = v; return; } SkipListNode<T> q = new SkipListNode<T>(k, v); backLink(p, q); int currentLevel = 0;// 當前所在的層級是0 // 拋硬幣 while (random.nextDouble() < PROBABILITY) { // 如果超出了高度,需要重新建一個頂層 if (currentLevel >= listLevel) { listLevel++; SkipListNode<T> p1 = new SkipListNode<T>(SkipListNode.HEAD_KEY, null); SkipListNode<T> p2 = new SkipListNode<T>(SkipListNode.TAIL_KEY, null); horizontalLink(p1, p2); vertiacallLink(p1, head); vertiacallLink(p2, tail); head = p1; tail = p2; } // 將p移動到上一層 while (p.up == null) { p = p.left; } p = p.up; SkipListNode<T> e = new SkipListNode<T>(k, null);// 只保存key就ok backLink(p, e);// 將e插入到p的後面 vertiacallLink(e, q);// 將e和q上下連接 q = e; currentLevel++; } nodes++;// 層數遞增 } public void remove(int key) { SkipListNode<T> p = findNode(key); if (p.getKey() != key) { return; } // 刪除元素後重新關聯,同時使被刪除的對象遊離,便於垃圾回收 horizontalLink(p.left, p.right); p.right = null; p.left = null; // 自底向上,使所有鍵等於key的SkipListEntry對象左右兩個方向的引用置空 while (p.up != null) { p = p.up; horizontalLink(p.left, p.right); p.right = null; p.left = null; } // 自頂向下,使所有鍵等於key的SkipListEntry對象上下兩個方向的引用置空 while (p.down != null) { SkipListNode<T> temp = p.down; p.down = null; temp.up = null; p = temp; } /* * 刪除元素後,如果頂層的鏈表只有head和tail兩個元素,則刪除頂層。 * 刪除頂層以後最新的頂層如果依然只有head和tail兩個元素,則也要被刪除,以此類推。 */ while (head.right.key == tail.key && listLevel > 0) { SkipListNode<T> p1, p2; p1 = head.down; p2 = tail.down; head.right = null; head.down = null; tail.left = null; tail.down = null; p1.up = null; p2.up = null; head = p1; tail = p2; listLevel = listLevel - 1; } // 成功移除一個元素,大小減1 nodes = nodes - 1; // System.out.println("-----刪除[" + key + "]後的跳躍表是:-----"); } // node1後面插入node2 private void backLink(SkipListNode<T> node1, SkipListNode<T> node2) { node2.left = node1; node2.right = node1.right; node1.right.left = node2; node1.right = node2; } /** * 水平雙向連接 */ private void horizontalLink(SkipListNode<T> node1, SkipListNode<T> node2) { node1.right = node2; node2.left = node1; } /** * 垂直雙向連接 */ private void vertiacallLink(SkipListNode<T> node1, SkipListNode<T> node2) { node1.down = node2; node2.up = node1; } /** * 打印出原始數據 */ @Override public String toString() { if (isEmpty()) { return "跳躍表爲空!"; } StringBuilder builder = new StringBuilder(); SkipListNode<T> p = head; while (p.down != null) { p = p.down; } while (p.left != null) { p = p.left; } if (p.right != null) { p = p.right; } while (p.right != null) { builder.append(p); builder.append("\n"); p = p.right; } return builder.toString(); } /** * 打印出跳錶的圖示結構(水平方向) */ public void printHorizontal() { String s = ""; int i; SkipListNode<T> p; p = head; while (p.down != null) { p = p.down; } i = 0; while (p != null) { p.pos = i++; p = p.right; } p = head; while (p != null) { s = getOneRow(p); System.out.println(s); p = p.down; } } private String getOneRow(SkipListNode<T> p) { String s; int a, b, i; a = 0; s = "" + p.key; p = p.right; while (p != null) { SkipListNode<T> q; q = p; while (q.down != null){ q = q.down; } b = q.pos; s = s + " <-"; for (i = a + 1; i < b; i++){ s = s + "--------"; } s = s + "> " + p.key; a = b; p = p.right; } return s; } /** * 打印出跳錶的圖示結構(垂直方向) */ public void printVertical() { String s = ""; SkipListNode<T> p; p = head; while (p.down != null){ p = p.down; } while (p != null) { s = getOneColumn(p); System.out.println(s); p = p.right; } } private String getOneColumn(SkipListNode<T> p) { String s = ""; while (p != null) { s = s + " " + p.key; p = p.up; } return (s); } } public static void main(String[] args) { SkipList<String> list = new SkipList<String>(); System.out.println(list); list.put(2, "yan"); list.put(1, "co"); list.put(3, "feng"); list.put(1, "cao");// 測試同一個key值 list.put(4, "曹"); list.put(6, "豐"); list.put(5, "豔"); System.out.println(list); System.out.println("size:" + list.size()); System.out.println("height:" + list.listLevel); list.printHorizontal(); System.out.println("刪除元素3,2後:"); list.remove(3); list.remove(2); System.out.println(list); System.out.println("size:" + list.size()); System.out.println("height:" + list.listLevel); list.printHorizontal(); } }