美文网首页
Redis-sorted set

Redis-sorted set

作者: 麦大大吃不胖 | 来源:发表于2020-12-12 00:21 被阅读0次

by shihang.mai

1. 代码

package skpilist;

import java.util.Random;

public class SkipList {
    //  number of entries in the Skip List
    public int n;
    // height
    public int h;
    // 表头
    private SkipListEntry head;
    // 表尾
    private SkipListEntry tail;
    // 生成randomLevel用到的概率值
    private Random r;

    public SkipList() {

        head = new SkipListEntry(Integer.MIN_VALUE, Integer.MIN_VALUE);
        tail = new SkipListEntry(Integer.MAX_VALUE, Integer.MAX_VALUE);
        head.right =tail;
        tail.left = head;
        n = 0;
        h = 0;
        r = new Random();
    }

    /**
     * 查找
     * @param
     * @return
     */
    public SkipListEntry findEntry(Integer key) {
        SkipListEntry p;

       /* -----------------
       Start at "head"
       ----------------- */
        p = head;

        while ( true ) {
          /* --------------------------------------------
       Search RIGHT until you find a LARGER entry
             E.g.: k = 34
                       10 ---> 20 ---> 30 ---> 40
                                        ^
                                        |
                                        p stops here
        p.right.key = 40
       -------------------------------------------- */
            while ( p.right.key != Integer.MAX_VALUE && p.right.key< key ) {
                p = p.right;
                //    System.out.println(">>>> " + p.key);
            }

    /* ---------------------------------
       Go down one level if you can...
       --------------------------------- */
            if ( p.down != null ) {
                p = p.down;
                // System.out.println("vvvv " + p.key);
            } else{
                //加入判断by shihang.mai==============原博主代码需要在这加入判断
                if(p.right.key== key){
                    p = p.right;
                }
                break;  // We reached the LOWEST level... Exit...
            }

        }

        return(p);         // p.key <= k
    }
    public Integer get(int key) {

        SkipListEntry p;

        p = findEntry(key);

        if(p.key ==key) {
            return p.value;
        } else {
            return null;
        }

    }

    public Integer insert(int key, int value) {
        SkipListEntry p, q;
        int i = 0;

        // 查找适合插入的位子
        p = findEntry(key);

        // 如果跳跃表中存在含有key值的节点,则进行value的修改操作即可完成
        if(p.key ==key) {
            Integer oldValue = p.value;
            p.value = value;
            return oldValue;
        }

        // 如果跳跃表中不存在含有key值的节点,则进行新增操作
        q = new SkipListEntry(key, value);
        /* --------------------------------------------------------------
        Insert q into the lowest level after SkipListEntry p:
                         p   put q here           p        q
                         |     |                  |        |
                         V     V                  V        V        V
        Lower level:    [ ] <------> [ ]    ==>  [ ] <--> [ ] <--> [ ]
        --------------------------------------------------------------- */
        q.left = p;
        q.right = p.right;
        p.right.left = q;
        p.right = q;

        //本层操作完毕,看更高层操作
        //抛硬币随机决定是否上层插入
        while ( r.nextDouble() < 0.5 /* Coin toss */ ) {
            if ( i >= h )   // We reached the top level !!!
            {
                //Create a new empty TOP layer
                addEmptyLevel();
            }
         /* ------------------------------------
         Find first element with an UP-link
         ------------------------------------ */
            while ( p.up == null )
            {
                p = p.left;
            }
      /* --------------------------------
       Make p point to this UP element
       -------------------------------- */
            p = p.up;

    /* ---------------------------------------------------
          Add one more (k,*) to the column
       Schema for making the linkage:
               p <--> e(k,*) <--> p.right
                         ^
                  |
                  v
                  q
       ---------------------------------------------------- */
            SkipListEntry e;
            // 这里需要注意的是除底层节点之外的节点对象是不需要value值的
            e = new SkipListEntry(key, null);
    /* ---------------------------------------
       Initialize links of e
       --------------------------------------- */
            e.left = p;
            e.right = p.right;
            e.down = q;
    /* ---------------------------------------
       Change the neighboring links..
       --------------------------------------- */
            p.right.left = e;
            p.right = e;
            q.up = e;

            //把q执行新插入的节点:
            q = e;
            // level增加
            i = i + 1;


        }
        n = n+1; //更新链表长度
        return null;
    }



    private void addEmptyLevel() {

        SkipListEntry p1, p2;

        p1 = new SkipListEntry(Integer.MIN_VALUE, null);
        p2 = new SkipListEntry(Integer.MAX_VALUE, null);

        p1.right = p2;
        p1.down = head;

        p2.left = p1;
        p2.down = tail;

        head.up = p1;
        tail.up = p2;

        head = p1;
        tail = p2;

        h = h + 1;
    }

