內嵌變長資料結構範例 trbstrmap

2021-08-30 07:12:53 字數 3617 閱讀 3179

以前的

這篇文章

介紹了嵌入的變長資料結構(

embeded)

本文介紹乙個使用這種思想實現的通用

strmap

容器,相當於:

實現上使用了我以前寫的線索紅黑樹

——相比標準

map的實現,節省了一半的結點儲存開銷,而平均查詢時間只付出很小的額外開銷,並且沒有**膨脹問題。

是可選的,

allocator

總在類範圍,可以修改:

為了節省空間,

trbstrmap

使用乙個位元組儲存

strkey_length

,因此,

strlen(strkey)

不可超過

255,允許長度為0的

key。最大長度

255基本上可以應對絕大多數情況。 把

key作為變長字段,有乙個原因很重要:

key一旦插入,就不可改變!因此,整個結點的

memblock

也就不需要重新分配,可以修改的只有。

容器的iterator只有在刪除該node以後才失效」的語義!

一旦用在多執行緒環境中,問題就會變得很複雜,因為修改了父節點。就不能僅lock需要修改資料的那個結點,而是需要lock整個tree,使用資料庫的術語,就是一下子從記錄鎖變成了表鎖,本來按key查詢時,因為key沒改變,就不需要加鎖,而這樣搞,查詢時就需要對整個表加鎖,嚴重影響併發性!

注意事項:

1.        

trbstrmap::iterator::value_type

和trbstrmap::value_type都是,

*iter

也是;而不是

std::map

的pair。

2.        

trbstrmap::key(iter)

獲得iter

對應的key

3.        

trbstrmap::klen(iter)

獲得key_length

,當然,

strlen(trbstrmap::key(iter))

也可以獲得

key_length

,但需要一些時間開銷;另外,當

key_content

中存在\0

時,klen

就是不可缺少的了(後面將詳細介紹這種情況)

4.        

再次強調,

key_cstr_length

最大長度不可超過

255,但這個長度不包括末尾的\0

示例**:

typedef febird::trbstrmapsmap_t;

smap_t smap, smap2;

smap["1"] = 0;

smap["2"] = 1;

smap["3"] = 1;

smap["4"] = 2;

smap["1"]++;

smap["4"] += 2;

smap.insert("5", 5);

assert(!smap.insert("5", 6).second);

// str長度不可超過255

smap["aabbccddeeffgghhiijjkk***********************************=="] = 10;

for (typename smt::iterator i = smap.begin(); i != smap.end(); ++i)

在簡單的情況下,使用

trbstrmap,

比std::map

可以節省

50%~70%

的記憶體。使用的方便程度,基本上沒差別。

是模板引數,可以是任意struct/class

,當然也可以內嵌指標,也可以是複雜物件,沒有任何限制。

trbstrmap

允許加入內容中存在

\0的字串,這種應用比較罕見,但是仍然允許,只是必須遵循

以下注意事項:

1.        

在這種情況下,需要傳入

key_content_length

引數:trbstrmap.probe(key,key_content_length)

trbstrmap.insert(key,key_content_length, val)

key_content_length

是整個key_content

長度,包括末尾的

\0——如果有的話

2.        

或者,傳入

std::string

:trbstrmap[std::string(…)] = val;

equal to: trbstrmap.probe(s.c_str(), s.size()+1) = val;

3.        

trbstrmap.insert(key, klen, val)

4.        

這種情況下,應用一般需要傳入乙個自定義的

compare

5.        

trbstrmap::klen(iter)

在任何情況下,返回的都是key_content_length – 1

不管末尾有沒有\0

6.        

自定義函式需要獲取key_content_length時,應該如下:

inttrb_compare_custom ( const

struct trb_vtab* trb_restrict vtab,

const

struct trb_tree* trb_restrict tree,

const

void* trb_restrict x,

const

void* trb_restrict y)

7.        

當給trbstrmap::find/lower_bound/equal_range

多傳入乙個

key_content_length

時,這些函式會將

key和

key_content_length

打包(這些都在庫內部完成),應用須知這會有稍微多一些的開銷。

必須這麼做,因為

compare

函式需要找到

key_content_length

,除此之外,別無他法。

8.        

貌似很複雜,但始終堅持剃刀原理:在絕大多數情況下,也就是字串是

cstr

,末尾包含

\0時,函式的行為符合傳統慣例並且高效;在罕見情況下也可用,只是效率有一點下降,使用難度也大一些。

9.        

當情況複雜時,記住:只要你明確傳入了長度,這個長度就是你真實資料的長度

**:

測試**:

資料結構 變長陣列

剛發現,以前用vector覺得挺簡單的,自己實現一下才知道這麼麻煩。真是佩服那些c 大師,寫出這麼好的東西。這算是乙個簡易的vector吧,之所以說它簡易,並不是因為功能少,而是實現的複雜度遠遠不及std vector 但基本原理是一樣的 1 pragma once23 const intinit ...

資料結構 堆疊的範例程式

堆疊本身可以使用靜態陣列結構或動態鍊錶結構實現,只要維持堆疊後進先出和從頂端讀取資料兩個基本原則即可。利用資料結構來實現堆疊的好處是演算法設計簡單,下面將用佇列來模擬堆疊。範例是 以陣列模擬撲克牌的洗牌及發牌過程,以點數取得撲克牌後放入堆疊,放滿52張牌後利用堆疊功能來給4個人發牌。include ...

資料結構與演算法 C 實現動態變長陣列

乙個簡單至極的變長陣列,僅僅是在原生陣列中新增了自動變長功能 參考stl中vector的實現,每次下標越界,就將陣列容量擴大一倍。申請新的空間,是原長度的二倍 從原記憶體複製所有內容到新記憶體 釋放原記憶體 author trialley date 2019 7 26 licence mit pra...