中文亚洲精品无码_熟女乱子伦免费_人人超碰人人爱国产_亚洲熟妇女综合网

當(dāng)前位置: 首頁(yè) > news >正文

wordpress做的好的網(wǎng)站如何優(yōu)化網(wǎng)站快速排名

wordpress做的好的網(wǎng)站,如何優(yōu)化網(wǎng)站快速排名,秦皇島公司做網(wǎng)站,頁(yè)面網(wǎng)站緩存如何做目錄 哈希表的基本原理 哈希表的優(yōu)點(diǎn) 哈希表的缺點(diǎn) 應(yīng)用場(chǎng)景 閉散列法 開(kāi)散列法 開(kāi)放定值法Open Addressing——線性探測(cè)的模擬實(shí)現(xiàn) 超大重點(diǎn)部分評(píng)析 鏈地址法Separate Chaining——哈希桶的模擬實(shí)現(xiàn) 哈希表(Hash Table)是一種數(shù)據(jù)結(jié)構(gòu)&#x…

目錄

哈希表的基本原理

哈希表的優(yōu)點(diǎn)

哈希表的缺點(diǎn)

應(yīng)用場(chǎng)景

閉散列法

開(kāi)散列法

開(kāi)放定值法Open Addressing——線性探測(cè)的模擬實(shí)現(xiàn)

超大重點(diǎn)部分評(píng)析

鏈地址法Separate Chaining——哈希桶的模擬實(shí)現(xiàn)


哈希表(Hash Table)是一種數(shù)據(jù)結(jié)構(gòu),它通過(guò)將鍵(Key)映射到值(Value)的方式來(lái)實(shí)現(xiàn)快速的數(shù)據(jù)存儲(chǔ)與查找。哈希表的核心概念是哈希函數(shù),該函數(shù)用于將輸入的鍵轉(zhuǎn)換為哈希值(通常是一個(gè)整數(shù)),并根據(jù)這個(gè)哈希值將數(shù)據(jù)存儲(chǔ)在數(shù)組中的特定位置。

哈希表的基本原理

  1. 哈希函數(shù):這是哈希表的關(guān)鍵部分,它接收一個(gè)鍵并返回一個(gè)整數(shù)(哈希值)。理想情況下,哈希函數(shù)會(huì)將不同的鍵均勻地分布到數(shù)組的不同位置上。

  2. 數(shù)組(桶,Bucket):哈希表通常是基于數(shù)組實(shí)現(xiàn)的,哈希函數(shù)的輸出決定了鍵值對(duì)應(yīng)該存儲(chǔ)在數(shù)組中的哪個(gè)位置。

  3. 處理沖突:由于不同的鍵可能會(huì)生成相同的哈希值(稱為哈希沖突),需要有機(jī)制來(lái)處理這些沖突。常見(jiàn)的處理方式包括:

    • 鏈地址法(Separate Chaining):每個(gè)數(shù)組位置存儲(chǔ)一個(gè)鏈表,所有哈希值相同的鍵值對(duì)都存儲(chǔ)在同一個(gè)鏈表中。
    • 開(kāi)放地址法(Open Addressing):當(dāng)沖突發(fā)生時(shí),查找數(shù)組中的下一個(gè)空閑位置存儲(chǔ)鍵值對(duì),常見(jiàn)的方式包括線性探測(cè)、二次探測(cè)和雙重散列。
  4. 查找和插入:哈希表允許以 O(1) 的時(shí)間復(fù)雜度進(jìn)行查找和插入操作(在理想情況下),即只需一次哈希函數(shù)計(jì)算和一次數(shù)組訪問(wèn)即可找到或插入數(shù)據(jù)。

哈希表的優(yōu)點(diǎn)

  • 快速的查找、插入和刪除:在平均情況下,哈希表的查找、插入和刪除操作都是常數(shù)時(shí)間(O(1)),這使其非常高效。
  • 簡(jiǎn)單實(shí)現(xiàn):哈希表相對(duì)容易實(shí)現(xiàn),且不需要復(fù)雜的數(shù)據(jù)結(jié)構(gòu)操作。

