在线观看www成人影院-在线观看www日本免费网站-在线观看www视频-在线观看操-欧美18在线-欧美1级

0
  • 聊天消息
  • 系統(tǒng)消息
  • 評論與回復(fù)
登錄后你可以
  • 下載海量資料
  • 學(xué)習(xí)在線課程
  • 觀看技術(shù)視頻
  • 寫文章/發(fā)帖/加入社區(qū)
會員中心
創(chuàng)作中心

完善資料讓更多小伙伴認(rèn)識你,還能領(lǐng)取20積分哦,立即完善>

3天內(nèi)不再提示

跳躍表數(shù)據(jù)結(jié)構(gòu)與算法分析

OSC開源社區(qū) ? 來源:OSCHINA 社區(qū) ? 2023-01-31 13:35 ? 次閱讀

作者 | 京東云開發(fā)者-京東物流 紀(jì)卓志

目前市面上充斥著大量關(guān)于跳躍表結(jié)構(gòu)與 Redis 的源碼解析,但是經(jīng)過長期觀察后發(fā)現(xiàn)大都只是在停留在代碼的表面,而沒有系統(tǒng)性地介紹跳躍表的由來以及各種常量的由來。作為一種概率數(shù)據(jù)結(jié)構(gòu),理解各種常量的由來可以更好地進(jìn)行變化并應(yīng)用到高性能功能開發(fā)中。本文沒有重復(fù)地以對現(xiàn)有優(yōu)秀實(shí)現(xiàn)進(jìn)行代碼分析,而是通過對跳躍表進(jìn)行了系統(tǒng)性地介紹與形式化分析,并給出了在特定場景下的跳躍表擴(kuò)展方式,方便讀者更好地理解跳躍表數(shù)據(jù)結(jié)構(gòu)。

跳躍表 [1,2,3] 是一種用于在大多數(shù)應(yīng)用程序中取代平衡樹的概率數(shù)據(jù)結(jié)構(gòu)。跳躍表擁有與平衡樹相同的期望時間上界,并且更簡單、更快、是用更少的空間。在查找與列表的線性操作上,比平衡樹更快,并且更簡單。

概率平衡也可以被用在基于樹的數(shù)據(jù)結(jié)構(gòu) [4] 上,例如樹堆(Treap)。與平衡二叉樹相同,跳躍表也實(shí)現(xiàn)了以下兩種操作

通過搜索引用 [5],可以保證從任意元素開始,搜索到在列表中間隔為 k 的元素的任意期望時間是 O (logk)

實(shí)現(xiàn)線性表的常規(guī)操作(例如_將元素插入到列表第 k 個元素后面_)

這幾種操作在平衡樹中也可以實(shí)現(xiàn),但是在跳躍表中實(shí)現(xiàn)起來更簡單而且非常的快,并且通常情況下很難在平衡樹中直接實(shí)現(xiàn)(樹的線索化可以實(shí)現(xiàn)與鏈表相同的效果,但是這使得實(shí)現(xiàn)變得更加復(fù)雜 [6])

預(yù)覽

最簡單的支持查找的數(shù)據(jù)結(jié)構(gòu)可能就是鏈表。Figure.1 是一個簡單的鏈表。在鏈表中執(zhí)行一次查找的時間正比于必須考查的節(jié)點(diǎn)個數(shù),這個個數(shù)最多是 N。

ec4d8c8a-a11e-11ed-bfe3-dac502259ad0.png

Figure.1 Linked List

Figure.2 表示一個鏈表,在該鏈表中,每個一個節(jié)點(diǎn)就有一個附加的指針指向它在表中的前兩個位置上的節(jié)點(diǎn)。正因?yàn)檫@個前向指針,在最壞情況下最多考查?N/2?+1 個節(jié)點(diǎn)。

ec63137a-a11e-11ed-bfe3-dac502259ad0.png

Figure.2 Linked List with fingers to the 2nd forward elements

Figure.3 將這種想法擴(kuò)展,每個序數(shù)是 4 的倍數(shù)的節(jié)點(diǎn)都有一個指針指向下一個序數(shù)為 4 的倍數(shù)的節(jié)點(diǎn)。只有?N/4?+2 個節(jié)點(diǎn)被考查。

ec74bc9c-a11e-11ed-bfe3-dac502259ad0.png

Figure.3 Linked List with fingers to the 4th forward elements

