最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

c++如何實(shí)現(xiàn)跳表(skiplist)

 更新時(shí)間:2020年08月12日 14:45:58   作者:evenleo  
這篇文章主要介紹了c++如何實(shí)現(xiàn)跳表,幫助大家更好的理解和學(xué)習(xí),感興趣的朋友可以了解下

引言

二分查找底層依賴的是數(shù)組隨機(jī)訪問(wèn)的特性,所以只能用數(shù)組來(lái)實(shí)現(xiàn)。如果數(shù)據(jù)存儲(chǔ)在鏈表中,就真的沒法用二分查找算法了嗎?實(shí)際上,只需要對(duì)鏈表稍加改造,就可以支持類似“二分”的查找算法。改造之后的數(shù)據(jù)結(jié)構(gòu)叫作跳表。

定義

跳表是一個(gè)隨機(jī)化的數(shù)據(jù)結(jié)構(gòu)。它允許快速查詢一個(gè)有序連續(xù)元素的數(shù)據(jù)鏈表。跳躍列表的平均查找和插入時(shí)間復(fù)雜度都是O(log n),優(yōu)于普通隊(duì)列的O(n)。性能上和紅黑樹,AVL樹不相上下,但跳表的原理非常簡(jiǎn)單,目前Redis和LevelDB中都有用到。
跳表是一種可以替代平衡樹的數(shù)據(jù)結(jié)構(gòu)。跳表追求的是概率性平衡,而不是嚴(yán)格平衡。因此,跟平衡二叉樹相比,跳表的插入和刪除操作要簡(jiǎn)單得多,執(zhí)行也更快。

C++簡(jiǎn)單實(shí)現(xiàn)

下面實(shí)現(xiàn)過(guò)程主要是簡(jiǎn)單實(shí)現(xiàn)跳表的過(guò)程,不是多線程安全的,LevelDB實(shí)現(xiàn)的跳表支持多線程安全,用了std::atomic原子操作,本文主要是為了理解跳表的原理,所以采用最簡(jiǎn)單的實(shí)現(xiàn)。

#ifndef SKIPLIST_H
#define SKIPLIST_H

#include <ctime>
#include <initializer_list>
#include <iostream>
#include <random>

template <typename Key>
class Skiplist {
public:
 struct Node {
 Node(Key k) : key(k) {}
 Key key;
 Node* next[1]; // C語(yǔ)言中的柔性數(shù)組技巧
 };

private:
 int maxLevel;
 Node* head;

 enum { kMaxLevel = 12 };

public:
 Skiplist() : maxLevel(1)
 {
 head = newNode(0, kMaxLevel);
 }

 Skiplist(std::initializer_list<Key> init) : Skiplist()
 {
 for (const Key& k : init)
 {
  insert(k);
 }
 }

 ~Skiplist()
 {
 Node* pNode = head;
 Node* delNode;
 while (nullptr != pNode)
 {
  delNode = pNode;
  pNode = pNode->next[0];
  free(delNode); // 對(duì)應(yīng)malloc
 }
 }

 // 禁止拷貝構(gòu)造和賦值
 Skiplist(const Skiplist&) = delete;
 Skiplist& operator=(const Skiplist&) = delete;
 Skiplist& operator=(Skiplist&&) = delete;

private:
 Node* newNode(const Key& key, int level)
 {
 /*
 * 開辟sizeof(Node) + sizeof(Node*) * (level - 1)大小的空間
 * sizeof(Node*) * (level - 1)大小的空間是給Node.next[1]指針數(shù)組用的
 * 為什么是level-1而不是level,因?yàn)閟izeof(Node)已包含一個(gè)Node*指針的空間
 */ 
 void* node_memory = malloc(sizeof(Node) + sizeof(Node*) * (level - 1));
 Node* node = new (node_memory) Node(key);
 for (int i = 0; i < level; ++i)
  node->next[i] = nullptr;

 return node;
 }
 /*
 * 隨機(jī)函數(shù),范圍[1, kMaxLevel],越小概率越大
 */ 
 static int randomLevel()
 {
 int level = 1;
 while (rand() % 2 && level < kMaxLevel)
  level++;

 return level;
 }

public:
 Node* find(const Key& key)
 {
 // 從最高層開始查找,每層查找最后一個(gè)小于key的前繼節(jié)點(diǎn),不斷縮小范圍
 Node* pNode = head;
 for (int i = maxLevel - 1; i >= 0; --i)
 {
  while (pNode->next[i] != nullptr && pNode->next[i]->key < key)
  {
  pNode = pNode->next[i];
  }
 }

 // 如果第一層的pNode[0]->key == key,則返回pNode->next[0],即找到key
 if (nullptr != pNode->next[0] && pNode->next[0]->key == key)
  return pNode->next[0];

 return nullptr;
 }