哈希表的缺點(diǎn)

  • 空間浪費(fèi):如果哈希表的負(fù)載因子(存儲(chǔ)的元素?cái)?shù)量與數(shù)組大小的比值)較高,容易導(dǎo)致沖突增加,從而降低性能。為避免沖突,通常會(huì)使用更大的數(shù)組,這會(huì)導(dǎo)致空間浪費(fèi)。
  • 無(wú)法有序遍歷:哈希表中的數(shù)據(jù)是無(wú)序的,如果需要順序訪問(wèn)數(shù)據(jù),需要額外的處理。
  • 哈希函數(shù)質(zhì)量:哈希表的性能高度依賴于哈希函數(shù)的質(zhì)量,差勁的哈希函數(shù)可能導(dǎo)致較多的沖突。

應(yīng)用場(chǎng)景

哈希表在許多場(chǎng)景中廣泛使用,包括但不限于:

  • 字典實(shí)現(xiàn):例如,Python 中的字典(dict)就是通過(guò)哈希表實(shí)現(xiàn)的。
  • 緩存:哈希表常用于實(shí)現(xiàn)緩存機(jī)制,如 LRU 緩存。
  • 集合操作:例如,在查找某個(gè)元素是否在集合中時(shí),哈希表可以顯著提高效率。
  • 位圖:
  • 布隆過(guò)濾器:

通過(guò)哈希表,可以在大型數(shù)據(jù)集上快速執(zhí)行查找、插入和刪除操作,這使得它在實(shí)際應(yīng)用中非常實(shí)用。

所以依照哈希表的基本原理可以看出哈希表的底層結(jié)構(gòu)可以分為以下兩種,這兩種方法的本質(zhì)都是除留余數(shù)法:

閉散列法

閉散列法也叫開(kāi)放定址法,當(dāng)發(fā)生哈希沖突時(shí),如果哈希表未被裝滿,說(shuō)明在哈希表中必然還有 空位置,那么可以把key存放到?jīng)_突位置中的“下一個(gè)” 空位置中去。那如何尋找下一個(gè)空位置 呢? 比如2.1中的場(chǎng)景,現(xiàn)在需要插入元素44,先通過(guò)哈希函數(shù)計(jì)算哈希地址,hashAddr為4, 因此44理論上應(yīng)該插在該位置,但是該位置已經(jīng)放了值為4的元素,即發(fā)生哈希沖突。從發(fā)生沖突的位置開(kāi)始,依次向后探測(cè),直到尋找到下一個(gè)空位置為止。

插入: 通過(guò)哈希函數(shù)獲取待插入元素在哈希表中的位置 如果該位置中沒(méi)有元素則直接插入新元素,如果該位置中有元素發(fā)生哈希沖突, 使用線性探測(cè)找到下一個(gè)空位置,插入新元素。

刪除:采用閉散列處理哈希沖突時(shí),不能隨便物理刪除哈希表中已有的元素,若直接刪除元素 會(huì)影響其他元素的搜索。比如刪除元素4,如果直接刪除掉,44查找起來(lái)可能會(huì)受影 響。因此線性探測(cè)采用標(biāo)記的偽刪除法來(lái)刪除一個(gè)元素。

上面有一個(gè)名詞為線性探測(cè),就是當(dāng)待插入元素出現(xiàn)哈希沖突時(shí),一個(gè)一個(gè)往下尋找空位置稱為線性探測(cè),每次n的固定次方倍往下找稱為二次探測(cè),兩種探測(cè)的本質(zhì)解決的問(wèn)題完全一致,所有我們就只使用線性探測(cè)進(jìn)行實(shí)現(xiàn)。

開(kāi)散列法

開(kāi)散列法又叫鏈地址法(開(kāi)鏈法),首先對(duì)關(guān)鍵碼集合用散列函數(shù)計(jì)算散列地址,具有相同地 址的關(guān)鍵碼歸于同一子集合,每一個(gè)子集合稱為一個(gè)桶,各個(gè)桶中的元素通過(guò)一個(gè)單鏈表鏈 接起來(lái),各鏈表的頭結(jié)點(diǎn)存儲(chǔ)在哈希表中。代碼總體實(shí)現(xiàn)的功能和上面的閉散列法差不多。

從上圖可以看出,開(kāi)散列中每個(gè)桶中放的都是發(fā)生哈希沖突的元素。

開(kāi)放定值法Open Addressing——線性探測(cè)的模擬實(shí)現(xiàn)

#include<iostream>
#include<vector>
using namespace std;

//namespace hashbucket//包一個(gè)命名空間就可以調(diào)用了
//{

