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

C++數(shù)據(jù)結(jié)構(gòu)哈希表詳解

 更新時(shí)間:2022年07月19日 15:00:34   作者:一起摸摸魚  
C++標(biāo)準(zhǔn)庫中使用的unordered_map底層實(shí)現(xiàn)是哈希表,下面這篇文章主要給大家介紹了關(guān)于C++中使用哈希表(unordered_map)的一些常用操作方法,需要的朋友可以參考下

實(shí)現(xiàn)

哈希表,即散列表,可以快速地存儲(chǔ)和查詢記錄。理想哈希表的存儲(chǔ)和查詢時(shí)間都是 O(1)。

本《資料》中哈希表分以下幾部分:散列函數(shù)、存儲(chǔ)和查找時(shí)的元素定位、存儲(chǔ)、查找。刪除操作因?yàn)椴怀S茫灾唤o出思想,不給出代碼。

根據(jù)實(shí)際情況,可選擇不同的散列方法。

以下代碼假設(shè)哈希表不會(huì)溢出。

// N表示哈希表長(zhǎng)度,是一個(gè)素?cái)?shù),M表示額外空間的大小,empty代表“沒有元素”。
const int N=9997, M=10000, empty=-1;
int a[N];
void init() // 初始化哈希表
{
memset(a,empty,sizeof(a)); // 注意,只有empty等于0或-1時(shí)才可以這樣做!
memset(bucket,empty,sizeof(bucket));
memset(first,0,sizeof(first));
}
inline int h(int); // 散列函數(shù)
int *locate(int, bool); // 用于存儲(chǔ)和查找的定位函數(shù),并返回對(duì)應(yīng)位置。
// 如果用于存儲(chǔ),則第二個(gè)參數(shù)為true,否則為false①。
void save(int x) // 存儲(chǔ)數(shù)據(jù)
{
int *p = locate(x, true);
if (p!=NULL) *p=x;
}
bool isexist(int x) // 查找數(shù)據(jù)
{
int *p = locate(x,false);
return (p!=NULL && *p==x);
}

散列函數(shù)

為了達(dá)到快速存儲(chǔ)和查找的目的,就必須在記錄的存儲(chǔ)位置和它的關(guān)鍵字之間建立一個(gè)確定的對(duì)應(yīng)關(guān)系 h。

這個(gè)關(guān)系 h 叫做哈希函數(shù)。

哈希表存取方便但存儲(chǔ)時(shí)容易沖突:即不同的關(guān)鍵字可以對(duì)應(yīng)同一哈希地址。如何確定哈希函數(shù)和解決沖突是關(guān)鍵。以下是幾種常見的哈希函數(shù)的構(gòu)造方法:

1. 取余數(shù)法:h(x) = x%p(p≤N,且最好是素?cái)?shù))

2. 直接定址法:h(x)=x 或 h(x)=a*x+b

3. 數(shù)字分析法:取關(guān)鍵字的若干數(shù)位(如中間兩位數(shù))組成哈希地址。

4. 平方取中法:關(guān)鍵字平方后取中間幾位數(shù)組成哈希地址。

5. 折疊法:將關(guān)鍵數(shù)字分割成位數(shù)相同的幾部分(最后一部分的位數(shù)可以不同)然后取幾部分的疊加和(舍去進(jìn)位)作為哈希地址。

6. 偽隨機(jī)數(shù)法:事先產(chǎn)生一個(gè)隨機(jī)數(shù)序列 r[],然后令 h(x)=r[x]。

設(shè)計(jì)哈希函數(shù)時(shí),要注意

對(duì)關(guān)鍵碼值的分布并不了解——希望選擇的散列函數(shù)在關(guān)鍵碼范圍內(nèi)能夠產(chǎn)生一個(gè)大致平均的關(guān)鍵碼值隨機(jī)分布,同時(shí)避免明顯的聚集可能性,如對(duì)關(guān)鍵碼值的高位或低位敏感的散列函數(shù)。