這種跳躍幅度的一般情況如 Figure.4 所示。每個 2i 節(jié)點(diǎn)就有一個指針指向下一個 2i 節(jié)點(diǎn),前向指針的間隔最大為 N/2。可以證明總的指針最大不會超過 2N(見空間復(fù)雜度分析),但現(xiàn)在在一次查找中最多考查?logN?個節(jié)點(diǎn)。這意味著一次查找中總的時間消耗為 O (logN),也就是說在這種數(shù)據(jù)結(jié)構(gòu)中的查找基本等同于二分查找(binary search)。

ec876fa4-a11e-11ed-bfe3-dac502259ad0.png

Figure.4 Linked List with fingers to the 2ith forward elements

在這種數(shù)據(jù)結(jié)構(gòu)中,每個元素都由一個節(jié)點(diǎn)表示。每個節(jié)點(diǎn)都有一個高度(height)或級別(level),表示節(jié)點(diǎn)所擁有的前向指針數(shù)量。每個節(jié)點(diǎn)的第 i 個前向指針指向下一個級別為 i 或更高的節(jié)點(diǎn)。

在前面描述的數(shù)據(jù)結(jié)構(gòu)中,每個節(jié)點(diǎn)的級別都是與元素數(shù)量有關(guān)的,當(dāng)插入或刪除時需要對數(shù)據(jù)結(jié)構(gòu)進(jìn)行調(diào)整來滿足這樣的約束,這是很呆板且低效的。為此,可以_將每個 2i 節(jié)點(diǎn)就有一個指針指向下一個 2i 節(jié)點(diǎn)_的限制去掉,當(dāng)新元素插入時為每個新節(jié)點(diǎn)分配一個隨機(jī)的級別而不用考慮數(shù)據(jù)結(jié)構(gòu)的元素數(shù)量。

ec9f070e-a11e-11ed-bfe3-dac502259ad0.png

ecb9fb2c-a11e-11ed-bfe3-dac502259ad0.png

Figure.5 Skip List

數(shù)據(jù)結(jié)構(gòu)

到此為止,已經(jīng)得到了所有讓鏈表支持快速查找的充要條件,而這種形式的數(shù)據(jù)結(jié)構(gòu)就是跳躍表。接下來將會使用更正規(guī)的方式來定義跳躍表

所有元素在跳躍表中都是由一個節(jié)點(diǎn)表示。

每個節(jié)點(diǎn)都有一個高度或級別,有時候也可以稱之為階(step),節(jié)點(diǎn)的級別是一個與元素總數(shù)無關(guān)的隨機(jī)數(shù)。規(guī)定 NULL 的級別是∞。

每個級別為 k 的節(jié)點(diǎn)都有 k 個前向指針,且第 i 個前向指針指向下一個級別為 i 或更高的節(jié)點(diǎn)。

每個節(jié)點(diǎn)的級別都不會超過一個明確的常量 MaxLevel。整個跳躍表的級別是所有節(jié)點(diǎn)的級別的最高值。如果跳躍表是空的,那么跳躍表的級別就是 1。

存在一個頭節(jié)點(diǎn) head,它的級別是 MaxLevel,所有高于跳躍表的級別的前向指針都指向 NULL。

稍后將會提到,節(jié)點(diǎn)的查找過程是在頭節(jié)點(diǎn)從最高級別的指針開始,沿著這個級別一直走,直到找到大于正在尋找的節(jié)點(diǎn)的下一個節(jié)點(diǎn)(或者是 NULL),在此過程中除了頭節(jié)點(diǎn)外并沒有使用到每個節(jié)點(diǎn)的級別,因此每個節(jié)點(diǎn)無需存儲節(jié)點(diǎn)的級別。

在跳躍表中,級別為 1 的前向指針與原始的鏈表結(jié)構(gòu)中 next 指針的作用完全相同,因此跳躍表支持所有鏈表支持的算法

對應(yīng)到高級語言中的結(jié)構(gòu)定義如下所示(后續(xù)所有代碼示例都將使用 C 語言描述)

#define SKIP_LIST_KEY_TYPE     int
#define SKIP_LIST_VALUE_TYPE   int
#define SKIP_LIST_MAX_LEVEL    32
#define SKIP_LIST_P            0.5

struct Node {
  SKIP_LIST_KEY_TYPE    key;
  SKIP_LIST_VALUE_TYPE  value;
  struct Node          *forwards[]; // flexible array member
};

struct SkipList {
  struct Node *head;
  int          level;
};