?? ?template<class K>
?? ?struct Hashfunc
?? ?{
?? ??? ?size_t operator()(const K& key)
?? ??? ?{
?? ??? ??? ?return (size_t)key;
//由于像當(dāng)K為string時(shí)不可以直接強(qiáng)制轉(zhuǎn)換成整型,所以如果哈希表需要插入string類型的數(shù)據(jù)就需要寫(xiě)string的特化版本,如下
?? ??? ?}
?? ?};
?? ?
//struct StringHashFunc
?? ?//{
?? ?//?? ?size_t operator()(const string& s)
?? ?//?? ?{
?? ?//?? ??? ?size_t hash = 0;
?? ?//?? ??? ?for (auto e : s)
?? ?//?? ??? ?{
?? ?//?? ??? ??? ?hash *= 31;
?? ?//?? ??? ??? ?hash += e;
?? ?//?? ??? ?}
?? ?//
?? ?//?? ??? ?return hash;
?? ?//?? ?}
?? ?//};

?? ?template<>
?? ?struct Hashfunc<string>
//可以直接在這里寫(xiě),模板的特化前提是前面有寫(xiě)過(guò)了,且名稱一樣,遇到和特化吻合的會(huì)優(yōu)先匹配特化版本
?? ?{
?? ??? ?size_t operator()(const string& key)
?? ??? ?{
?? ??? ??? ?size_t hash = 0;
?? ??? ??? ?for (auto e : key)
?? ??? ??? ?{
?? ??? ??? ??? ?hash += e;
?? ??? ??? ??? ?hash *= 31;
//根據(jù)某篇文章可得多乘31可以有效避免很多重復(fù)
?? ??? ??? ?}
?? ??? ??? ?return hash;
?? ??? ?}
?? ?};
?? ?enum status
?? ?{
?? ??? ?EXIST,
?? ??? ?EMPTY,
?? ??? ?DELETE
//三個(gè)狀態(tài),這里定義了哈希表中的數(shù)據(jù)的多個(gè)狀態(tài),在紅黑樹(shù)的模擬實(shí)現(xiàn)中有用過(guò),這樣方便判斷此位置的數(shù)據(jù)狀態(tài),方便以后的線性探測(cè)和刪除數(shù)據(jù)等
?? ?};

?? ?template<class K, class V>
?? ?struct Hashdata
?? ?{
?? ??? ?pair<K, V> _kv;
?? ??? ?status s = EMPTY;
//剛開(kāi)始時(shí)所有空位的狀態(tài)都是EMPTY
?? ?};