對(duì)關(guān)鍵碼值的分布有所了解——應(yīng)該使用一個(gè)依賴于分布的散列函數(shù),避免把一組相關(guān)的關(guān)鍵碼值映射到散列表的同一個(gè)槽中。

開散列方法

哈希表中難免會(huì)發(fā)生沖突。使用開散列方法可以解決這個(gè)問題。常用操作方法是“拉鏈法”,即相同的地址的關(guān)鍵字值均鏈入對(duì)應(yīng)的鏈表中。

如果散列函數(shù)很差,就容易形成長(zhǎng)長(zhǎng)的鏈表,從而影響查找的效率。

下面是用“拉鏈法”處理沖突時(shí)的定位函數(shù):

int size=-1;
struct node {int v; node * next;} *first[N], mem[M];
#define NEW(p) p=&mem[++size]; p->next=NULL
int * locate(int x, bool ins=false)
{
int p=h(x);
if (a[p]==x && !ins) return &a[p];
// 處理沖突
node *q = first[p];
if (ins)
if (q==NULL)
{
NEW(q);
first[p]=q;
return &q->v;
}
else
{
while (q->next!=NULL) q=q->next;
node *r; NEW(r);
q->next=r;
return &r->v;
}
else
while (q!=NULL)
{
if (q->v == x) return &q->v;
q=q->next;
}
return NULL;
}

閉散列方法(開地址方法)

處理沖突的另一種方法是為該關(guān)鍵字的記錄找到另一個(gè)“空”的哈希地址。在處理中可能得到一個(gè)地址序列 g(i)(i=1,2,…,k;0≤g(i)≤n-1),即在處理沖突時(shí)若得到的另一個(gè)哈希地址 g(1)仍發(fā)生沖突,再

求下一地址 g(2),若仍沖突,再求 g(3)……怎樣得到 g(i)呢?

溢出桶法:設(shè)一個(gè)溢出桶,不管得到的哈希地址如何,一旦發(fā)生沖突,都填入溢出桶。

再哈希法:使用另外一種哈希函數(shù)來定位。

線性探查:g(i)=(h(x)+di) % N,其中 h(x)為哈希函數(shù),N 為哈希表長(zhǎng),di 為增量序列。

1. 線性探測(cè)再散列:di=1,2,3,…,m-1

2. 二次探測(cè)再散列:

3. 偽隨機(jī)探測(cè)序列:事先產(chǎn)生一個(gè)隨機(jī)數(shù)序列 random[],令 di=random[i]。

下面是用溢出桶處理沖突時(shí)的定位函數(shù):

int bucket[M], top=-1; // 用于閉散列方法(溢出桶)
int * locate(int x, bool ins=false)
{
int p=h(x);
if (a[p]==x && !ins) // 在查找模式下碰到了所需的元素
return &a[p];
else if (ins)
{
if (a[p]==empty) // 可以插入
return &a[p];
else // 處理沖突
return &bucket[++top];
}
else // 到溢出桶中尋找元素
for (int i=0; i<=top; i++)
if (bucket[i]==x) return &bucket[i];
return NULL;
}

下面是用線性探查處理沖突的定位函數(shù),當(dāng)然,它也可以用于再哈希法處理沖突

inline int g(int p, int i) {return (p+i)%N;} // 根據(jù)需要來設(shè)計(jì)
int * locate(int x, bool ins=false)
{
int p=h(x);
int p2, c=0;
if (a[p]==x && !ins)
return &a[p];
else if (ins)
{
do
{
p2 = g(p, c++);
} while (a[p2]!=empty);
return &a[p2];
} else {
do
{
p2 = g(p, c++);
} while (a[p2]!=x && a[p2]!=empty);
if (a[p2]==x) return &a[p2];
}
return NULL;
}

閉散列方法的優(yōu)點(diǎn)是節(jié)省空間。不過,無論是溢出桶,還是線性探查,都會(huì)在尋址過程中浪費(fèi)時(shí)間。線性

探查的探查序列如果太長(zhǎng),就會(huì)使一些其他元素被迫散列在其他位置,從而影響了其他元素的查找效率。

刪除*