struct Node *CreateNode(int level) {
  struct Node *node;
  assert(level > 0);
  node = malloc(sizeof(struct Node) + sizeof(struct Node *) * level);
  return node;
}

struct SkipList *CreateSkipList() {
  struct SkipList *list;
  struct Node     *head;
  int              i;

  list = malloc(sizeof(struct SkipList));
  head = CreateNode(SKIP_LIST_MAX_LEVEL);
  for (i = 0; i < SKIP_LIST_MAX_LEVEL; i++) {
    head->forwards[i] = NULL;
  }
  list->head = head;
  list->level = 1;

  return list;
}

從前面的預(yù)覽章節(jié)中,不難看出 MaxLevel 的選值影響著跳躍表的查詢性能,關(guān)于 MaxLevel 的選值將會在后續(xù)章節(jié)中進(jìn)行介紹。在此先將 MaxLevel 定義為 32,這對于 232 個元素的跳躍表是足夠的。延續(xù)預(yù)覽章節(jié)中的描述,跳躍表的概率被定義為 0.5,關(guān)于這個值的選取問題將會在后續(xù)章節(jié)中進(jìn)行詳細(xì)介紹。

算法

搜索

在跳躍表中進(jìn)行搜索的過程,是通過 Z 字形遍歷所有沒有超過要尋找的目標(biāo)元素的前向指針來完成的。在當(dāng)前級別沒有可以移動的前向指針時,將會移動到下一級別進(jìn)行搜索。直到在級別為 1 的時候且沒有可以移動的前向指針時停止搜索,此時直接指向的節(jié)點(diǎn)(級別為 1 的前向指針)就是包含目標(biāo)元素的節(jié)點(diǎn)(如果目標(biāo)元素在列表中的話)。在 Figure.6 中展示了在跳躍表中搜索元素 17 的過程。
ecce1972-a11e-11ed-bfe3-dac502259ad0.png

Figure.6 A search path to find element 17 in Skip List 整個過程的示例代碼如下所示,因?yàn)楦呒壵Z言中的數(shù)組下標(biāo)從 0 開始,因此 forwards [0] 表示節(jié)點(diǎn)的級別為 1 的前向指針,依此類推

struct Node *SkipListSearch(struct SkipList *list, SKIP_LIST_KEY_TYPE target) {
  struct Node *current;
  int          i;

  current = list->head;
  for (i = list->level - 1; i >= 0; i--) {
    while (current->forwards[i] && current->forwards[i]->key < target) {
      current = current->forwards[i];
    }
  }

  current = current->forwards[0];
  if (current->key == target) {
    return current;
  } else {
    return NULL;
  }
}

插入和刪除

在插入和刪除節(jié)點(diǎn)的過程中,需要執(zhí)行和搜索相同的邏輯。在搜索的基礎(chǔ)上,需要維護(hù)一個名為 update 的向量,它維護(hù)的是搜索過程中跳躍表每個級別上遍歷到的最右側(cè)的值,表示插入或刪除的節(jié)點(diǎn)的左側(cè)直接直接指向它的節(jié)點(diǎn),用于在插入或刪除后調(diào)整節(jié)點(diǎn)所在所有級別的前向指針(與樸素的鏈表節(jié)點(diǎn)插入或刪除的過程相同)。 當(dāng)新插入節(jié)點(diǎn)的級別超過當(dāng)前跳躍表的級別時,需要增加跳躍表的級別并將 update 向量中對應(yīng)級別的節(jié)點(diǎn)修改為 head 節(jié)點(diǎn)。 Figure.7 和 Figure.8 展示了在跳躍表中插入元素 16 的過程。首先,在 Figure.7 中執(zhí)行與搜索相同的查詢過程,在每個級別遍歷到的最后一個元素在對應(yīng)層級的前向指針被標(biāo)記為灰色,表示稍后將會對齊進(jìn)行調(diào)整。接下來在 Figure.8 中,在元素為 13 的節(jié)點(diǎn)后插入元素 16,元素 16 對應(yīng)的節(jié)點(diǎn)的級別是 5,這比跳躍表當(dāng)前級別要高,因此需要增加跳躍表的級別到 5,并將 head 節(jié)點(diǎn)對應(yīng)級別的前向指針標(biāo)記為灰色。Figure.8 中所有虛線部分都表示調(diào)整后的效果。 ece08ec2-a11e-11ed-bfe3-dac502259ad0.png

