zoukankan      html  css  js  c++  java
  • 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;
        }
    }
  • 相关阅读:
    用C#一次匹配HTML代码中A的链接和文字的方法
    去黑头的7个必胜秘方
    用C#写外挂或辅助工具必须要的WindowsAPI
    用C#把HTML内容转为UBB的方法
    Windows Server 2008 Standard, Enterprise, and Datacenter with Service Pack 2
    xmpp协议分析
    查看Win7的真实版本号方法
    什么是游戏NP?如何在NP下读写游戏内存及如何进入NP进程
    C#正则表达式扫盲 保证 10分钟入门 30分钟精通[绝对不可错过的文章]
    可扩展消息出席协议(XMPP):核心 RFC 3920
  • 原文地址:https://www.cnblogs.com/liuboyuan/p/14852988.html
Copyright © 2011-2022 走看看