跳錶分析以及實現

來源:互聯網
上載者:User

題目:

實現鏈表的快速插入、查詢、刪除等操作

分析:

我們知道,如果只是通過簡單的單鏈表,我們對單鏈表的插入、刪除、查詢操作都是O(n)的,這裡需要用到一種特殊的資料結構——跳錶,能夠實現高速插入、刪除、尋找,平均時間複雜度能夠達到O(logn)(具體分析,有很多人寫了專門的文章,由於跳錶是基於機率的,所以時間複雜度不好分析)。

跳錶的核心思想,比如尋找,讓尋找儘可能的快,所以我們第一次嘗試查詢時,查詢跳躍步長儘可能大,如果失敗,我們再減小步長,直到最壞情況下,我們步長為1,這就和普通單鏈表查詢一樣了。


如上資料結構,我們的跳錶level最大是4層,假如我們要尋找元素6,我們首先從level 4(level從上往下遞減)開始,level 4指向NULL,所以我們減小level,到level 3,level 3指標直接指向元素4,繼續從元素4的level 3往後跳,這樣就跳到了元素6,正好6就是我們要尋找的元素。

從上面可以看出來,原來需要6次的尋找,現在只需要3次就行。我們利用了額外的空間換取了時間,但是注意,每個元素的level層數是由一個隨機函數產生的,所以跳錶是基於機率的,時間複雜度分析不好做,有誰能給個好的分析方法,還望給個連結。

代碼實現:

C語言的版本可以參考這個部落格http://yilee.info/skip-list.html,作者分析也做得非常好

C++版本可以參考:http://www.cnblogs.com/liuhao/archive/2012/07/26/2610218.html,但是我啟動並執行時候存在一些問題,我修改了一下,貼出來:

// ConsoleApplication1.cpp : Defines the entry point for the console application.//#include "stdafx.h"#include "skipList.h"#include <stdlib.h>#include <stdio.h>#include <time.h>#define SKIP_LIST_TEST_MAINskiplistNode *slCreateNode(int level, double score) {skiplistNode * sn = (skiplistNode *)malloc(sizeof(*sn) + level*sizeof(struct skiplistNode));sn->score = score;return sn;}skiplist *slCreate(void) {int j;skiplist *sl;sl = (skiplist *)malloc(sizeof(*sl));sl->level = 1;sl->length = 0;sl->header = slCreateNode(SKIPLIST_MAXLEVEL, 0);for(j = 0; j < SKIPLIST_MAXLEVEL; j++) {sl->header->level[j].forward = NULL;}sl->header->backward = NULL;sl->tail = NULL;return sl;}void slFreeNode(skiplistNode *sn) {free(sn);}void slFree(skiplist *sl) {skiplistNode *node = sl->header->level[0].forward, *next;free(sl->header);while(node) {next = node->level[0].forward;slFreeNode(node);node = next;}free(sl);}int slRandomLevel(void) {int level = 1;//while((rand()&0xFFFF) < (0.5 * 0xFFFF)) while(rand() % 2)//change the value to adjust the level numberlevel += 1;return (level < SKIPLIST_MAXLEVEL) ? level : SKIPLIST_MAXLEVEL;}skiplistNode *slInsert(skiplist *sl, double score) {skiplistNode *update[SKIPLIST_MAXLEVEL];skiplistNode *node;node = sl->header;int i, level;for ( i = sl->level-1; i >= 0; i--) {while(node->level[i].forward && node->level[i].forward->score < score) {node = node->level[i].forward;}update[i] = node;}level = slRandomLevel();if (level > sl->level) {for (i = sl->level; i< level ;i++) {update[i] = sl->header;}sl->level = level;}node = slCreateNode(level, score);for (i = 0; i < level; i++) {node->level[i].forward = update[i]->level[i].forward;update[i]->level[i].forward = node;}node->backward = (update[0] == sl->header? NULL : update[0]);if (node->level[0].forward)node->level[0].forward->backward = node;elsesl->tail = node;sl->length++;return node;}void slDeleteNode(skiplist *sl, skiplistNode *x, skiplistNode **update){int i;for (i = 0; i < sl->level; i++) {if (update[i]->level[i].forward == x) {update[i]->level[i].forward = x->level[i].forward;}}if (x->level[0].forward) {x->level[0].forward->backward = x->backward;} else {sl->tail = x->backward;}while (sl->level > 1 && sl->header->level[sl->level-1].forward == NULL) sl->level--;sl->length--;}int slDelete(skiplist *sl, double score) {skiplistNode *update[SKIPLIST_MAXLEVEL], *node;int i;node = sl->header;for(i = sl->level-1; i >= 0; i--) {while (node->level[i].forward && node->level[i].forward->score < score) {node = node->level[i].forward;}update[i] = node;}node = node->level[0].forward;if (node && score == node->score) {slDeleteNode(sl, node, update);slFreeNode(node);return 1;} else {return 0;}return 0;}int slSearch(skiplist *sl, double score) {skiplistNode *node;int i;node = sl->header;for (i = sl->level-1; i >= 0 ;i--) {while(node->level[i].forward && node->level[i].forward->score < score) {node = node->level[i].forward;}}node = node->level[0].forward;if (node && score == node->score) {printf("Found %d\n",(int)node->score);return 1;} else {printf("Not found %d\n", (int)score);return 0;}}void slPrint(skiplist *sl) {skiplistNode *node;int i;for (i = 0; i < SKIPLIST_MAXLEVEL; i++) {printf("LEVEL[%d]: ", i);node = sl->header->level[i].forward;while(node) {printf("%d -> ", (int)(node->score));node = node->level[i].forward;}printf("NULL\n");}}#ifdef SKIP_LIST_TEST_MAINint main() {srand((unsigned)time(0));int count = 20, i;printf("### Function Test ###\n");printf("=== Init Skip List ===\n");skiplist * sl = slCreate();for ( i = 0; i < count; i++) {slInsert(sl,i);}printf("=== Print Skip List ===\n");slPrint(sl);printf("=== Search Skip List ===\n");for (i = 0; i < count; i++) {int value = rand()%(count+10);slSearch(sl, value);}printf("=== Delete Skip List ===\n");for (i = 0; i < count+10; i+=2) {printf("Delete[%d]: %s\n", i, slDelete(sl, i)?"SUCCESS":"NOT FOUND");}slPrint(sl);slFree(sl);sl = NULL;system("pause");return 0;}#endif

總結:

skip list非常實用,在Redis等很多項目中都用到,相比紅/黑樹狀結構、平衡樹,實現更加簡單,而且效率也非常高。


修訂:

這個部落格寫的很好,而且分析時間和空間複雜度。http://www.cnblogs.com/flyfy1/archive/2011/02/24/1963347.html

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.