Figure.7 Search path for inserting element 16

ecfd688a-a11e-11ed-bfe3-dac502259ad0.png

Figure.8 Insert element 16 and adjust forward pointers

struct Node *SkipListInsert(struct SkipList *list, SKIP_LIST_KEY_TYPE key, SKIP_LIST_VALUE_TYPE value) {
  struct Node *update[SKIP_LIST_MAX_LEVEL];
  struct Node *current;
  int          i;
  int          level;

  current = list->head;
  for (i = list->level - 1; i >= 0; i--) {
    while (current->forwards[i] && current->forwards[i]->key < target) {
      current = current->forwards[i];
    }
    update[i] = current;
  }

  current = current->forwards[0];
  if (current->key == target) {
    current->value = value;
    return current;
  }

  level = SkipListRandomLevel();
  if (level > list->level) {
    for (i = list->level; i < level; i++) {
      update[i] = list->header;
    }
  }

  current = CreateNode(level);
  current->key = key;
  current->value = value;

  for (i = 0; i < level; i++) {
    current->forwards[i] = update[i]->forwards[i];
    update[i]->forwards[i] = current;
  }

  return current;
}

在刪除節(jié)點(diǎn)后,如果刪除的節(jié)點(diǎn)是跳躍表中級別最大的節(jié)點(diǎn),那么需要降低跳躍表的級別。 Figure.9 和 Figure.10 展示了在跳躍表中刪除元素 19 的過程。首先,在 Figure.9 中執(zhí)行與搜索相同的查詢過程,在每個級別遍歷到的最后一個元素在對應(yīng)層級的前向指針被標(biāo)記為灰色,表示稍后將會對齊進(jìn)行調(diào)整。接下來在 Figure.10 中,首先通過調(diào)整前向指針將元素 19 對應(yīng)的節(jié)點(diǎn)從跳躍表中卸載,因?yàn)樵?19 對應(yīng)的節(jié)點(diǎn)是級別最高的節(jié)點(diǎn),因此將其從跳躍表中移除后需要調(diào)整跳躍表的級別。Figure.10 中所有虛線部分都表示調(diào)整后的效果。 ed1c9b9c-a11e-11ed-bfe3-dac502259ad0.png Figure.9 Search path for deleting element 19 ed374d98-a11e-11ed-bfe3-dac502259ad0.png Figure.10 Delete element 19 and adjust forward pointers
struct Node *SkipListDelete(struct SkipList *list, SKIP_LIST_KEY_TYPE key) {
  struct Node *update[SKIP_LIST_MAX_LEVEL];
  struct Node *current;
  int          i;

  current = list->head;
  for (i = list->level - 1; i >= 0; i--) {
    while (current->forwards[i] && current->forwards[i]->key < key) {
      current = current->forwards[i];
    }
    update[i] = current;
  }

  current = current->forwards[0];
  if (current && current->key == key) {
    for (i = 0; i < list->level; i++) {
      if (update[i]->forwards[i] == current) {
        update[i]->forwards[i] = current->forwards[i];
      } else {
        break;
      }
    }

    while (list->level > 1 && list->head->forwards[list->level - 1] == NULL) {
      list->level--;
    }
  }

  return current;
}

生成隨機(jī)級別

ed487cd0-a11e-11ed-bfe3-dac502259ad0.png

int SkipListRandomLevel() {
  int level;
  level = 1;
  while (random() < RAND_MAX * SKIP_LIST_P && level <= SKIP_LIST_MAX_LEVEL) {
    level++;
  }
  return level;
}

以下表格為按上面算法執(zhí)行 232 次后,所生成的隨機(jī)級別的分布情況。

1 2 3 4 5 6 7 8
2147540777 1073690199 536842769 268443025 134218607 67116853 33563644 16774262
9 10 11 12 13 14 15 16
8387857 4193114 2098160 1049903 523316 262056 131455 65943
17 18 19 20 21 22 23 24
32611 16396 8227 4053 2046 1036 492 249
25 26 27 28 29 30 31 32
121 55 34 16 7 9 2 1

MaxLevel 的選擇

在 Figure.4 中曾給出過對于 10 個元素的跳躍表最理想的分布情況,其中 5 個節(jié)點(diǎn)的級別是 1,3 個節(jié)點(diǎn)的級別是 2,1 個節(jié)點(diǎn)的級別是 3,1 個節(jié)點(diǎn)的級別是 4。 這引申出一個問題:既然相同元素數(shù)量下,跳躍表的級別不同會有不同的性能,那么跳躍表的級別為多少才合適? ed627d92-a11e-11ed-bfe3-dac502259ad0.png

