跳表(skip list)

我們知道二叉搜索算法能夠高效的查詢數(shù)據(jù)稀颁,但是需要一塊連續(xù)的內(nèi)存芬失,而且增刪改效率很低。
跳表匾灶,是基于鏈表實現(xiàn)的一種類似“二分”的算法棱烂。它可以快速的實現(xiàn)增,刪阶女,改颊糜,查操作。
我們先來看一下單向鏈表如何實現(xiàn)查找


image.png

當我們要在該單鏈表中查找某個數(shù)據(jù)的時候需要的時間復雜度為O(n).
怎么提高查詢效率呢秃踩?如果我們給該單鏈表加一級索引衬鱼,將會改善查詢效率。

image.png

如圖所示憔杨,當我們每隔一個節(jié)點就提取出來一個元素到上一層鸟赫,把這一層稱作索引,其中的down指針指向原始鏈表消别。
當我們查找元素16的時候惯疙,單鏈表需要比較10次,而加過索引的兩級鏈表只需要比較7次妖啥。當數(shù)據(jù)量增大到一定程度的時候霉颠,效率將會有顯著的提升。
如果我們再加多幾級索引的話荆虱,效率將會進一步提升蒿偎。這種鏈表加多級索引的結(jié)構,就叫做跳表怀读。
image.png

跳表的查詢時間復雜度可以達到O(logn)

高效的動態(tài)插入和刪除

跳表也可以實現(xiàn)高效的動態(tài)更新诉位,定位到要插入或者刪除數(shù)據(jù)的位置需要的時間復雜度為O(logn).
在插入的時候,我們需要考慮將要插入的數(shù)據(jù)也插入到索引中去菜枷。在這里使用的策略是通過隨機函數(shù)生成一個隨機數(shù)K,然后將要插入的數(shù)據(jù)同時插入到k級以下的每級索引中苍糠。

下面是跳表的java代碼實現(xiàn)

package structs;

import java.util.Random;

public class SkipList {
    private static final int MAX_LEVEL = 16;
    private int levelCount = 1;
    private Node head = new Node();
    private Random random = new Random();

    public Node find(int value){
        Node p = head;
        for(int i = levelCount - 1; i >= 0; i--){
            while(p.forwards[i] != null && p.forwards[i].data < value){
                p = p.forwards[i];
            }
        }
        if(p.forwards[0] != null && p.forwards[0].data == value) return p.forwards[0];
        return null;
    }

    public void insert(int value){
        Node p = head;
        int level = randomLevel();
        Node node = new Node();
        node.data = value;
        node.maxLevel = level;
        Node update[] = new Node[level];
        for(int i = level; i >= 0; i--){
            while(p.forwards[i] != null && p.forwards[i].data < value){
                p = p.forwards[i];
            }
            update[i] = p;
        }
        for(int i = 0; i < level; i++){
            node.forwards[i] = update[i].forwards[i];
            update[i].forwards[i] = node;
        }
        if(levelCount < level) levelCount = level;
    }

    public void delete(int value){
        Node[] deleteNode = new Node[MAX_LEVEL];
        Node p = head;
        for(int i = levelCount - 1; i >=0; i--){
            while(p.forwards[i] != null && p.forwards[i].data < value){
                p = p.forwards[i];
            }
            deleteNode[i] = p;
        }
        if(p.forwards[0] != null && p.forwards[0].data == value){
            for(int i = levelCount - 1; i >= 0; i--){
                if(deleteNode[i] != null && deleteNode[i].forwards[i].data == value){
                    deleteNode[i].forwards[i] = deleteNode[i].forwards[i].forwards[i];
                }
            }
        }
    }

    public void printAll(){
        Node p = head;
        while(p.forwards[0] != null){
            System.out.print(p.forwards[0] + " ");
            p = p.forwards[0];
        }
        System.out.println();
    }
    private int randomLevel() {
        int level = 0;
        for(int i = 0; i < MAX_LEVEL; i++){
            if(random.nextInt()%2 == 1){
                level++;
            }
        }
        return level;
    }

    class Node{
        private int data;
        private Node[] forwards = new Node[MAX_LEVEL];
        private int maxLevel;

