Redis underlying data structure: JAVA implementation of jump tables (gitbuh project: AlgorithmPractice)

Project Introduction

  • This project decomposes the common written interview questions of major factories, traces the source to the underlying implementation principles of data structures and algorithms, and knows what they are.
  • Establish a knowledge structure system for easy search, welcome more like-minded friends to join the project AlgorithmPractice, (issues and pull requests are welcome).

1. Title description

  • What is a jump table: A jump table is a linked list that can be searched in half. It inserts a mark pointer into the source linked list, and then the mark pointer is also stringed into a linked list, so that the purpose of quickly finding a value is achieved by searching for the mark pointer. Similarly, if the mark pointer is too long, the mark pointer can be marked again, similar to a multi-level cache.

  • Jump table and its implementation : (The methods mainly include: add() , delete() , find() , initial() , print() ).

  • Code implementation : SkipList

Second, problem-solving ideas
First, prepare a data structure of a Node node. We assume that each linked list value of this quick table is sorted from small to large, and all starting values ​​are set to Integer.MIN_VALUE.

class SkipListNode {
    
    

    int value;
    SkipListNode next;
    SkipListNode down;

    public SkipListNode() {
    
    

        this.value = Integer.MIN_VALUE;
        next = null;
        down = null;
    }

    public SkipListNode(int value) {
    
    

        this.value = value;
        next = null;
        down = null;
    }
}

1. The initial() method

When each linked list is initialized, two nodes at the beginning and the end are required. Note that the values ​​of the head node and the end node are set to (from small to large):
public static final int HEAD_KEY = Integer.MIN_VALUE;
public static final int TAIL_KEY = Integer.MAX_VALUE;

Every time it is initialized, it is necessary to exchange the links between the old and new nodes and the end nodes.

public SkipListNode initial() {
    
    
        SkipListNode phead = new SkipListNode();
        SkipListNode ptail = new SkipListNode();
        phead.value = HEAD_KEY;
        ptail.value = TAIL_KEY;
        phead.next = ptail;
        return phead;
    }

2. add() method

The add method first determines whether the nodes exist, if they exist, they return directly, if they do not exist, they first determine whether it is necessary to create a new layer of tag pointers based on the source linked list.
public void add(int Value) {
    
    

        if (find(Value)) {
    
    
            return;
        }
        SkipListNode insertKey;
        SkipListNode fathersln = null;
        /* 经过实验证明:查找 耗时 比 插入 更加耗时。
        层数越高,整个数据备份越多,越臃肿,但是查找快、插入和删除慢
		层数越低,整个数据备份越少,      但是查找慢、插入和删除快
		综合考虑,建议层数高
		*/

        //无需新建层数
        if (SkipListnum <= (2 << SkipListlevel - 1)) {
    
    
            int k = randomLevel();
            insertKey = head;
            for (int i = 0; i < k; i++) {
    
    
                insertKey = insertKey.down;
            }
        } else {
    
    //需要新建层数
            SkipListNode phead = initial();
            phead.down = head;
            phead.next.down = tail;
            head = phead;
            tail = phead.next;
            insertKey = head;
            SkipListlevel++;
        }
        //向下补全所有的插入节点
        while (insertKey != null) {
    
    
            while (insertKey.next.value < Value) {
    
    
                insertKey = insertKey.next;
            }
            SkipListNode sln = new SkipListNode(Value);
            if (fathersln != null) {
    
    
                fathersln.down = sln;
            }
            sln.next = insertKey.next;
            insertKey.next = sln;
            insertKey = insertKey.down;
            fathersln = sln;
        }
        SkipListnum++;
    }

3. The delete() method

The deletion method needs to pay attention to three points: 1. The number of surface layers is downgraded, 2. The value is searched horizontally, and 3. The value is searched vertically.
public boolean delete(int x) {
    
    

        //快表层高降级
        if (head.next == tail && head.down != null) {
    
    
            head = head.down;
            tail = tail.down;
            this.SkipListlevel--;
        }
        //注意顺序:先降级、再判断不然会出现最后一个元素删除了,但是表级仍然不为1
		if (!find(x)) {
    
    
			return false;
		}
        SkipListNode point = head;
        SkipListNode prepoint = point;


        //横向查找
        while (point.value != x) {
    
    
            while (point.next.value <= x) {
    
    
                prepoint = point;
                point = point.next;
            }
            if (point.value == x) {
    
    
                break;
            }
            point = point.down;
            prepoint = prepoint.down;
            if (point.equals(prepoint)) {
    
    
                continue;
            }
            while (prepoint.next != point) {
    
    
                prepoint = prepoint.next;
            }
        }
        //纵向删除
        while (prepoint != null) {
    
    

            point = point.down;
            prepoint.next = prepoint.next.next;
            prepoint = prepoint.down;
            //循环至最低点结束
            while (prepoint != null && prepoint.next != point) {
    
    
                prepoint = prepoint.next;
            }
        }
        this.SkipListnum--;
        return true;
    }

4. find() method

public boolean find(int x) {
    
    

        SkipListNode point = head;
        while (true) {
    
    
            while (point.next.value <= x) {
    
    
                point = point.next;
            }
            if (point.value == x) {
    
    
                return true;
            }
            if (point.down == null) {
    
    //到达最底层
                return false;
            }
            point = point.down;
        }
    }

5. The print() method

The output is the overall structure of the linked list from top to bottom.
public void print() {
    
    //输出链表的整体结构
        SkipListNode point;
        SkipListNode headpoint = head;
        while (headpoint != null) {
    
    
            point = headpoint;
            while (point.value != TAIL_KEY) {
    
    
                if (point.value != HEAD_KEY) {
    
    
                    System.out.print(point.value + "-");
                }
                point = point.next;
            }
            System.out.println();
            headpoint = headpoint.down;
        }
    }

Guess you like

Origin blog.csdn.net/ljfirst/article/details/104504763