分析

空間復(fù)雜度分析

前面提到過,分?jǐn)?shù) p 代表節(jié)點(diǎn)同時帶有第 i 層前向指針和第 i+1 層前向指針的概率,而每個節(jié)點(diǎn)的級別最少是 1,因此級別為 i 的前向指針數(shù)為 npi?1。定義 S (n) 表示所有前向指針的總量,由等比數(shù)列求和公式可得 ed78b62a-a11e-11ed-bfe3-dac502259ad0.png 對 S (n) 求極限,有 ed91725a-a11e-11ed-bfe3-dac502259ad0.png 易證,這是一個關(guān)于 p 的單調(diào)遞增函數(shù),因此 p 的值越大,跳躍表中前向指針的總數(shù)越多。因?yàn)?1?p 是已知的常數(shù),所以說跳躍表的空間復(fù)雜度是 O (n)。

時間復(fù)雜度分析

非形式化分析

eda0f95a-a11e-11ed-bfe3-dac502259ad0.png

形式化分析

edba9efa-a11e-11ed-bfe3-dac502259ad0.png

延續(xù)_分?jǐn)?shù) p 代表節(jié)點(diǎn)同時帶有第 i 層前向指針和第 i+1 層前向指針的概率_的定義,考慮反方向分析搜索路徑。 搜索的路徑總是小于必須執(zhí)行的比較的次數(shù)的。首先需要考查從級別 1(在搜索到元素前遍歷的最后一個節(jié)點(diǎn))爬升到級別 L (n) 所需要反向跟蹤的指針數(shù)量。雖然在搜索時可以確定每個節(jié)點(diǎn)的級別都是已知且確定的,在這里仍認(rèn)為只有當(dāng)整個搜索路徑都被反向追蹤后才能被確定,并且在爬升到級別 L (n) 之前都不會接觸到 head 節(jié)點(diǎn)。 在爬升過程中任何特定的點(diǎn),都認(rèn)為是在元素 x 的第 i 個前向指針,并且不知道元素 x 左側(cè)所有元素的級別或元素 x 的級別,但是可以知道元素 x 的級別至少是 i。元素 x 的級別大于 i 的概率是 p,可以通過考慮視認(rèn)為這個反向爬升的過程是一系列由成功的爬升到更高級別或失敗地向左移動的隨機(jī)獨(dú)立實(shí)驗(yàn)。 在爬升到級別 L (n) 過程中,向左移動的次數(shù)等于在連續(xù)隨機(jī)試驗(yàn)中第 L (n)?1 次成功前的失敗的次數(shù),這符合負(fù)二項分布。期望的向上移動次數(shù)一定是 L (n)?1。因此可以得到無限列表中爬升到 L (n) 的代價 C C=prob (L (n)?1)+NB (L (n)?1,p) 列表長度無限大是一個悲觀的假設(shè)。當(dāng)反向爬升的過程中接觸到 head 節(jié)點(diǎn)時,可以直接向上爬升而不需要任何向左移動。因此可以得到 n 個元素列表中爬升到 L (n) 的代價 C (n) C(n)≤probC=prob(L(n)?1)+NB(L(n)?1,p) 因此 n 個元素列表中爬升到 L (n) 的代價 C (n) 的數(shù)學(xué)期望和方差為 edd028d8-a11e-11ed-bfe3-dac502259ad0.png

因?yàn)?1/p 是已知常數(shù),因此跳躍表的搜索、插入和刪除的時間復(fù)雜度都是 O (logn)。

P 的選擇


edee4af2-a11e-11ed-bfe3-dac502259ad0.png
ee0dcb0c-a11e-11ed-bfe3-dac502259ad0.jpg

Figure.11 Normalized search times

ee1fa14c-a11e-11ed-bfe3-dac502259ad0.png

擴(kuò)展

快速隨機(jī)訪問

ee335cbe-a11e-11ed-bfe3-dac502259ad0.png

#define SKIP_LIST_KEY_TYPE     int
#define SKIP_LIST_VALUE_TYPE   int
#define SKIP_LIST_MAX_LEVEL    32
#define SKIP_LIST_P            0.5

struct Node; // forward definition

struct Forward {
  struct Node *forward;
  int          span;
}