 void insert(const Key& key)
 {
 int level = randomLevel();
 Node* new_node = newNode(key, level);
 Node* prev[kMaxLevel];
 Node* pNode = head;
 // 從最高層開始查找,每層查找最后一個(gè)小于key的前繼節(jié)點(diǎn)
 for (int i = level - 1; i >= 0; --i)
 {
  while (pNode->next[i] != nullptr && pNode->next[i]->key < key)
  {
  pNode = pNode->next[i];
  }
  prev[i] = pNode;
 }
 // 然后每層將新節(jié)點(diǎn)插入到前繼節(jié)點(diǎn)后面
 for (int i = 0; i < level; ++i)
 {
  new_node->next[i] = prev[i]->next[i];
  prev[i]->next[i] = new_node;
 }

 if (maxLevel < level) // 層數(shù)大于最大層數(shù),更新最大層數(shù)
  maxLevel = level;
 }

 void erase(const Key& key)
 {
 Node* prev[maxLevel];
 Node* pNode = head;
 // 從最高層開始查找,每層查找最后一個(gè)小于key的前繼節(jié)點(diǎn)
 for (int i = maxLevel - 1; i >= 0; --i)
 {
  while (pNode->next[i] != nullptr && pNode->next[i]->key < key)
  pNode = pNode->next[i];
  prev[i] = pNode;
 }
 
 // 如果找到key,
 if (pNode->next[0] != nullptr && pNode->next[0]->key == key)
 {
  Node *delNode = pNode->next[0];
  // 從最高層開始,如果當(dāng)前層的next節(jié)點(diǎn)的值等于key,則刪除next節(jié)點(diǎn)
  for (int i = maxLevel - 1; i >= 0; --i)
  {
  if (prev[i]->next[i] != nullptr && key == prev[i]->next[i]->key)
   prev[i]->next[i] = prev[i]->next[i]->next[i];
  }
  free(delNode); // 最后銷毀pNode->next[0]節(jié)點(diǎn)
 }
 
 // 如果max_level>1且頭結(jié)點(diǎn)的next指針為空,則該層已無(wú)數(shù)據(jù),max_level減一
 while (maxLevel > 1 && head->next[maxLevel] == nullptr)
 {
  maxLevel--;
 }
 }
};

#endif

Redis和LevelDB選用跳表而棄用紅黑樹的原因

  1. Skiplist的復(fù)雜度和紅黑樹一樣,而且實(shí)現(xiàn)起來(lái)更簡(jiǎn)單。
  2. 在并發(fā)環(huán)境下Skiplist有另外一個(gè)優(yōu)勢(shì),紅黑樹在插入和刪除的時(shí)候可能需要做一些rebalance的操作,這樣的操作可能會(huì)涉及到整個(gè)樹的其他部分,而skiplist的操作顯然更加局部性一些,鎖需要盯住的節(jié)點(diǎn)更少,因此在這樣的情況下性能好一些。

以上就是c++如何實(shí)現(xiàn)跳表的詳細(xì)內(nèi)容,更多關(guān)于c++ 跳表的資料請(qǐng)關(guān)注腳本之家其它相關(guān)文章!

