認識與實現Skip List

前言

增長了向前指針的鏈表叫做跳錶。跳錶全稱叫作跳躍表,簡稱跳錶。跳錶是一個隨機化的數據結構,實質就是一種能夠進行二分查找的有序鏈表。跳錶在原有的有序鏈表上面增長了多級索引,經過索引來實現快速查找。跳錶不只能提升搜索性能,同時也能夠提升插入和刪除操做的性能。java

1. 跳錶的樣兒

跳錶結構圖

2. 跳錶具備以下性質:

1.由不少層結構組成
2.每一層都是一個有序的鏈表
3.最底層(第一層)的鏈表包含全部元素
4.若是一個元素出如今 第 i 層 的鏈表中,則它在第 i 層 之下的鏈表也都會出現。
5.每一個節點包含兩個指針,一個指向同一鏈表中的下一個元素,一個指向下面一層的元素。node

3. 來一個栗子,你將豁然開朗

栗子:查找元素 6
1.頭指針最開始在第一層最小值INT_MIN處
2.因而和旁邊的1比較,固然了1大嘛,因而指針移向1
3.再和當前層4比較, 比 4 大,跳到4
4.與7比較,比7小,因而向下跳到第二層4
5..與5比較,比5大,跳到5
6.與7比較,比7小,跳到最低層5
7.只能依次向後比較了,因而找到了6git

4. 筆者的Java實現,慢慢看,很清晰

1.節點定義,共三個成員變量:value,right,downgithub

package crabapple;

/*
 * Copyright (c) This is zhaoxubin's Java program.
 * Copyright belongs to the crabapple organization.
 * The crabapple organization has all rights to this program.
 * No individual or organization can refer to or reproduce this program without permission.
 * If you need to reprint or quote, please post it to zhaoxubin2016@live.com.
 * You will get a reply within a week,
 *
 */

import java.util.Random;

/**
 * 節點類定義
 */
class Node {

    //值
    public int value = 0;

    //當前層下一個節點
    public Node right;

    //下一層,直連的節點
    public Node down;

    //構造函數
    public Node() {

    }

    public Node(int value) {
        this.value = value;
    }
}

2.跳錶類 定義,你們能夠清晰的看請代碼邏輯結構,該類只暴露insert()和search()兩個方法,其它變量及方法均設爲私有.數據結構

/**
 * 跳錶定義
 */
public class SkipTable {

    //表層數
    private int levelCount;
    
    //表的頭指針
    private Node firstNode;

    //初始化:層數爲1,共先後兩個節點,一個最小值,一個最大值
    private void init() {
        levelCount = 1;
        firstNode=new Node();
        firstNode.value = Integer.MIN_VALUE;
        firstNode.right = new Node(Integer.MAX_VALUE);
    }

    public SkipTable() {
        init();
    }

    /**
     * 查找值
     * @param value
     * @return
     */
    public boolean search(int value) {

        Node current = firstNode;
        return toSearch(current, value);
    }

    private boolean toSearch(Node node, int value) {
        if (node.value == value)
            return true;
        else if (node.right!=null&&value >= node.right.value)
            return toSearch(node.right, value);
        else if (node.down != null)
            return toSearch(node.down, value);
        return false;
    }

    
    
    /**
     * 插入值
     * @param value
     * @return
     */
    public boolean insert(int value) {

        //判斷是否有這個元素
        if (search(value))
            return false;

        //隨機獲取一個層數
        int willLevel = updateLevelCount();

        //判斷是否添加新層
        if (willLevel > levelCount) {
            Node newFirstNode = new Node();
            addLevel(firstNode, newFirstNode);
            firstNode=newFirstNode;
            levelCount = willLevel;
        }

        //插入新元素
        Node port = firstNode;
        int skipLevel = levelCount - willLevel;

        //迭代到指定層
        while ((skipLevel--) > 0)
            port = port.down;

        //上下層新節點的橋樑
        Node insertNode = null;

        while (port != null) {

            //獲取當前層第一個節點指針
            Node curPort = port;

            //迭代到右邊的節點值比本身大爲止
            while (port.right.value < value)
                port = port.right;

            //準備插入的新節點
            Node curInNode = new Node(value);

            //更新當前節點和前節點指針指向
            curInNode.right = port.right;
            port.right = curInNode;

            //將當前節點引用給上層節點
            if (insertNode != null)
                insertNode.down = curInNode;

            //將新插入的節點指針更新到insertNode,以備在下一層創建指向
            insertNode = curInNode;

            //行頭指針向下迭代
            port = port.down;
        }
        return true;

    }

    /**
     * 添加新層
     *
     * @param oldFirst
     * @param newFirst
     */
    private void addLevel(Node oldFirst, Node newFirst) {

        newFirst.value = oldFirst.value;
        newFirst.down = oldFirst;
        if (oldFirst.right != null) {
            Node newRightNode = new Node();
            newFirst.right = newRightNode;
            addLevel(oldFirst.right, newRightNode);
        }
    }

    /**
     * 以必定機率使得獲取一個和老層數差值不超過1的新層數
     * @return
     */
    private int updateLevelCount() {

        Random random=new Random();
        int v = random.nextInt(10);
        return v ==0 ? random.nextInt(levelCount) + 2 : random.nextInt(levelCount)+1 ;
    }
}

3.測試類app

package crabapple;


public class Main {
    
    public static void main(String[] args) {
        //測試
        SkipTable skipTable=new SkipTable();
        skipTable.insert(1);
        skipTable.insert(2);
        skipTable.insert(3);
        skipTable.insert(4);
        skipTable.insert(5);
        skipTable.insert(6);
        skipTable.insert(7);
        skipTable.insert(8);
        skipTable.insert(9);
        skipTable.insert(10);

        //健壯性邊界值測試
        System.out.println(skipTable.search(0));
        System.out.println(skipTable.search(1));
        System.out.println(skipTable.search(2));
        System.out.println(skipTable.search(5));
        System.out.println(skipTable.search(9));
        System.out.println(skipTable.search(10));
        System.out.println(skipTable.search(11));
    }
}

//output:
/**
 * false
 * true
 * true
 * true
 * true
 * true
 * false
 *
 * Process finished with exit code 0
 */

結語

上面的代碼,你們是能夠直接運行,筆者能力有限,代碼也許還有不足,望你們多多指教.dom

相關文章
相關標籤/搜索