如果使用開散列方法,那么可以直接刪除元素。然而,使用閉散列方法,是不可以直接刪除元素的。假如

直接刪除,很有可能會(huì)影響其他元素的查找。

在這種情況下,有兩種刪除方法:一種是交換法,另一種是標(biāo)記法。

交換法:在刪除某元素時(shí),不要立刻把它清除。按照線性探查函數(shù)繼續(xù)尋找,直到?jīng)]有數(shù)值為止。將遇到

的最后一個(gè)數(shù)值與它交換。當(dāng)然,交換之前還要進(jìn)行類似的操作,可謂“牽一發(fā)而動(dòng)全身”。

標(biāo)記法:開一個(gè)標(biāo)記數(shù)組 flag[]。如果第 i 個(gè)元素被刪除了,就將 flag[i]設(shè)為 true。

1. 插入元素時(shí),如果所在位置有標(biāo)記,就把元素放到這里,并把標(biāo)記清除。

2. 查找元素時(shí),如果經(jīng)過標(biāo)記,就跳過去繼續(xù)查找。

3. 為了哈希表的效率,應(yīng)該定期清理表中的標(biāo)記(或重新散列所有元素)。

到此這篇關(guān)于C++數(shù)據(jù)結(jié)構(gòu)哈希表詳解的文章就介紹到這了,更多相關(guān)C++哈希表內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!

相關(guān)文章

  • C語言實(shí)現(xiàn)簡(jiǎn)單彈跳小球

    C語言實(shí)現(xiàn)簡(jiǎn)單彈跳小球

    這篇文章主要為大家詳細(xì)介紹了C語言實(shí)現(xiàn)簡(jiǎn)單彈跳小球,文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下
    2022-05-05
  • C語言?分析逆序字符串與字符串的逆序輸出有什么區(qū)別

    C語言?分析逆序字符串與字符串的逆序輸出有什么區(qū)別

    例如,給定一個(gè)字符串?s,將?s?中的字符順序顛倒過來,如?s?=?“abcd”,逆序后變成?“dcba”??梢圆捎枚喾N方法對(duì)字符串進(jìn)行逆序,以下將對(duì)其中的方法和字符串的逆序輸出的區(qū)別進(jìn)行分析
    2022-04-04
  • VScode+cuda編程常見環(huán)境問題的解決

    VScode+cuda編程常見環(huán)境問題的解決

    本文主要介紹了VScode+cuda編程常見環(huán)境問題的解決,文中通過示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧
    2023-02-02
  • C語言 數(shù)據(jù)類型詳細(xì)介紹

    C語言 數(shù)據(jù)類型詳細(xì)介紹

    本文主要講解C語言 數(shù)據(jù)類型,這里整理了詳細(xì)的數(shù)據(jù)類型的資料,希望能幫助剛剛開始學(xué)習(xí)C語言的同學(xué)
    2016-08-08
  • C++面向行輸入之get()與getline()實(shí)例詳解

    C++面向行輸入之get()與getline()實(shí)例詳解

    在c++里當(dāng)我們輸入一個(gè)字符串時(shí)習(xí)慣用cin,但是cin只能讀取一段不含空格的字符串,如果我們需要讀取一段包含空格的字符串時(shí),就需要用到getline()或get(),下面這篇文章主要給大家介紹了關(guān)于C++面向行輸入之get()與getline()的相關(guān)資料,需要的朋友可以參考下
    2021-10-10
  • 最新評(píng)論

    海伦市| 日土县| 河间市| 乐安县| 六盘水市| 镇江市| 岐山县| 景宁| 五台县| 镇江市| 阆中市| 紫金县| 依安县| 邵武市| 吉安市| 龙口市| 乌审旗| 马鞍山市| 阿拉尔市| 高雄县| 灌南县| 唐山市| 蒲城县| 彭水| 龙泉市| 许昌市| 德昌县| 内黄县| 怀化市| 什邡市| 息烽县| 兴城市| 元阳县| 大姚县| 无为县| 白水县| 武陟县| 黔江区| 盐池县| 惠安县| 晴隆县|