    public Integer remove(int key) {

        SkipListEntry p, q;

        p = findEntry(key);

        if(!p.key.equals(key)) {
            return null;
        }

        Integer oldValue = p.value;
        while(p != null) {
            q = p.up;
            p.left.right = p.right;
            p.right.left = p.left;
            p = q;
        }

        return oldValue;
    }

    public void printHorizontal()
    {
        String s = "";
        int I;

        SkipListEntry p;

         /* ----------------------------------
        Record the position of each entry
        ---------------------------------- */
        p = head;

        while ( p.down != null )
        {
            p = p.down;
        }

        i = 0;
        while ( p != null )
        {
            p.pos = I++;
            p = p.right;
        }

         /* -------------------
        Print...
        ------------------- */
        p = head;

        while ( p != null )
        {
            s = getOneRow( p );
            System.out.println(s);

            p = p.down;
        }
    }

    public String getOneRow( SkipListEntry p )
    {
        String s;
        int a, b, I;

        a = 0;

        s = "" + p.key;
        p = p.right;


        while ( p != null )
        {
            SkipListEntry q;

            q = p;
            while (q.down != null)
                q = q.down;
            b = q.pos;

            s = s + " <-";


            for (i = a+1; i < b; I++)
                s = s + "--------";

            s = s + "> " + p.key;

            a = b;

            p = p.right;
        }

        return(s);
    }

    public static void main(String[] args) {

        SkipList l = new SkipList();
        Random r = new Random();
        for (int i = 0; i < 10; i++ )
        {
            int tmp = r.nextInt(100);
            System.out.println("add:"+tmp);
            l.insert( tmp,  tmp );
            l.printHorizontal();
        }
        System.out.println("add:18");
        l.insert( 18,  18 );
        l.printHorizontal();

        System.out.println("remove:"+l.remove(18));;
        l.printHorizontal();
        //System.out.println("over");

    }
}

class SkipListEntry {
    Integer key;
    Integer value;
    skpilist.SkipListEntry right;
    skpilist.SkipListEntry left;
    skpilist.SkipListEntry down;
    skpilist.SkipListEntry up;
    public SkipListEntry(Integer key, Integer value) {
        this.key = key;
        this.value = value;
    }
    public String toString()
    {
        return "(" + key + "," + value + ")";
    }

    public int pos;//与数据结构无关,只为输出方便
}

2. 解析

redis的sortSet用的跳表,用空间换时间

节点属性包括:key、value、上下左右节点


class SkipListEntry {
    Integer key;
   Integer value;
   SkipListEntry right;      
   SkipListEntry left;
   SkipListEntry down;
   SkipListEntry up;
   public SkipListEntry(Integer key, Integer value) {
       this.key = key;
       this.value = value;           
   }
   public String toString() 
   {
     return "(" + key + "," + value + ")";
   }
   
   public int pos;//与数据结构无关,只为输出方便
}

跳表属性包括:有多少个元素、跳表高度、head和tail节点、还有一个抛硬币的随机数(用来决定要不要构建上一层索引的)

public class SkipList<T {

//  number of entries in the Skip List  
public int n;
// height
public int h;
// 表头
private SkipListEntry head;
// 表尾
private SkipListEntry tail;
// 生成randomLevel用到的概率值
private Random r;
查找

对于查找,例如查找50

  1. 从head出发查找,因为head指向最顶层链表的开始节点,相当于从顶层开始查找;
  2. 移动到当前节点的右指针(right)指向的节点,直到右节点的key值大于要查找的key值时停止在当前节点;
  3. 如果还有更低层次的链表,则移动到当前节点的下一层节点,继续2的过程
  4. 重复第2步 和 第3步,直到查找到key值所在的节点,或者不存在而退出查找

对于插入,例如插入42

  1. 先通过查找42,如果找到,那么直接替换值

  2. 如果没找到返回比它少的一个,即39,那么用一个变量P=39

  3. 插入的变量Q=42,那么插入到39和44之间,并维护前后指针。这时抛硬币,如果需要向上层晋升,那么

  4. 将P变量找到最近一个有上层节点的节点,即38,将变量A向上移动一层,创建变量Z(key=42,value=null),插入到上层节点,并维护前后指针。如此往复,如果一直晋升,那么结果如下图

    过程图
晋升

对于删除,就把所有层级删掉,并维护前后指针,这个没什么好说的

参考地址:https://blog.csdn.net/bohu83/article/details/83654524

相关文章

网友评论

      本文标题:Redis-sorted set

      本文链接:https://www.haomeiwen.com/subject/whnziktx.html