日本不卡不码高清免费观看,久久国产精品久久w女人spa,黄色aa久久,三上悠亚国产精品一区二区三区

您的位置:首頁技術(shù)文章
文章詳情頁

PHP內(nèi)核探索 —— PHP中的哈希表:哈希表是PHP實現(xiàn)中尤為關(guān)鍵的數(shù)據(jù)結(jié)構(gòu)

瀏覽:25日期:2022-09-16 13:58:36

PHP中使用最為頻繁的數(shù)據(jù)類型非字符串和數(shù)組莫屬,PHP比較容易上手也得益于非常靈活的數(shù)組類型。 在開始詳細介紹這些數(shù)據(jù)類型之前有必要介紹一下哈希表(HashTable)。 哈希表是PHP實現(xiàn)中尤為關(guān)鍵的數(shù)據(jù)結(jié)構(gòu)。

哈希表在實踐中使用的非常廣泛,例如編譯器通常會維護的一個符號表來保存標(biāo)記,很多高級語言中也顯式的支持哈希表。 哈希表通常提供查找(Search),插入(Insert),刪除(Delete)等操作,這些操作在最壞的情況下和鏈表的性能一樣為O(n)。 不過通常并不會這么壞,合理設(shè)計的哈希算法能有效的避免這類情況,通常哈希表的這些操作時間復(fù)雜度為O(1)。 這也是它被鐘愛的原因。

正是因為哈希表在使用上的便利性及效率上的表現(xiàn),目前大部分動態(tài)語言的實現(xiàn)中都使用了哈希表。

為了方便讀者閱讀后面的內(nèi)容,這里提前列舉一下HashTable實現(xiàn)中出現(xiàn)的基本概念。 哈希表是一種通過哈希函數(shù),將特定的鍵映射到特定值的一種數(shù)據(jù)結(jié)構(gòu),它維護鍵和值之間一一對應(yīng)關(guān)系。

鍵(key):用于操作數(shù)據(jù)的標(biāo)示,例如PHP數(shù)組中的索引,或者字符串鍵等等。槽(slot/bucket):哈希表中用于保存數(shù)據(jù)的一個單元,也就是數(shù)據(jù)真正存放的容器。哈希函數(shù)(hash function):將key映射(map)到數(shù)據(jù)應(yīng)該存放的slot所在位置的函數(shù)。哈希沖突(hash collision):哈希函數(shù)將兩個不同的key映射到同一個索引的情況。

哈希表可以理解為數(shù)組的擴展或者關(guān)聯(lián)數(shù)組,數(shù)組使用數(shù)字下標(biāo)來尋址,如果關(guān)鍵字(key)的范圍較小且是數(shù)字的話, 我們可以直接使用數(shù)組來完成哈希表,而如果關(guān)鍵字范圍太大,如果直接使用數(shù)組我們需要為所有可能的key申請空間。 很多情況下這是不現(xiàn)實的。即使空間足夠,空間利用率也會很低,這并不理想。同時鍵也可能并不是數(shù)字, 在PHP中尤為如此,所以人們使用一種映射函數(shù)(哈希函數(shù))來將key映射到特定的域中:

h(key) -> index

通過合理設(shè)計的哈希函數(shù),我們就能將key映射到合適的范圍,因為我們的key空間可以很大(例如字符串key), 在映射到一個較小的空間中時可能會出現(xiàn)兩個不同的key映射被到同一個index上的情況, 這就是我們所說的出現(xiàn)了沖突。 目前解決hash沖突的方法主要有兩種:鏈接法和開放尋址法。

沖突解決

鏈接法:鏈接法通過使用一個鏈表來保存slot值的方式來解決沖突,也就是當(dāng)不同的key映射到一個槽中的時候使用鏈表來保存這些值。 所以使用鏈接法是在最壞的情況下,也就是所有的key都映射到同一個槽中了,操作鏈表的時間復(fù)雜度為O(n)。 所以選擇一個合適的哈希函數(shù)是最為關(guān)鍵的。目前PHP中HashTable的實現(xiàn)就是采用這種方式來解決沖突的。