        public String toString(){
            StringBuilder sb = new StringBuilder();
            sb.append("{data: ");
            sb.append(data);
            sb.append("; level: ");
            sb.append(maxLevel);
            sb.append(" }");
            return sb.toString();
        }
    }


}

其中理解了Node節(jié)點的結(jié)構,代碼就會很好理解了啤誊。
Node節(jié)點中forwards存儲的是該節(jié)點在各個level索引的下一個數(shù)據(jù)節(jié)點岳瞭;

?著作權歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市蚊锹,隨后出現(xiàn)的幾起案子瞳筏,更是在濱河造成了極大的恐慌,老刑警劉巖牡昆,帶你破解...
    沈念sama閱讀 216,744評論 6 502
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件姚炕,死亡現(xiàn)場離奇詭異,居然都是意外死亡,警方通過查閱死者的電腦和手機柱宦,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,505評論 3 392
  • 文/潘曉璐 我一進店門些椒,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人掸刊,你說我怎么就攤上這事免糕。” “怎么了痒给?”我有些...
    開封第一講書人閱讀 163,105評論 0 353
  • 文/不壞的土叔 我叫張陵说墨,是天一觀的道長。 經(jīng)常有香客問我苍柏,道長尼斧,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 58,242評論 1 292
  • 正文 為了忘掉前任试吁,我火速辦了婚禮棺棵,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘熄捍。我一直安慰自己烛恤,他們只是感情好,可當我...
    茶點故事閱讀 67,269評論 6 389
  • 文/花漫 我一把揭開白布余耽。 她就那樣靜靜地躺著缚柏,像睡著了一般。 火紅的嫁衣襯著肌膚如雪碟贾。 梳的紋絲不亂的頭發(fā)上币喧,一...
    開封第一講書人閱讀 51,215評論 1 299
  • 那天,我揣著相機與錄音袱耽,去河邊找鬼杀餐。 笑死,一個胖子當著我的面吹牛朱巨,可吹牛的內(nèi)容都是我干的史翘。 我是一名探鬼主播,決...
    沈念sama閱讀 40,096評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼冀续,長吁一口氣:“原來是場噩夢啊……” “哼琼讽!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起沥阳,我...
    開封第一講書人閱讀 38,939評論 0 274
  • 序言:老撾萬榮一對情侶失蹤跨琳,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后桐罕,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 45,354評論 1 311
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 37,573評論 2 333
  • 正文 我和宋清朗相戀三年功炮,在試婚紗的時候發(fā)現(xiàn)自己被綠了溅潜。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 39,745評論 1 348
  • 序言:一個原本活蹦亂跳的男人離奇死亡薪伏,死狀恐怖滚澜,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情嫁怀,我是刑警寧澤设捐,帶...
    沈念sama閱讀 35,448評論 5 344
  • 正文 年R本政府宣布,位于F島的核電站塘淑,受9級特大地震影響萝招,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜存捺,卻給世界環(huán)境...
    茶點故事閱讀 41,048評論 3 327
  • 文/蒙蒙 一槐沼、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧捌治,春花似錦岗钩、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,683評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至森枪,卻和暖如春视搏,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背疲恢。 一陣腳步聲響...
    開封第一講書人閱讀 32,838評論 1 269
  • 我被黑心中介騙來泰國打工凶朗, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人显拳。 一個月前我還...
    沈念sama閱讀 47,776評論 2 369
  • 正文 我出身青樓棚愤,卻偏偏與公主長得像,于是被迫代替她去往敵國和親杂数。 傳聞我的和親對象是個殘疾皇子宛畦,可洞房花燭夜當晚...
    茶點故事閱讀 44,652評論 2 354

推薦閱讀更多精彩內(nèi)容

  • 我在這里 但有時候我也不知道我在哪里 我明明在這一個遍地是人的角落呼吸 有時候也忘了自己不是一只鳥 要獨自飛行 如...
    柳橙芝閱讀 489評論 5 13
  • 尊敬的帽子先生: 您好! 非常抱歉揍移,因為我的胡鬧次和,將你從心愛的人的頭頂上吹到了這棵即將枯死的的大樹上...
    一槿閱讀 747評論 0 0
  • pch讓編譯更快 在日常的開發(fā)中踏施,有很多地方會用到Foundation和UIKit石蔗,使用之前需要先將頭文件#imp...
    liaojinxing閱讀 2,699評論 2 16