struct Node {
  SKIP_LIST_KEY_TYPE    key;
  SKIP_LIST_VALUE_TYPE  value;
  struct Forward        forwards[]; // flexible array member
};

struct SkipList {
  struct Node *head;
  int          level;
  int          length;
};

struct Node *CreateNode(int level) {
  struct Node *node;
  assert(level > 0);
  node = malloc(sizeof(struct Node) + sizeof(struct Forward) * level);
  return node;
}

struct SkipList *CreateSkipList() {
  struct SkipList *list;
  struct Node     *head;
  int              i;

  list = malloc(sizeof(struct SkipList));
  head = CreateNode(SKIP_LIST_MAX_LEVEL);
  for (i = 0; i < SKIP_LIST_MAX_LEVEL; i++) {
    head->forwards[i].forward = NULL;
    head->forwards[i].span = 0;
  }

  list->head = head;
  list->level = 1;

  return list;
}

接下來需要修改插入和刪除操作,來保證在跳躍表修改后跨度的數(shù)據(jù)完整性。

需要注意的是,在插入過程中需要使用 indices 記錄在每個層級遍歷到的最后一個元素的位置,這樣通過做簡單的減法操作就可以知道每個層級遍歷到的最后一個元素到新插入節(jié)點(diǎn)的跨度。

struct Node *SkipListInsert(struct SkipList *list, SKIP_LIST_KEY_TYPE key, SKIP_LIST_VALUE_TYPE value) {
  struct Node *update[SKIP_LIST_MAX_LEVEL];
  struct Node *current;
  int          indices[SKIP_LIST_MAX_LEVEL];
  int          i;
  int          level;

  current = list->head;
  for (i = list->level - 1; i >= 0; i--) {
    if (i == list->level - 1) {
      indices[i] = 0;
    } else {
      indices[i] = indices[i + 1];
    }
    
    while (current->forwards[i].forward && current->forwards[i].forward->key < target) {
      indices[i] += current->forwards[i].span;
      current = current->forwards[i].forward;
    }
    update[i] = current;
  }

  current = current->forwards[0].forward;
  if (current->key == target) {
    current->value = value;
    return current;
  }

  level = SkipListRandomLevel();
  if (level > list->level) {
    for (i = list->level; i < level; i++) {
      indices[i] = 0;
      update[i] = list->header;
      update[i]->forwards[i].span = list->length;
    }
  }

  current = CreateNode(level);
  current->key = key;
  current->value = value;

  for (i = 0; i < level; i++) {
    current->forwards[i].forward = update[i]->forwards[i].forward;
    update[i]->forwards[i].forward = current;
    current->forwards[i].span = update[i]->forwards[i].span - (indices[0] - indices[i]);
    update[i]->forwards[i].span = (indices[0] - indices[i]) + 1;
  }

  list.length++;

  return current;
}

struct Node *SkipListDelete(struct SkipList *list, SKIP_LIST_KEY_TYPE key) {
  struct Node *update[SKIP_LIST_MAX_LEVEL];
  struct Node *current;
  int          i;

  current = list->head;
  for (i = list->level - 1; i >= 0; i--) {
    while (current->forwards[i].forward && current->forwards[i].forward->key < key) {
      current = current->forwards[i].forward;
    }
    update[i] = current;
  }

  current = current->forwards[0].forward;
  if (current && current->key == key) {
    for (i = 0; i < list->level; i++) {
      if (update[i]->forwards[i].forward == current) {
        update[i]->forwards[i].forward = current->forwards[i];
        update[i]->forwards[i].span += current->forwards[i].span - 1;
      } else {
        break;
      }
    }

    while (list->level > 1 && list->head->forwards[list->level - 1] == NULL) {
      list->level--;
    }
  }

  return current;
}

當(dāng)實(shí)現(xiàn)了快速隨機(jī)訪問之后,通過簡單的指針操作即可實(shí)現(xiàn)區(qū)間查詢功能。

審核編輯:湯梓紅

