大纲:
- 跳跃表结构
- 跳跃表特性
- 跳跃表源码
一、跳跃表结构
图转自:http://www.cppblog.com/mysileng/archive/2013/04/06/199159.html
这个图描述了一个大于37小于45的数字的插入过程,也基本描述了跳跃表的结构,增、删、查都是从左上角的头结点开始的
每插入一个元素需要先计算随机层数,然后在对应的位置插入一列数值相同的结点,每个结点有2个指针,right和down
二、跳跃表特性
- 第一列结点不保存具体数值
- 跳跃表的每一层都是一条有序的链表
- 增、删、查 时间复杂度为O(logn)
- 最底层的链表包含所有元素
- 跳跃表的层数随机,redis中的随机算法越高层越不容易增长,而且右最大层数限制
三、跳跃表源码
import java.util.Random; public class SkipList { SkipListNode head = null; //头结点 int level = 0; //跳跃表最大层数 Random random = new Random(); public void insert(int target) { //随机一个层数,当前的算法是:每次50%的几率增加一层,最多比当前跳表高一层 int nodeLevel = 1; while (nodeLevel <= this.level && (random.nextInt() & 1) == 1) { nodeLevel++; } //当新结点层数高于跳表层数的时候,新结点替换原有头结点下指针指向原有头结点,替换跳表层数 if (nodeLevel > this.level) { this.level = nodeLevel; this.head = new SkipListNode(null, null, this.head); } //找到结点插入位置的前一个结点,由上自下依次添加结点 SkipListNode cur = this.head; SkipListNode lastNewNode = null; //从head开始找位置,从nodeLevel层开始新增结点 for (int i = this.level; i > 0; i--) { //找到cur结点的下个结点要么为null,要么大于等于target while (cur.right != null && cur.right.value < target) { cur = cur.right; } if (i <= nodeLevel) { cur.right = new SkipListNode(target, cur.right, null); //每次插入的结点被保存在lastNewNode,本层插入后,将上一层新插入的结点down指针指向本层新插入的结点 if (lastNewNode != null) { lastNewNode.down = cur.right; } lastNewNode = cur.right; } cur = cur.down; } } public void delete(int target) { SkipListNode cur = this.head; for (int i = this.level; i > 0; i--) { while (cur.right != null && cur.right.value < target) { cur = cur.right; } //找到的cur下一个值如果是target就删除 if (cur.right != null && cur.right.value == target) { cur.right = cur.right.right; } cur = cur.down; } } public SkipListNode search(int target) { System.out.println(this.level); SkipListNode cur = this.head; //从头结点向右、向下、在向右、再向下,依次查找 while (cur != null) { while (cur.right != null && cur.right.value < target) { cur = cur.right; } if (cur.right != null && cur.right.value == target) { return cur.right; } cur = cur.down; } return null; } } class SkipListNode { Integer value; //当前结点值 SkipListNode right; //右指针 SkipListNode down; //下指针 public SkipListNode(Integer value, SkipListNode right, SkipListNode down) { this.value = value; this.right = right; this.down = down; } }