日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

Skpi List跳表

發布時間:2025/4/14 编程问答 18 豆豆
生活随笔 收集整理的這篇文章主要介紹了 Skpi List跳表 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

為什么選擇跳表

目前經常使用的平衡數據結構有:B樹,紅黑樹,AVL樹,Splay Tree, Treep等。

?

想象一下,給你一張草稿紙,一只筆,一個編輯器,你能立即實現一顆紅黑樹,或者AVL樹

出來嗎? 很難吧,這需要時間,要考慮很多細節,要參考一堆算法與數據結構之類的樹,

還要參考網上的代碼,相當麻煩。

?

用跳表吧,跳表是一種隨機化的數據結構,目前開源軟件 Redis 和 LevelDB 都有用到它,

它的效率和紅黑樹以及 AVL 樹不相上下,但跳表的原理相當簡單,只要你能熟練操作鏈表,

就能輕松實現一個 SkipList。

?

有序表的搜索

考慮一個有序表:


?

從該有序表中搜索元素 < 23, 43, 59 > ,需要比較的次數分別為 < 2, 4, 6 >,總共比較的次數

為 2 + 4 + 6 = 12 次。有沒有優化的算法嗎? ?鏈表是有序的,但不能使用二分查找。類似二叉

搜索樹,我們把一些節點提取出來,作為索引。得到如下結構:



?這里我們把 < 14, 34, 50, 72 > 提取出來作為一級索引,這樣搜索的時候就可以減少比較次數了。

?我們還可以再從一級索引提取一些元素出來,作為二級索引,變成如下結構:

?

??

?

? ? ?這里元素不多,體現不出優勢,如果元素足夠多,這種索引結構就能體現出優勢來了。

?

跳表

下面的結構是就是跳表:

?其中 -1 表示 INT_MIN, 鏈表的最小值,1 表示 INT_MAX,鏈表的最大值。

?

?

跳表具有如下性質:

(1) 由很多層結構組成

(2) 每一層都是一個有序的鏈表

(3) 最底層(Level 1)的鏈表包含所有元素

(4) 如果一個元素出現在 Level i 的鏈表中,則它在 Level i 之下的鏈表也都會出現。

(5) 每個節點包含兩個指針,一個指向同一鏈表中的下一個元素,一個指向下面一層的元素。

?

跳表的搜索


?

例子:查找元素 117

(1) 比較 21, 比 21 大,往后面找

(2) 比較 37, ? 比 37大,比鏈表最大值小,從 37 的下面一層開始找

(3) 比較 71, ?比 71 大,比鏈表最大值小,從 71 的下面一層開始找

(4) 比較 85, 比 85 大,從后面找

(5) 比較 117, 等于 117, 找到了節點。

?

具體的搜索算法如下:?

?