?? ?template<class K, class V, class Hash = Hashfunc<K>>
?? ?class Hashtable
?? ?{
?? ?public:
?? ??? ?Hashtable()
?? ??? ?{
?? ??? ??? ?_table.resize(10);
//直接在初始化時(shí)開(kāi)10個(gè)空間
?? ??? ?}
?? ??? ?Hash ha;
//仿函數(shù)
?? ??? ?bool insert(const pair<K, V>& kv)
?? ??? ?{
?? ??? ??? ?if (Find(kv.first))
?? ??? ??? ?{
?? ??? ??? ??? ?return false;
?? ??? ??? ?}
?? ??? ??? ?if (10 * n / _table.size() >= 7)
?? ??? ??? ?{
?? ??? ??? ??? ?
//vector<HashData<K, V>> newTables(_tables.size() * 2);
?? ??? ??? ??? ? 遍歷舊表, 將所有數(shù)據(jù)映射到新表
?? ??? ??? ??? ? ...
?? ??? ??? ??? ?//_tables.swap(newTables);
?? ??? ??? ??? ?//以上方法無(wú)法復(fù)用insert

?? ??? ??? ??? ?Hashtable<K, V, Hash> newht;//是KV
?? ??? ??? ??? ?newht._table.resize(2 * _table.size());//_table肯定是類里的,不然要指定的
?? ??? ??? ??? ?for (int i = 0; i < _table.size(); i++)
?? ??? ??? ??? ?{
?? ??? ??? ??? ??? ?newht.insert(_table[i]._kv);
//復(fù)用
?? ??? ??? ??? ?}
?? ??? ??? ??? ?_table.swap(newht._table);
//交換
?? ??? ??? ?}
?? ??? ??? ?size_t hashi = ha(kv.first) % _table.size();
//非整型不能取%,所以使用仿函樹(shù)轉(zhuǎn)換一下
?? ??? ??? ?while (_table[hashi].s == EXIST)
?? ??? ??? ?{
?? ??? ??? ??? ?hashi++;
?? ??? ??? ??? ?hashi %= _table.size();
//hashi不斷的++的時(shí)候有可能會(huì)超出整個(gè)vector的數(shù)據(jù)的長(zhǎng)度,所以需要再%_table.size()使其處在最后時(shí)下一步回到數(shù)據(jù)的開(kāi)頭,所以可以看出hashi是不斷循環(huán)的。
?? ??? ??? ?}
?? ??? ??? ?_table[hashi]._kv = kv;
?? ??? ??? ?_table[hashi].s = EXIST;
?? ??? ??? ?n++;
//每成功插入一個(gè)數(shù)據(jù),其負(fù)載因子就加1
?? ??? ??? ?return true;
?? ??? ?}
?? ??? ?vector<Hashdata<K, V>>* begin() const
?? ??? ?{
?? ??? ??? ?return &_table[0];
?? ??? ?}

?? ??? ?vector<Hashdata<K, V>>* end() const
?? ??? ?{
?? ??? ??? ?return &_table[_table.size()];
?? ??? ?}
?? ??? ?Hashdata<K, V>* Find(const K& key)
?? ??? ?{
?? ??? ??? ?size_t hashi = ha(key) % _table.size();
?? ??? ??? ?size_t n = hashi;
?? ??? ??? ?while (_table[hashi].s != DELETE)
?? ??? ??? ?{
?? ??? ??? ??? ?if (_table[hashi]._kv.first == key && _table[hashi].s == EXIST)
//由于下面的刪除邏輯為不刪除數(shù)據(jù)只改名數(shù)據(jù)的狀態(tài)所以當(dāng)找到相等時(shí),這個(gè)數(shù)據(jù)有可能會(huì)有兩種狀態(tài):EXIST和DELETE
?? ??? ??? ??? ?{
?? ??? ??? ??? ??? ?return &_table[hashi];
?? ??? ??? ??? ?}
?? ??? ??? ??? ?hashi++;
?? ??? ??? ??? ?hashi = hashi % _table.size();
?? ??? ??? ??? ?if (hashi == n)
?? ??? ??? ??? ?{
?? ??? ??? ??? ??? ?return nullptr;
?? ??? ??? ??? ?}
?? ??? ??? ?}
?? ??? ??? ?return nullptr;
?? ??? ?}

?? ??? ?bool Erase(const K& key)//只要傳一個(gè)K就可以了
?? ??? ?{
?? ??? ??? ?Hashdata<K, V>* ret = Find(key);
?? ??? ??? ?if (ret)
?? ??? ??? ?{
?? ??? ??? ??? ?ret->s == DELETE;
?? ??? ??? ??? ?return true;
?? ??? ??? ?}
?? ??? ??? ?return false;
?? ??? ?}
?? ?private:
?? ??? ?vector<Hashdata<K, V>> _table;
?? ??? ?size_t n = 0;
//表中存儲(chǔ)數(shù)據(jù)個(gè)數(shù), n為負(fù)載因子
?? ?};

?? ?
//}

超大重點(diǎn)部分評(píng)析

這邊說(shuō)一下擴(kuò)容的邏輯,由于插入邏輯里面hashi是不斷循環(huán)的,所以當(dāng)哈希表里面數(shù)據(jù)都占滿時(shí),hashi會(huì)陷入死循環(huán),但是就算沒(méi)有全部占滿,如果已占數(shù)據(jù)過(guò)多就會(huì)使得下一個(gè)數(shù)據(jù)在插入時(shí)哈希沖突過(guò)多使時(shí)間復(fù)雜度變大,所以為了避免這種情況,引入負(fù)載因子,當(dāng)插入數(shù)據(jù)占比>=百分之70時(shí),也就是負(fù)載因子/空間數(shù)據(jù)容納最大個(gè)數(shù) == 0.7時(shí),將容器的容量擴(kuò)大成原來(lái)的雙倍。

再觀察上面的擴(kuò)容代碼,為什么不能直接再原空間之間擴(kuò)容呢,需要另開(kāi)一個(gè)空間再交換回去,因?yàn)槿绻g在原空間擴(kuò)容,會(huì)使得size(數(shù)據(jù)最大個(gè)數(shù))變大使得原本的數(shù)據(jù)的映射亂了。像現(xiàn)在這種擴(kuò)容寫(xiě)法交換swap之后,由于新創(chuàng)建的臨時(shí)變量newht出函數(shù)體就會(huì)銷毀了,也就會(huì)順帶釋放掉swap交給它的原空間,這樣擴(kuò)容之后的空間就保留下來(lái)了,所以不需要考慮舊表沒(méi)有被釋放的問(wèn)題。