開放尋址法:通常還有另外一種解決沖突的方法:開放尋址法。使用開放尋址法是槽本身直接存放數(shù)據(jù), 在插入數(shù)據(jù)時如果key所映射到的索引已經(jīng)有數(shù)據(jù)了,這說明發(fā)生了沖突,這是會尋找下一個槽, 如果該槽也被占用了則繼續(xù)尋找下一個槽,直到尋找到?jīng)]有被占用的槽,在查找時也使用同樣的策律來進行。

哈希表的實現(xiàn)

在了解到哈希表的原理之后要實現(xiàn)一個哈希表也很容易,主要需要完成的工作只有三點:

實現(xiàn)哈希函數(shù)沖突的解決操作接口的實現(xiàn)

首先我們需要一個容器來保存我們的哈希表,哈希表需要保存的內(nèi)容主要是保存進來的的數(shù)據(jù), 同時為了方便的得知哈希表中存儲的元素個數(shù),需要保存一個大小字段, 第二個需要的就是保存數(shù)據(jù)的容器了。作為實例,下面將實現(xiàn)一個簡易的哈希表。基本的數(shù)據(jù)結(jié)構(gòu)主要有兩個, 一個用于保存哈希表本身,另外一個就是用于實際保存數(shù)據(jù)的單鏈表了,定義如下:

typedef struct _Bucket{ char *key; void *value; struct _Bucket *next;} Bucket;typedef struct _HashTable{ int size; Bucket* buckets;} HashTable;

上面的定義和PHP中的實現(xiàn)類似,為了便于理解裁剪了大部分無關(guān)的細節(jié),在本節(jié)中為了簡化, key的數(shù)據(jù)類型為字符串,而存儲的數(shù)據(jù)類型可以為任意類型。

Bucket結(jié)構(gòu)體是一個單鏈表,這是為了解決多個key哈希沖突的問題,也就是前面所提到的的鏈接法。 當(dāng)多個key映射到同一個index的時候?qū)_突的元素鏈接起來。

哈希函數(shù)需要盡可能的將不同的key映射到不同的槽(slot或者bucket)中,首先我們采用一種最為簡單的哈希算法實現(xiàn): 將key字符串的所有字符加起來,然后以結(jié)果對哈希表的大小取模,這樣索引就能落在數(shù)組索引的范圍之內(nèi)了。

static int hash_str(char *key){ int hash = 0; char *cur = key; while(*(cur++) != ’0’) {hash += *cur; } return hash;}// 使用這個宏來求得key在哈希表中的索引#define HASH_INDEX(ht, key) (hash_str((key)) % (ht)->size)

這個哈希算法比較簡單,它的效果并不好,在實際場景下不會使用這種哈希算法, 例如PHP中使用的是稱為DJBX33A算法, 這里列舉了Mysql,OpenSSL等開源軟件使用的哈希算法, 有興趣的讀者可以前往參考。

操作接口的實現(xiàn)

為了操作哈希表,實現(xiàn)了如下幾個操作函數(shù):

int hash_init(HashTable *ht); // 初始化哈希表int hash_lookup(HashTable *ht, char *key, void **result); // 根據(jù)key查找內(nèi)容int hash_insert(HashTable *ht, char *key, void *value); // 將內(nèi)容插入到哈希表中int hash_remove(HashTable *ht, char *key); // 刪除key所指向的內(nèi)容int hash_destroy(HashTable *ht);

下面以插入和獲取操作函數(shù)為例:

int hash_insert(HashTable *ht, char *key, void *value){ // check if we need to resize the hashtable resize_hash_table_if_needed(ht); // 哈希表不固定大小,當(dāng)插入的內(nèi)容快占滿哈表的存儲空間// 將對哈希表進行擴容, 以便容納所有的元素 int index = HASH_INDEX(ht, key); // 找到key所映射到的索引 Bucket *org_bucket = ht->buckets[index]; Bucket *bucket = (Bucket *)malloc(sizeof(Bucket)); // 為新元素申請空間 bucket->key = strdup(key); // 將值內(nèi)容保存進來, 這里只是簡單的將指針指向要存儲的內(nèi)容,而沒有將內(nèi)容復(fù)制。 bucket->value = value; LOG_MSG('Insert data p: %pn', value); ht->elem_num += 1; // 記錄一下現(xiàn)在哈希表中的元素個數(shù) if(org_bucket != NULL) { // 發(fā)生了碰撞,將新元素放置在鏈表的頭部LOG_MSG('Index collision found with org hashtable: %pn', org_bucket);bucket->next = org_bucket; } ht->buckets[index]= bucket; LOG_MSG('Element inserted at index %i, now we have: %i elementsn',index, ht->elem_num); return SUCCESS;}

上面這個哈希表的插入操作比較簡單,簡單的以key做哈希,找到元素應(yīng)該存儲的位置,并檢查該位置是否已經(jīng)有了內(nèi)容, 如果發(fā)生碰撞則將新元素鏈接到原有元素鏈表頭部。在查找時也按照同樣的策略,找到元素所在的位置,如果存在元素, 則將該鏈表的所有元素的key和要查找的key依次對比, 直到找到一致的元素,否則說明該值沒有匹配的內(nèi)容。

int hash_lookup(HashTable *ht, char *key, void **result){ int index = HASH_INDEX(ht, key); Bucket *bucket = ht->buckets[index]; if(bucket == NULL) return FAILED; // 查找這個鏈表以便找到正確的元素,通常這個鏈表應(yīng)該是只有一個元素的,也就不用多次 // 循環(huán)。要保證這一點需要有一個合適的哈希算法,見前面相關(guān)哈希函數(shù)的鏈接。 while(bucket) {if(strcmp(bucket->key, key) == 0){ LOG_MSG('HashTable found key in index: %i with key: %s value: %pn',index, key, bucket->value); *result = bucket->value;return SUCCESS;}bucket = bucket->next; } LOG_MSG('HashTable lookup missed the key: %sn', key); return FAILED;}

PHP中數(shù)組是基于哈希表實現(xiàn)的,依次給數(shù)組添加元素時,元素之間是有先后順序的,而這里的哈希表在物理位置上顯然是接近平均分布的, 這樣是無法根據(jù)插入的先后順序獲取到這些元素的,在PHP的實現(xiàn)中Bucket結(jié)構(gòu)體還維護了另一個指針字段來維護元素之間的關(guān)系。 具體內(nèi)容在后一小節(jié)PHP中的HashTable中進行詳細說明。上面的例子就是PHP中實現(xiàn)的一個精簡版。

標(biāo)簽: PHP
相關(guān)文章:
日本不卡不码高清免费观看,久久国产精品久久w女人spa,黄色aa久久,三上悠亚国产精品一区二区三区
一区免费在线| 精品99久久| 国产精品久久久久av电视剧| 国产中文字幕一区二区三区| 久久久久观看| 精品少妇一区| sm捆绑调教国产免费网站在线观看| 精品三级国产| 桃色av一区二区| 欧美亚洲国产精品久久| 亚洲一级影院| 欧美日韩四区| 日韩精品一二三四| 欧美日韩国产在线观看网站| 亚洲女同一区| 欧美中文日韩| 少妇精品久久久| 国产精品巨作av| 久久一区亚洲| 成人免费电影网址| 黄色亚洲在线| 日韩av中文字幕一区二区三区| 国产精品sss在线观看av| 成人日韩av| 久久一区二区三区喷水| 日韩在线一二三区| 国产欧美一区二区三区国产幕精品 | 日韩精品91亚洲二区在线观看| 欧美精品影院| 国产一区二区精品久| 欧美日韩亚洲在线观看| 亚洲天堂免费| 国产极品模特精品一二| 秋霞影院一区二区三区| 免费视频久久| 美女毛片一区二区三区四区最新中文字幕亚洲 | 国产视频一区三区| 日本视频一区二区| 国产不卡一区| 黄页网站一区| 国产精品综合色区在线观看| 精品日韩视频| 日韩在线观看中文字幕| 成人三级高清视频在线看| 亚洲欧美日韩精品一区二区| 国产精品成人3p一区二区三区| 秋霞影院一区二区三区| 亚洲免费毛片| 亚洲va中文在线播放免费| 亚洲天堂日韩在线| 97精品国产一区二区三区| 天堂成人免费av电影一区| 你懂的国产精品| 亚洲精品在线观看91| 日本va欧美va欧美va精品| 色婷婷亚洲mv天堂mv在影片| 男女男精品网站| 亚洲综合电影| 日韩**一区毛片| 中文另类视频| 国产精品久久久久久久久久白浆 | 精品成人18| 午夜一区在线| 日韩大片在线| 国产日韩在线观看视频| 亚洲午夜久久久久久尤物| 国产视频一区二| 亚洲欧洲日本mm| 久久久亚洲欧洲日产| 视频一区视频二区中文| 日韩免费高清| 国产精品任我爽爆在线播放| 麻豆极品一区二区三区| 日本不卡视频在线观看| 日韩成人午夜精品| 久久久免费人体| 国产美女亚洲精品7777| 日韩黄色免费网站| 国产福利一区二区精品秒拍| 婷婷国产精品| 日韩欧美中文在线观看| 成人高清一区| 蜜桃视频一区二区| 黄色在线网站噜噜噜| 日韩精彩视频在线观看| 91成人精品视频| 丁香婷婷久久| 精品一区二区三区的国产在线观看| 亚洲大片在线| 美日韩一区二区三区| 亚洲主播在线| 麻豆91在线播放| 国产精久久久| 国产中文在线播放| 99视频一区| 日韩欧美2区| 成人av二区| а√在线中文在线新版| 波多视频一区| 日本精品国产| 激情欧美丁香| 91亚洲国产| 麻豆精品99| 国产麻豆精品久久| 久久国产日韩欧美精品| 中文字幕成人| 国产一区日韩欧美| 国产超碰精品| 久久久久中文| 欧美1级日本1级| 欧美视频精品全部免费观看| 蜜臀av性久久久久蜜臀aⅴ四虎| 激情欧美国产欧美| 亚洲成av人片一区二区密柚| 日韩久久电影| 国产+成+人+亚洲欧洲在线| 久久久国产精品入口麻豆| 国产欧美日韩精品一区二区免费| 婷婷视频一区二区三区| 亚洲免费专区| 日韩在线网址| 亚洲一区区二区| 日韩视频久久| 欧美专区18| 午夜久久av | 久久国产婷婷国产香蕉| 日韩国产在线观看一区| 日韩在线观看中文字幕| 日韩中文字幕| 四虎精品永久免费| 日韩中文欧美在线| 综合激情一区| 中文字幕日韩亚洲| 日韩av一区二区三区四区| 国产免费播放一区二区| 久久成人高清| 国产精品99一区二区三区| 激情不卡一区二区三区视频在线| 国产在线一区不卡| 在线精品亚洲欧美日韩国产| 亚洲精品永久免费视频| 久久精品123| 亚洲免费成人| 午夜天堂精品久久久久| 国产三级精品三级在线观看国产| 久久精品99国产国产精| 欧美a在线观看| 日韩精品dvd| 91成人精品| 日韩精品五月天| 久久精品欧洲| 久久香蕉国产| 免费成人在线观看| 国产剧情一区| 国产精品伦理久久久久久| 日韩天堂在线| 国产日韩专区| 欧美日本二区| 在线天堂中文资源最新版| 黄色亚洲在线| 日韩毛片网站| 国产成人精选| 偷拍欧美精品| 日韩av在线免费观看不卡| 久久永久免费| 天堂资源在线亚洲| 综合激情网站| 麻豆精品少妇| 国产一区观看| 人人爱人人干婷婷丁香亚洲| 久久久久久一区二区| 五月综合激情| 欧美视频二区| 在线看片福利| 在线精品亚洲| 免费一级欧美片在线观看网站| 91精品蜜臀一区二区三区在线| 国产亚洲精品v| 国产精品亚洲产品| 久久中文字幕二区| 欧美日韩1区| 欧美日韩在线二区| 欧美在线看片| 久久国产电影| 国产日产精品_国产精品毛片 | 亚洲综合电影| 在线精品视频一区| 成人一区而且| 蜜桃av一区二区三区电影| 精品一区视频| 免费观看在线色综合| а√在线中文在线新版| 亚洲人成亚洲精品| 日韩专区精品| 欧美一级久久| 不卡中文字幕| 国产一区二区三区亚洲| 亚洲精品九九| 久久在线视频免费观看| 国产精品亚洲一区二区在线观看|