C代碼??
  • /*?如果存在?x,?返回?x?所在的節點,?
  • ?*?否則返回?x?的后繼節點?*/??
  • find(x)???
  • {??
  • ????p?=?top;??
  • ????while?(1)?{??
  • ????????while?(p->next->key?<?x)??
  • ????????????p?=?p->next;??
  • ????????if?(p->down?==?NULL)???
  • ????????????return?p->next;??
  • ????????p?=?p->down;??
  • ????}??
  • }??
  • ?

    ?

    跳表的插入

    先確定該元素要占據的層數 K(采用丟硬幣的方式,這完全是隨機的)

    然后在 Level 1 ... Level K 各個層的鏈表都插入元素。

    例子:插入 119, K = 2


    ?

    如果 K 大于鏈表的層數,則要添加新的層。

    例子:插入 119, K = 4



    丟硬幣決定 K

    插入元素的時候,元素所占有的層數完全是隨機的,通過一下隨機算法產生:

    ?

    C代碼??
  • int?random_level()??
  • {??
  • ????K?=?1;??
  • ??
  • ????while?(random(0,1))??
  • ????????K++;??
  • ??
  • ????return?K;??
  • }??
  • ?

    相當與做一次丟硬幣的實驗,如果遇到正面,繼續丟,遇到反面,則停止,

    用實驗中丟硬幣的次數 K 作為元素占有的層數。顯然隨機變量 K 滿足參數為 p = 1/2 的幾何分布,

    K 的期望值 E[K] = 1/p = 2. 就是說,各個元素的層數,期望值是 2 層。

    ?

    ?

    跳表的高度。

    n 個元素的跳表,每個元素插入的時候都要做一次實驗,用來決定元素占據的層數 K,

    跳表的高度等于這?n 次實驗中產生的最大 K,待續。。。

    ?

    跳表的空間復雜度分析

    根據上面的分析,每個元素的期望高度為 2, 一個大小為 n 的跳表,其節點數目的

    期望值是 2n。

    ?

    跳表的刪除

    在各個層中找到包含 x 的節點,使用標準的 delete from list 方法刪除該節點。

    例子:刪除 71



    [cpp]?view plaincopy
  • #include?<stdio.h>??
  • #include?<stdlib.h>??
  • #include?<malloc.h>??
  • ????
  • typedef?int?key_t;??
  • typedef?int?value_t;??
  • typedef?struct?node_t??
  • {??
  • ????key_t?key;??
  • ????value_t?value;??
  • ????struct?node_t?*forward[];??
  • }?node_t;??
  • ????
  • typedef?struct?skiplist??
  • {??
  • ????int?level;??
  • ????int?length;??
  • ????node_t?*header;??
  • }?list_t;??
  • ????
  • #define?MAX_LEVEL???16??
  • #define?SKIPLIST_P??0.25??
  • ????
  • node_t*?slCreateNode(int?level,?key_t?key,?value_t?value)??
  • {??
  • ????node_t?*n?=?(node_t?*)malloc(sizeof(node_t)?+?level?*?sizeof(node_t*));??
  • ????if(n?==?NULL)?return?NULL;??
  • ????n->key?=?key;??
  • ????n->value?=?value;??
  • ????return?n;??
  • }??
  • ????
  • list_t*?slCreate(void)??
  • {??
  • ????list_t?*l?=?(list_t?*)malloc(sizeof(list_t));??
  • ????int?i?=?0;??
  • ????if(l?==?NULL)?return?NULL;??
  • ????
  • ????l->length?=?0;??
  • ????l->level?=?0;??
  • ????l->header?=?slCreateNode(MAX_LEVEL?-?1,?0,?0);??
  • ????for(i?=?0;?i?<?MAX_LEVEL;?i++)??
  • ????{??
  • ????????l->header->forward[i]?=?NULL;??
  • ????}??
  • ????return?l;??
  • }??
  • ????
  • int?randomLevel(void)??
  • {??
  • ????int?level?=?1;??
  • ????while?((rand()&0xFFFF)?<?(SKIPLIST_P?*?0xFFFF))??
  • ????????level?+=?1;??
  • ????return?(level<MAX_LEVEL)???level?:?MAX_LEVEL;??
  • }??
  • ????
  • value_t*?slSearch(list_t?*list,?key_t?key)??
  • {??
  • ????node_t?*p?=?list->header;??
  • ????int?i;??
  • ????
  • ????for(i?=?list->level?-?1;?i?>=?0;?i--)??
  • ????{??
  • ????????while(p->forward[i]?&&?(p->forward[i]->key?<=?key)){??
  • ????????????if(p->forward[i]->key?==?key){??
  • ????????????????return?&p->forward[i]->value;??
  • ????????????}??
  • ????????????p?=?p->forward[i];??
  • ????????}??
  • ????}??
  • ????return?NULL;??
  • }??
  • ????
  • int?slDelete(list_t?*list,?key_t?key)??
  • {??
  • ????node_t?*update[MAX_LEVEL];??
  • ????node_t?*p?=?list->header;??
  • ????node_t?*last?=?NULL;??
  • ????int?i?=?0;??
  • ????
  • ????for(i?=?list->level?-?1;?i?>=?0;?i--){??
  • ????????while((last?=?p->forward[i])?&&?(last->key?<?key)){??
  • ????????????p?=?last;??
  • ????????}??
  • ????????update[i]?=?p;??
  • ????}??
  • ????
  • ????if(last?&&?last->key?==?key){??
  • ????????for(i?=?0;?i?<?list->level;?i++){??
  • ????????????if(update[i]->forward[i]?==?last){??
  • ????????????????update[i]->forward[i]?=?last->forward[i];??
  • ????????????}??
  • ????????}??
  • ????????free(last);??
  • ????????for(i?=?list->level?-?1;?i?>=?0;?i--){??
  • ????????????if(list->header->forward[i]?==?NULL){??
  • ????????????????list->level--;??
  • ????????????}??
  • ????????}??
  • ????????list->length--;??
  • ????}else{??
  • ????????return?-1;??
  • ????}??
  • ????
  • ????return?0;??
  • }??
  • ????
  • int?slInsert(list_t?*list,?key_t?key,?value_t?value)??
  • {??
  • ????node_t?*update[MAX_LEVEL];??
  • ????node_t?*p,?*node?=?NULL;??
  • ????int?level,?i;??
  • ????
  • ????p?=?list->header;??
  • ????for(i?=?list->level?-?1;?i?>=?0;?i--){??
  • ????????while((node?=?p->forward[i])?&&?(node->key?<?key)){??
  • ????????????p?=?node;??
  • ????????}??
  • ????????update[i]?=?p;??
  • ????}??
  • ????if(node?&&?node->key?==?key){??
  • ????????node->value?=?value;??
  • ????????return?0;??
  • ????}??
  • ????
  • ????level?=?randomLevel();??
  • ????if?(level?>?list->level)??
  • ????{??
  • ????????for(i?=?list->level;?i?<?level;?i++){??
  • ????????????update[i]?=?list->header;??
  • ????????}??
  • ????????list->level?=?level;??
  • ????}??
  • ????
  • ????node?=?slCreateNode(level,?key,?value);??
  • ????for(i?=?0;?i?<?level;?i++){??
  • ????????node->forward[i]?=?update[i]->forward[i];??
  • ????????update[i]->forward[i]?=?node;??
  • ????}??
  • ????list->length++;??
  • ????return?0;??
  • }??
  • ????
  • int?main(int?argc,?char?**argv)??
  • {??
  • ????list_t?*list?=?slCreate();??
  • ????node_t?*p?=?NULL;??
  • ????value_t?*val?=?NULL;??
  • ????
  • ????//插入??
  • ????for(int?i?=?1;?i?<=?15;?i++){??
  • ????????slInsert(list,?i,?i*10);??
  • ????}??
  • ????
  • ????//刪除??
  • ????if(slDelete(list,?12)?==?-1){??
  • ????????printf("delete:not?found\n");??
  • ????}else{??
  • ????????printf("delete:delete?success\n");??
  • ????}??
  • ????
  • ????//查找??
  • ????val?=?slSearch(list,?1);??
  • ????if(val?==?NULL){??
  • ????????printf("search:not?found\n");??
  • ????}else{??
  • ????????printf("search:%d\n",?*val);??
  • ????}??
  • ????
  • ????//遍歷??
  • ????p?=?list->header->forward[0];??
  • ????for(int?i?=?0;?i?<?list->length;?i++){??
  • ????????printf("%d,%d\n",?p->key,?p->value);??
  • ????????p?=?p->forward[0];??
  • ????}??
  • ????
  • ????getchar();??
  • ????return?0;??
  • }??


  • http://www.cxphp.com/?p=234(Redis中c語言的實現)

    http://imtinx.iteye.com/blog/1291165

    http://kenby.iteye.com/blog/1187303

    http://bbs.bccn.net/thread-228556-1-1.html

    http://blog.csdn.net/xuqianghit/article/details/6948554(leveldb源碼)

    分享到:?

    總結

    以上是生活随笔為你收集整理的Skpi List跳表的全部內容,希望文章能夠幫你解決所遇到的問題。

    如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。