聲明:本文內(nèi)容及配圖由入駐作者撰寫或者入駐合作網(wǎng)站授權(quán)轉(zhuǎn)載。文章觀點(diǎn)僅代表作者本人,不代表電子發(fā)燒友網(wǎng)立場。文章及其配圖僅供工程師學(xué)習(xí)之用,如有內(nèi)容侵權(quán)或者其他違規(guī)問題,請聯(lián)系本站處理。 舉報投訴
  • 算法
    +關(guān)注

    關(guān)注

    23

    文章

    4631

    瀏覽量

    93422
  • 源碼
    +關(guān)注

    關(guān)注

    8

    文章

    653

    瀏覽量

    29508
  • 數(shù)據(jù)結(jié)構(gòu)

    關(guān)注

    3

    文章

    573

    瀏覽量

    40237
  • 鏈表
    +關(guān)注

    關(guān)注

    0

    文章

    80

    瀏覽量

    10610
  • Redis
    +關(guān)注

    關(guān)注

    0

    文章

    379

    瀏覽量

    10966

原文標(biāo)題:跳躍表數(shù)據(jù)結(jié)構(gòu)與算法分析

文章出處:【微信號:OSC開源社區(qū),微信公眾號:OSC開源社區(qū)】歡迎添加關(guān)注!文章轉(zhuǎn)載請注明出處。