最后注意一下這個(gè)Erase的寫(xiě)法,很多人可能會(huì)認(rèn)為刪除某個(gè)元素需要像之前順序表的那種寫(xiě)法(畢竟每個(gè)數(shù)據(jù)就在順序表里面),刪除了這個(gè)數(shù)據(jù),讓這個(gè)數(shù)據(jù)后面的數(shù)據(jù)依次往前移,時(shí)間復(fù)雜度就是O(n),這里不是不可以,但是如果你這么寫(xiě)就麻煩了,因?yàn)槊總€(gè)數(shù)據(jù)都外帶了一個(gè)數(shù)據(jù)狀態(tài),按順序表那么寫(xiě)的話就忽略的狀態(tài)這個(gè)東西。

鏈地址法Separate Chaining——哈希桶的模擬實(shí)現(xiàn)

預(yù)知后事如何,請(qǐng)持續(xù)關(guān)注本系列內(nèi)容!!!

http://www.risenshineclean.com/news/9613.html

相關(guān)文章:

  • 萊山做網(wǎng)站的公司熊貓關(guān)鍵詞工具官網(wǎng)
  • 域名注冊(cè)后怎么建網(wǎng)站全網(wǎng)營(yíng)銷推廣案例
  • 商城網(wǎng)站都有什么功能模塊免費(fèi)網(wǎng)站推廣工具
  • 網(wǎng)站建設(shè)規(guī)劃書(shū)的空間seo軟文代寫(xiě)
  • 做網(wǎng)站學(xué)習(xí)營(yíng)銷策略范文
  • 長(zhǎng)沙企業(yè)網(wǎng)站建設(shè)服務(wù)怎么做網(wǎng)址
  • 淮北市住房和城鄉(xiāng)建設(shè)局網(wǎng)站出售外鏈
  • 門(mén)戶網(wǎng)站類型北京疫情消息1小時(shí)前
  • 手機(jī)網(wǎng)站制作費(fèi)用多少seo廠商
  • 黃驊市海邊深圳優(yōu)化排名公司
  • 網(wǎng)站制作服務(wù)公司婚戀網(wǎng)站排名前三
  • 怎樣做營(yíng)銷型網(wǎng)站推廣ppt抖音seo軟件
  • 網(wǎng)頁(yè)設(shè)計(jì)和網(wǎng)站開(kāi)發(fā)有什么區(qū)別百度競(jìng)價(jià)是什么工作
  • 如何給一個(gè)網(wǎng)站做定時(shí)的更新深圳網(wǎng)站制作推廣
  • 國(guó)內(nèi)永久在線免費(fèi)建站百度網(wǎng)盤(pán)資源搜索引擎入口
  • 深圳和海楓建設(shè)集團(tuán)有限公司網(wǎng)站百度推廣關(guān)鍵詞
  • node做網(wǎng)站優(yōu)勢(shì)東莞發(fā)布最新通告
  • 生產(chǎn)做網(wǎng)站表帶的制造廠家seo整站優(yōu)化系統(tǒng)
  • 專業(yè)網(wǎng)站建設(shè)模板怎么在百度推廣自己的網(wǎng)站
  • 購(gòu)物網(wǎng)站的圖片輪播怎么做短鏈接在線生成官網(wǎng)
  • 找別人做公司網(wǎng)站第一步做什么最新網(wǎng)站推廣方法
  • 做網(wǎng)站哪些公司好百度分析
  • 常德網(wǎng)站建設(shè)案例教程360優(yōu)化大師app
  • 自己做網(wǎng)站 為什么出現(xiàn)403營(yíng)銷渠道名詞解釋
  • 使用他人注冊(cè)商標(biāo)做網(wǎng)站湖南網(wǎng)站托管
  • 醫(yī)療器械做網(wǎng)站到哪里先備案網(wǎng)絡(luò)營(yíng)銷方法
  • 黔東網(wǎng)站建設(shè)什么網(wǎng)站都能打開(kāi)的瀏覽器
  • 聊天網(wǎng)站制作教程武漢seo廣告推廣
  • 淮北網(wǎng)站建設(shè)制作衡陽(yáng)網(wǎng)站優(yōu)化公司
  • 旅游網(wǎng)站模板源碼媒體發(fā)稿網(wǎng)