定义

跳表(SkipList,全称跳跃表)是用于有序元素序列快速搜索查找的一个数据结构,跳表是一个随机化的数据结构,实质就是一种可以进行二分查找的有序链表。跳表在原有的有序链表上面增加了多级索引,通过索引来实现快速查找。跳表不仅能提高搜索性能,同时也可以提高插入和删除操作的性能。它在性能上和红黑树,AVL树不相上下,但是跳表的原理非常简单,实现也比红黑树简单很多。

层: 一个节点在第几层是随机的,如果节点在低层3,那么底层3以及3一下都要修改一下节点的指向,操作同链表,看图基本上可以理解跳跃表的实现了。

每一层都是一个有序的列表。image.png

图片来自 http://zhangtielei.com/posts/blog-redis-skiplist.html

实现

  1. /**
  2. * <ul>
  3. * <li>1、一个跳表应该有几个层组成,第一层包含所有的元素</li>
  4. * <li>2、每一层都是有序链表</li>
  5. * <li>3、如果元素x出现在第i层,则所有比i小的层都包含x</li>
  6. * <li>4、第i层的元素通过一个down指针指向下一层拥有相同值的元素</li>
  7. * </ul>
  8. *
  9. * @author chenshun00@gmail.com
  10. * @since 2022/2/12 3:37 下午
  11. */
  12. public class SkipList<E> {
  13. private static final double p = 0.25D;
  14. int MAX_LEVEL = 32;
  15. /**
  16. * 跳表实际层数
  17. */
  18. int level;
  19. /**
  20. * 跳表头节点
  21. */
  22. SkipListNode<E> header;
  23. public static void main(String[] args) {
  24. SkipList<String> list = new SkipList<>();
  25. list.add(3, "耳朵听声音");
  26. list.add(7, "镰刀来割草");
  27. list.add(6, "口哨嘟嘟响");
  28. list.add(4, "红旗迎风飘");
  29. list.add(2, "小鸭水上漂");
  30. list.add(9, "勺子能吃饭");
  31. list.add(1, "铅笔细又长");
  32. list.add(5, "秤钩来买菜");
  33. list.add(8, "麻花扭一扭");
  34. list.printList();
  35. System.out.println("1==" + list.get(1));
  36. list.remove(1);
  37. System.out.println("====");
  38. System.out.println("1==" + list.get(1));
  39. list.printList();
  40. }
  41. /**
  42. * 创建节点
  43. *
  44. * @param level 节点所在层数
  45. * @param key 节点key
  46. * @param value 节点value
  47. * @return {@link SkipListNode<E>}
  48. */
  49. private SkipListNode<E> createNode(int level, int key, E value) {
  50. return new SkipListNode<E>(key, value, level);
  51. }
  52. /**
  53. * 初始化跳跃表
  54. * 1、初始化level为1级
  55. * 2、填充header的的next指针为null
  56. */
  57. public SkipList() {
  58. this.level = 0;
  59. this.header = createNode(MAX_LEVEL, Integer.MIN_VALUE, null);
  60. for (int i = 0; i < MAX_LEVEL; i++) {
  61. this.header.forwards[i] = null;
  62. }
  63. }
  64. /**
  65. * 添加节点到跳跃表
  66. *
  67. * @param key ke3y
  68. * @param value value
  69. */
  70. public void add(int key, E value) {
  71. final int randomLevel = getRandomLevel();
  72. final SkipListNode<E> node = createNode(randomLevel, key, value);
  73. //从高层开始向底层遍历,为每一层补充节点信息,操作方式同链表
  74. for (int i = level - 1; i >= 0; i--) {
  75. SkipListNode<E> closable = header;
  76. //找到这一层的下一个节点
  77. while (closable.forwards[i] != null) {
  78. if (key == closable.forwards[i].key) {
  79. closable.forwards[i].value = value;
  80. return;
  81. } else if (key > closable.forwards[i].key) {
  82. closable = closable.forwards[i];
  83. } else {
  84. break;
  85. }
  86. }
  87. if (randomLevel > i) {
  88. if (closable.forwards[i] == null) {
  89. closable.forwards[i] = node;
  90. } else {
  91. final SkipListNode<E> next = closable.forwards[i];
  92. closable.forwards[i] = node;
  93. node.forwards[i] = next;
  94. }
  95. }
  96. }
  97. if (randomLevel > level) { //如果随机出来的层数比当前的层数还大,那么超过currentLevel的head 直接指向newNode
  98. for (int i = level; i < randomLevel; i++) {
  99. header.forwards[i] = node;
  100. }
  101. this.level = randomLevel;
  102. }
  103. }
  104. public E get(int key) {
  105. SkipListNode<E> closable = header;
  106. for (int i = level - 1; i >= 0; i--) {
  107. //找到这一层的下一个节点
  108. while (closable.forwards[i] != null) {
  109. if (key == closable.forwards[i].key) {
  110. return closable.forwards[i].value;
  111. } else if (key > closable.forwards[i].key) {
  112. closable = closable.forwards[i];
  113. } else {
  114. break;
  115. }
  116. }
  117. if (closable.forwards[i] != null && closable.forwards[i].key == key) {
  118. return closable.forwards[i].value;
  119. }
  120. }
  121. return null;
  122. }
  123. public void remove(int key) {
  124. SkipListNode<E> closable = header;
  125. for (int i = level - 1; i >= 0; i--) {
  126. //找到这一层的下一个节点
  127. while (closable.forwards[i] != null) {
  128. if (key > closable.forwards[i].key) {
  129. closable = closable.forwards[i];
  130. } else {
  131. break;
  132. }
  133. }
  134. if (closable.forwards[i] != null && closable.forwards[i].key == key) {
  135. final SkipListNode<E> current = closable.forwards[i];
  136. final SkipListNode<E> next = current.forwards[i];
  137. closable.forwards[i] = next;
  138. }
  139. }
  140. }
  141. public void printList() {
  142. for (int i = level - 1; i >= 0; i--) {
  143. SkipListNode<E> curNode = this.header.forwards[i];
  144. System.out.print("HEAD->");
  145. while (curNode != null) {
  146. String line = String.format("(%s,%s)->", curNode.key, curNode.value);
  147. System.out.print(line);
  148. curNode = curNode.forwards[i];
  149. }
  150. System.out.println("NIL");
  151. }
  152. }
  153. private int getRandomLevel() {
  154. int lvl = 1;
  155. //Math.random() 返回一个介于 [0,1) 之间的数字
  156. while (lvl < MAX_LEVEL && Math.random() < p) {
  157. lvl++;
  158. }
  159. return lvl;
  160. }
  161. private static class SkipListNode<E> {
  162. /**
  163. * key 信息
  164. * <p>
  165. * 这个是什么?index 吗?
  166. */
  167. int key;
  168. /**
  169. * 存放的元素
  170. */
  171. E value;
  172. /**
  173. * 向前的指针
  174. * <p>
  175. * 跳表是多层的,这个向前的指针,最多和层数一样。
  176. *
  177. * @since 0.0.4
  178. */
  179. SkipListNode<E>[] forwards;
  180. @SuppressWarnings("all")
  181. public SkipListNode(int key, E value, int level) {
  182. this.key = key;
  183. this.value = value;
  184. this.forwards = new SkipListNode[level];
  185. }
  186. @Override
  187. public String toString() {
  188. return "SkipListNode{" +
  189. "key=" + key +
  190. ", value=" + value +
  191. ", forwards=" + Arrays.toString(forwards) +
  192. '}';
  193. }
  194. }
  195. }

参考链接