收藏 人收藏

    評論

    相關(guān)推薦

    數(shù)據(jù)結(jié)構(gòu)算法分析(Java版)(pdf)

    數(shù)據(jù)結(jié)構(gòu)算法分析(Java版)(pdf)http://www.ibeifeng.com/read.php?tid=4812&u=73481【中文】Java數(shù)據(jù)結(jié)構(gòu)
    發(fā)表于 12-20 21:22

    數(shù)據(jù)結(jié)構(gòu)概述及線性

    第一講 數(shù)據(jù)結(jié)構(gòu)概述及線性 1 數(shù)據(jù)結(jié)構(gòu)概述1.1 概述    60年代初期,還沒有獨(dú)立的“數(shù)據(jù)結(jié)構(gòu)”課程,有關(guān)內(nèi)容散見于操作系統(tǒng)、編譯
    發(fā)表于 12-05 21:20

    數(shù)據(jù)結(jié)構(gòu)算法分析

    數(shù)據(jù)結(jié)構(gòu)算法分析
    發(fā)表于 06-05 10:46

    數(shù)據(jù)結(jié)構(gòu)算法分析:C語音第二版

    數(shù)據(jù)結(jié)構(gòu)算法分析:C語音第二版,經(jīng)典資料與你分析
    發(fā)表于 12-10 10:57

    C#數(shù)據(jù)結(jié)構(gòu)算法分析_ 魏寶剛

    數(shù)據(jù)結(jié)構(gòu)算法分析》描述了各種類型的數(shù)據(jù)結(jié)構(gòu),包括線性、樹、堆、圖,以及查找、排序等算法。自
    發(fā)表于 12-15 16:46 ?0次下載
    C#<b class='flag-5'>數(shù)據(jù)結(jié)構(gòu)</b>和<b class='flag-5'>算法</b><b class='flag-5'>分析</b>_ 魏寶剛

    數(shù)據(jù)結(jié)構(gòu)算法分析(C語言版)

    電子發(fā)燒友網(wǎng)站提供《數(shù)據(jù)結(jié)構(gòu)算法分析(C語言版).txt》資料免費(fèi)下載
    發(fā)表于 11-28 11:05 ?0次下載

    數(shù)據(jù)結(jié)構(gòu)算法分析C++描述(第3版)

    電子發(fā)燒友網(wǎng)站提供《數(shù)據(jù)結(jié)構(gòu)算法分析C++描述(第3版).txt》資料免費(fèi)下載
    發(fā)表于 07-23 14:15 ?0次下載

    數(shù)據(jù)結(jié)構(gòu)算法習(xí)題

    數(shù)據(jù)結(jié)構(gòu)算法習(xí)題,ACM專用,刷題初期按照這個地方刷很好
    發(fā)表于 03-03 18:25 ?0次下載

    數(shù)據(jù)結(jié)構(gòu)算法

    全國C語言考試公共基礎(chǔ)知識點(diǎn)——數(shù)據(jù)結(jié)構(gòu)算法,該資料包含了有關(guān)數(shù)據(jù)結(jié)構(gòu)算法的全部知識點(diǎn)。
    發(fā)表于 03-30 14:27 ?0次下載

    數(shù)據(jù)結(jié)構(gòu)算法分析

    一部淺顯易懂的介紹數(shù)據(jù)結(jié)構(gòu)算法的書籍。
    發(fā)表于 07-14 17:12 ?0次下載

    算法數(shù)據(jù)結(jié)構(gòu)——哈希

    周立功教授數(shù)年之心血之作《程序設(shè)計與數(shù)據(jù)結(jié)構(gòu)》以及《面向第三章為算法數(shù)據(jù)結(jié)構(gòu),本文為3.5 哈希
    的頭像 發(fā)表于 09-25 11:37 ?5607次閱讀
    <b class='flag-5'>算法</b>與<b class='flag-5'>數(shù)據(jù)結(jié)構(gòu)</b>——哈希<b class='flag-5'>表</b>

    什么是數(shù)據(jù)結(jié)構(gòu)?為什么要學(xué)習(xí)數(shù)據(jù)結(jié)構(gòu)數(shù)據(jù)結(jié)構(gòu)的應(yīng)用實(shí)例分析

    本文檔的主要內(nèi)容詳細(xì)介紹的是什么是數(shù)據(jù)結(jié)構(gòu)?為什么要學(xué)習(xí)數(shù)據(jù)結(jié)構(gòu)數(shù)據(jù)結(jié)構(gòu)的應(yīng)用實(shí)例分析包括了:數(shù)據(jù)結(jié)構(gòu)在串口通信當(dāng)中的應(yīng)用,
    發(fā)表于 09-26 15:45 ?14次下載
    什么是<b class='flag-5'>數(shù)據(jù)結(jié)構(gòu)</b>?為什么要學(xué)習(xí)<b class='flag-5'>數(shù)據(jù)結(jié)構(gòu)</b>?<b class='flag-5'>數(shù)據(jù)結(jié)構(gòu)</b>的應(yīng)用實(shí)例<b class='flag-5'>分析</b>

    大牛分享平時如何學(xué)習(xí)數(shù)據(jù)結(jié)構(gòu)算法

    數(shù)據(jù)結(jié)構(gòu)算法的地位對于一個程序員來說不言而喻。今天這篇文章不是來勸你們學(xué)習(xí)數(shù)據(jù)結(jié)構(gòu)算法的,也不是來和你們說數(shù)據(jù)結(jié)構(gòu)
    的頭像 發(fā)表于 11-02 11:25 ?3027次閱讀

    數(shù)據(jù)結(jié)構(gòu)算法分析—C語言描述

    數(shù)據(jù)結(jié)構(gòu)算法分析:C語言描述》曾被評為20世紀(jì)頂尖的30部計算機(jī)著作之一,作者在數(shù)據(jù)結(jié)構(gòu)算法分析
    發(fā)表于 10-14 08:00 ?17次下載
    <b class='flag-5'>數(shù)據(jù)結(jié)構(gòu)</b>與<b class='flag-5'>算法</b><b class='flag-5'>分析</b>—C語言描述

    數(shù)據(jù)結(jié)構(gòu)算法分析——Java語言描述

    數(shù)據(jù)結(jié)構(gòu)算法分析——Java語言描述說明。
    發(fā)表于 05-31 14:25 ?22次下載
    主站蜘蛛池模板: 性满足久久久久久久久 | 毛片黄| 天天爱综合 | 日韩免费在线视频 | 亚洲精品国产美女在线观看 | 日本一区二区不卡视频 | 91在线国内在线播放大神 | 韩漫免费网站无遮挡羞羞漫画 | 国产一级做a爰片久久毛片 国产一级做a爰片久久毛片男 | 夜夜爱夜夜操 | 欧美日韩精品一区二区在线线 | 久久综合九色综合欧洲色 | 在线观看视频一区 | 在线色国产 | 婷婷爱爱 | 日韩在线视频一区二区三区 | 色综合天天综久久久噜噜噜久久〔 | 乱说欲小说又粗又长 | 成人毛片一区二区三区 | 亚洲va老文色欧美黄大片人人 | 6080伦理久久精品亚洲 | 亚洲欧美日韩国产一区二区三区精品 | 四虎永久影院 | 免费人成黄页在线观看日本 | 久久久99精品免费观看精品 | 婷婷视频网 | 天天射网站| 美女扒开尿口给男的桶个爽 | 无遮挡很爽很污很黄在线网站 | 国产乱辈通伦影片在线播放 | 在线视频一区二区三区四区 | 加勒比综合网 | 91大神亚洲影视在线 | 狠狠色丁香婷婷综合橹不卡 | 夜夜综合网 | 国产午夜视频在线观看网站 | 久久夜夜肉肉热热日日 | 夜恋秀场欧美成人影院 | 天天艹夜夜艹 | 性色aⅴ闺蜜一区二区三区 性色成人网 | 国产主播精品在线 |