相關(guān)文章

  • 一篇文章帶你了解C語(yǔ)言的選擇結(jié)構(gòu)

    一篇文章帶你了解C語(yǔ)言的選擇結(jié)構(gòu)

    這篇文章主要為大家介紹了C語(yǔ)言的選擇結(jié)構(gòu),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下,希望能夠給你帶來(lái)幫助
    2022-01-01
  • C++中基類和派生類之間的轉(zhuǎn)換實(shí)例教程

    C++中基類和派生類之間的轉(zhuǎn)換實(shí)例教程

    這篇文章主要介紹了C++中基類和派生類之間的轉(zhuǎn)換,有助于深入理解C++面向?qū)ο蟪绦蛟O(shè)計(jì),需要的朋友可以參考下
    2014-08-08
  • C++11中union的使用方法示例

    C++11中union的使用方法示例

    這篇文章主要給大家介紹了關(guān)于C++11中union的使用方法,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧
    2018-09-09
  • 八皇后問(wèn)題的相關(guān)C++代碼解答示例

    八皇后問(wèn)題的相關(guān)C++代碼解答示例

    這篇文章主要介紹了八皇后問(wèn)題的相關(guān)C++代碼解答示例,文中包括ACM競(jìng)賽的八皇后相關(guān)知識(shí)的練習(xí)實(shí)例,需要的朋友可以參考下
    2015-08-08
  • C語(yǔ)言實(shí)現(xiàn)2048小游戲

    C語(yǔ)言實(shí)現(xiàn)2048小游戲

    這篇文章主要為大家詳細(xì)介紹了C語(yǔ)言實(shí)現(xiàn)2048小游戲,注釋清晰,文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下
    2018-05-05
  • C++?Boost?Spirit精通教程

    C++?Boost?Spirit精通教程

    Boost是為C++語(yǔ)言標(biāo)準(zhǔn)庫(kù)提供擴(kuò)展的一些C++程序庫(kù)的總稱。Boost庫(kù)是一個(gè)可移植、提供源代碼的C++庫(kù),作為標(biāo)準(zhǔn)庫(kù)的后備,是C++標(biāo)準(zhǔn)化進(jìn)程的開發(fā)引擎之一,是為C++語(yǔ)言標(biāo)準(zhǔn)庫(kù)提供擴(kuò)展的一些C++程序庫(kù)的總稱
    2022-11-11
  • C++多線程實(shí)現(xiàn)電子詞典

    C++多線程實(shí)現(xiàn)電子詞典

    這篇文章主要為大家詳細(xì)介紹了C++多線程實(shí)現(xiàn)電子詞典,具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下
    2019-03-03
  • C語(yǔ)言深入探索之單鏈表與typedef的用法

    C語(yǔ)言深入探索之單鏈表與typedef的用法

    typedef為C語(yǔ)言的關(guān)鍵字,作用是為一種數(shù)據(jù)類型定義一個(gè)新名字,單鏈表是后面要學(xué)的雙鏈表以及循環(huán)鏈表的基礎(chǔ),要想繼續(xù)深入了解數(shù)據(jù)結(jié)構(gòu)以及C語(yǔ)言,我們就要奠定好這塊基石!接下來(lái)就和我一起學(xué)習(xí)吧
    2022-05-05
  • C語(yǔ)言使用ffmpeg和sdl實(shí)現(xiàn)多路音頻播放

    C語(yǔ)言使用ffmpeg和sdl實(shí)現(xiàn)多路音頻播放

    這篇文章主要為大家詳細(xì)介紹了一種基于ffmpeg和sdl實(shí)現(xiàn)的音頻多路混合的方法,文中的示例代碼講解詳細(xì),感興趣的小伙伴可以參考一下
    2023-06-06
  • C++歸并算法實(shí)例

    C++歸并算法實(shí)例

    這篇文章主要介紹了C++歸并算法,實(shí)例分析了C++實(shí)現(xiàn)基于歸并算法合并線性表的相關(guān)技巧,具有一定參考借鑒價(jià)值,需要的朋友可以參考下
    2015-07-07

最新評(píng)論

辛集市| 荆门市| 定西市| 丽水市| 加查县| 梧州市| 景洪市| 治多县| 咸丰县| 泰宁县| 融水| 潮州市| 牡丹江市| 盘锦市| 南漳县| 祁门县| 凯里市| 罗源县| 扶沟县| 定州市| 定远县| 威海市| 岳阳县| 开化县| 从化市| 江津市| 西宁市| 石棉县| 台中县| 津南区| 巧家县| 通道| 景东| 曲水县| 清新县| 永新县| 闸北区| 马尔康县| 布拖县| 怀安县| 双桥区|