redis数据结构-跳跃表

大纲:

  1. 跳跃表结构
  2. 跳跃表特性
  3. 跳跃表源码

 

一、跳跃表结构

 图转自:http://www.cppblog.com/mysileng/archive/2013/04/06/199159.html

这个图描述了一个大于37小于45的数字的插入过程,也基本描述了跳跃表的结构,增、删、查都是从左上角的头结点开始的

每插入一个元素需要先计算随机层数,然后在对应的位置插入一列数值相同的结点,每个结点有2个指针,right和down

 

二、跳跃表特性

  1. 第一列结点不保存具体数值
  2. 跳跃表的每一层都是一条有序的链表
  3. 增、删、查 时间复杂度为O(logn)
  4. 最底层的链表包含所有元素
  5. 跳跃表的层数随机,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;
    }
}

 

posted @ 2021-06-05 16:13  扶不起的刘阿斗  阅读(164)  评论(0编辑  收藏  举报