定义
跳表(SkipList,全称跳跃表)是用于有序元素序列快速搜索查找的一个数据结构,跳表是一个随机化的数据结构,实质就是一种可以进行二分查找的有序链表。跳表在原有的有序链表上面增加了多级索引,通过索引来实现快速查找。跳表不仅能提高搜索性能,同时也可以提高插入和删除操作的性能。它在性能上和红黑树,AVL树不相上下,但是跳表的原理非常简单,实现也比红黑树简单很多。
层: 一个节点在第几层是随机的,如果节点在低层3,那么底层3以及3一下都要修改一下节点的指向,操作同链表,看图基本上可以理解跳跃表的实现了。
每一层都是一个有序的列表。
实现
/*** <ul>* <li>1、一个跳表应该有几个层组成,第一层包含所有的元素</li>* <li>2、每一层都是有序链表</li>* <li>3、如果元素x出现在第i层,则所有比i小的层都包含x</li>* <li>4、第i层的元素通过一个down指针指向下一层拥有相同值的元素</li>* </ul>** @author chenshun00@gmail.com* @since 2022/2/12 3:37 下午*/public class SkipList<E> {private static final double p = 0.25D;int MAX_LEVEL = 32;/*** 跳表实际层数*/int level;/*** 跳表头节点*/SkipListNode<E> header;public static void main(String[] args) {SkipList<String> list = new SkipList<>();list.add(3, "耳朵听声音");list.add(7, "镰刀来割草");list.add(6, "口哨嘟嘟响");list.add(4, "红旗迎风飘");list.add(2, "小鸭水上漂");list.add(9, "勺子能吃饭");list.add(1, "铅笔细又长");list.add(5, "秤钩来买菜");list.add(8, "麻花扭一扭");list.printList();System.out.println("1==" + list.get(1));list.remove(1);System.out.println("====");System.out.println("1==" + list.get(1));list.printList();}/*** 创建节点** @param level 节点所在层数* @param key 节点key* @param value 节点value* @return {@link SkipListNode<E>}*/private SkipListNode<E> createNode(int level, int key, E value) {return new SkipListNode<E>(key, value, level);}/*** 初始化跳跃表* 1、初始化level为1级* 2、填充header的的next指针为null*/public SkipList() {this.level = 0;this.header = createNode(MAX_LEVEL, Integer.MIN_VALUE, null);for (int i = 0; i < MAX_LEVEL; i++) {this.header.forwards[i] = null;}}/*** 添加节点到跳跃表** @param key ke3y* @param value value*/public void add(int key, E value) {final int randomLevel = getRandomLevel();final SkipListNode<E> node = createNode(randomLevel, key, value);//从高层开始向底层遍历,为每一层补充节点信息,操作方式同链表for (int i = level - 1; i >= 0; i--) {SkipListNode<E> closable = header;//找到这一层的下一个节点while (closable.forwards[i] != null) {if (key == closable.forwards[i].key) {closable.forwards[i].value = value;return;} else if (key > closable.forwards[i].key) {closable = closable.forwards[i];} else {break;}}if (randomLevel > i) {if (closable.forwards[i] == null) {closable.forwards[i] = node;} else {final SkipListNode<E> next = closable.forwards[i];closable.forwards[i] = node;node.forwards[i] = next;}}}if (randomLevel > level) { //如果随机出来的层数比当前的层数还大,那么超过currentLevel的head 直接指向newNodefor (int i = level; i < randomLevel; i++) {header.forwards[i] = node;}this.level = randomLevel;}}public E get(int key) {SkipListNode<E> closable = header;for (int i = level - 1; i >= 0; i--) {//找到这一层的下一个节点while (closable.forwards[i] != null) {if (key == closable.forwards[i].key) {return closable.forwards[i].value;} else if (key > closable.forwards[i].key) {closable = closable.forwards[i];} else {break;}}if (closable.forwards[i] != null && closable.forwards[i].key == key) {return closable.forwards[i].value;}}return null;}public void remove(int key) {SkipListNode<E> closable = header;for (int i = level - 1; i >= 0; i--) {//找到这一层的下一个节点while (closable.forwards[i] != null) {if (key > closable.forwards[i].key) {closable = closable.forwards[i];} else {break;}}if (closable.forwards[i] != null && closable.forwards[i].key == key) {final SkipListNode<E> current = closable.forwards[i];final SkipListNode<E> next = current.forwards[i];closable.forwards[i] = next;}}}public void printList() {for (int i = level - 1; i >= 0; i--) {SkipListNode<E> curNode = this.header.forwards[i];System.out.print("HEAD->");while (curNode != null) {String line = String.format("(%s,%s)->", curNode.key, curNode.value);System.out.print(line);curNode = curNode.forwards[i];}System.out.println("NIL");}}private int getRandomLevel() {int lvl = 1;//Math.random() 返回一个介于 [0,1) 之间的数字while (lvl < MAX_LEVEL && Math.random() < p) {lvl++;}return lvl;}private static class SkipListNode<E> {/*** key 信息* <p>* 这个是什么?index 吗?*/int key;/*** 存放的元素*/E value;/*** 向前的指针* <p>* 跳表是多层的,这个向前的指针,最多和层数一样。** @since 0.0.4*/SkipListNode<E>[] forwards;@SuppressWarnings("all")public SkipListNode(int key, E value, int level) {this.key = key;this.value = value;this.forwards = new SkipListNode[level];}@Overridepublic String toString() {return "SkipListNode{" +"key=" + key +", value=" + value +", forwards=" + Arrays.toString(forwards) +'}';}}}
