一个跳表,应该具有以下特征:
- 一个跳表应该有几个层(level)组成;
- 跳表的第一层包含所有的元素;
- 每一层都是一个有序的链表;
- 如果元素x出现在第i层,则所有比i小的层都包含x;
跳表的插入过程如下;
蓝色线表示查找插入位置的过程,红色的都要记录在一个update[]数组中(反序的方式来记录,即从最高的level开始),即level变化时就需要记录下来,主要是为了后续插入后更新跳表之间的指针用。
新插入节点的level根据一个随机函数(zslRandomLevel())来计算得到,这个随机函数根据幂次法则,幂次法则决定了
数值越大,函数生成它的几率就越小,即生成的level大部分都是比较小的。
如果新申请的node的level小于原来的level,则在
update[]数组中的记录如下图的数字(圆圈内); 然后根据新申请的node的level更新相应的指针;
即如果level只是2,则只用在update中更新update[0]和update[1]中保存的节点的指针, 即将新的node插入到update[]数组中的节点后面,并更新各个节点的span(即指针的跨越节点);如图中蓝色连线。
如果新申请的node的level大于原来的level,则在update[]数组中的记录如下图的数字(圆圈内),即新增的level也需要记录在update[]数组中;然后从0开始依次更新update[]数组中的指针和新申请的node指针, 即将新的node插入到update[]数组中的节点后面,并更新各个节点的span(即指针的跨越节点);如图中蓝色连线。
跳表删除节点比较简单,查找到相应的节点,并将查找过程记录在update[]数组中(和插入类似),然后将各个update的指针更新到删除节点的后续节点;判断头节点中的域是否有指向NULL的,如果有,则将level压缩。