亚洲香蕉成人av网站在线观看_欧美精品成人91久久久久久久_久久久久久久久久久亚洲_热久久视久久精品18亚洲精品_国产精自产拍久久久久久_亚洲色图国产精品_91精品国产网站_中文字幕欧美日韩精品_国产精品久久久久久亚洲调教_国产精品久久一区_性夜试看影院91社区_97在线观看视频国产_68精品久久久久久欧美_欧美精品在线观看_国产精品一区二区久久精品_欧美老女人bb

首頁 > 編程 > C > 正文

詳解散列表算法與其相關的C語言實現

2020-01-26 14:59:08
字體:
來源:轉載
供稿:網友

散列表(也叫哈希表)是一種查找算法,與鏈表、樹等算法不同的是,散列表算法在查找時不需要進行一系列和關鍵字(關鍵字是數據元素中某個數據項的值,用以標識一個數據元素)的比較操作。

    散列表算法希望能盡量做到不經過任何比較,通過一次存取就能得到所查找的數據元素,因而必須要在數據元素的存儲位置和它的關鍵字(可用key表示)之間建立一個確定的對應關系,使每個關鍵字和散列表中一個唯一的存儲位置相對應。因此在查找時,只要根據這個對應關系找到給定關鍵字在散列表中的位置即可。這種對應關系被稱為散列函數(可用h(key)表示)。

    根據設定的散列函數h(key)和處理沖突的方法將一組關鍵字key映像到一個有限的連續的地址區間上,并以關鍵字在地址區間中的像作為數據元素在表中的存儲位置,這種表便被稱為散列表,這一映像過程稱為散列,所得存儲位置稱為散列地址。

    關鍵字、散列函數以及散列表的關系如下圖所示:

201581193721542.jpg (401×270)

     1、散列函數

    散列函數是從關鍵字到地址區間的映像。

    好的散列函數能夠使得關鍵字經過散列后得到一個隨機的地址,以便使一組關鍵字的散列地址均勻地分布在整個地址區間中,從而減少沖突。

    常用的構造散列函數的方法有:

    (1)、直接定址法

    取關鍵字或關鍵字的某個線性函數值為散列地址,即:

    h(key) = key   或 h(key) = a * key + b

    其中a和b為常數。

    (2)、數字分析法

    (3)、平方取值法

    取關鍵字平方后的中間幾位為散列地址。

    (4)、折疊法

    將關鍵字分割成位數相同的幾部分(最后一部分的位數可以不同),然后取這幾部分的疊加和(舍去進位)作為散列地址。

    (5)、除留余數法

    取關鍵字被某個不大于散列表表長m的數p除后所得的余數為散列地址,即:

    h(key) = key MOD p    p ≤ m

    (6)、隨機數法

    選擇一個隨機函數,取關鍵字的隨機函數值為它的散列地址,即:

    h(key) = random(key)

    其中random為隨機函數。

    2、處理沖突

    對不同的關鍵字可能得到同一散列地址,即key1 ≠ key2,而h(key1)= h(key2),這種現象稱為沖突。具有相同函數值的關鍵字對該散列函數來說稱作同義詞。

    在一般情況下,散列函數是一個壓縮映像,這就不可避免地會產生沖突,因此,在創建散列表時不僅要設定一個好的散列函數,而且還要設定一種處理沖突的方法。

    常用的處理沖突的方法有:

    (1)、開放定址法

    hi =(h(key) + di) MOD m     i =1,2,…,k(k ≤ m-1)

    其中,h(key)為散列函數,m為散列表表長,di為增量序列,可有下列三種取法:

    1)、di = 1,2,3,…,m-1,稱線性探測再散列;

    2)、di = 12,-12,22,-22,32,…,±k2 (k ≤m/2),稱二次探測再散列;

    3)、di = 偽隨機數序列,稱偽隨機探測再散列。

    (2)、再散列法

    hi = rhi(key)   i = 1,2,…,k

    rhi均是不同的散列函數。

    (3)、鏈地址法

    將所有關鍵字為同義詞的數據元素存儲在同一線性鏈表中。假設某散列函數產生的散列地址在區間[0,m-1]上,則設立一個指針型向量void *vec[m],其每個分量的初始狀態都是空指針。凡散列地址為i的數據元素都插入到頭指針為vec[i]的鏈表中。在鏈表中的插入位置可以在表頭或表尾,也可以在表的中間,以保持同義詞在同一線性鏈表中按關鍵字有序排列。

    (4)、建立一個公共溢出區


相關的C語言解釋

hash.h
哈希表數據結構&&接口定義頭文件

 

  #ifndef HASH_H   #define HASH_H      #define HASH_TABLE_INIT_SIZE 7      #define SUCCESS 1   #define FAILED 0         /**    * 哈希表槽的數據結構    */   typedef struct Bucket {     char *key;     void *value;     struct Bucket *next;   } Bucket;      /**    * 哈希表數據結構    */   typedef struct HashTable {     int size;  // 哈希表大小     int elem_num;  // 哈希表已經保存的數據元素個數     Bucket **buckets;   } HashTable;      int hashIndex(HashTable *ht, char *key);   int hashInit(HashTable *ht);   int hashLookup(HashTable *ht, char *key, void **result);   int hashInsert(HashTable *ht, char *key, void *value);   int hashRemove(HashTable *ht, char *key);   int hashDestory(HashTable *ht);   #endif 


hash.c
哈希表操作函數具體實現

  #include <stdio.h>   #include <stdlib.h>   #include <string.h>   #include "hash.h"      /**    * 初始化哈希表    *    * T = O(1)    *    */   int hashInit(HashTable *ht)   {     ht->size = HASH_TABLE_INIT_SIZE;     ht->elem_num = 0;     ht->buckets = (Bucket **)calloc(ht->size, sizeof(Bucket *));        if (ht->buckets == NULL)       return FAILED;     else       return SUCCESS;   }      /**    * 散列函數    *    * T = O(n)    *    */   int hashIndex(HashTable *ht, char *key)   {     int hash = 0;        while (*key != '/0') {       hash += (int)*key;       key ++;     }        return hash % ht->size;   }      /**    * 哈希查找函數    *    * T = O(n)    *    */   int hashLookup(HashTable *ht, char *key, void **result)   {     int index = hashIndex(ht, key);        Bucket *bucket = ht->buckets[index];        while (bucket) {       if (strcmp(bucket->key, key) == 0) {         *result = bucket->value;         return SUCCESS;       }       bucket = bucket->next;     }        return FAILED;   }         /**    * 哈希表插入操作    *    * T = O(1)    *    */   int hashInsert(HashTable *ht, char *key, void *value)   {     int index = hashIndex(ht, key);        Bucket *org_bucket, *tmp_bucket;     org_bucket = tmp_bucket = ht->buckets[index];        // 檢查key是否已經存在于hash表中     while (tmp_bucket) {       if (strcmp(tmp_bucket->key, key) == 0) {         tmp_bucket->value = value;         return SUCCESS;       }       tmp_bucket = tmp_bucket->next;     }        Bucket *new = (Bucket *)malloc(sizeof(Bucket));          if (new == NULL)  return FAILED;        new->key = key;     new->value = value;     new->next = NULL;        ht->elem_num += 1;        // 頭插法     if (org_bucket) {       new->next = org_bucket;     }        ht->buckets[index] = new;        return SUCCESS;    }      /**    * 哈希刪除函數    *    * T = O(n)    *    */   int hashRemove(HashTable *ht, char *key)   {     int index = hashIndex(ht, key);        Bucket *pre, *cur, *post;        pre = NULL;     cur = ht->buckets[index];        while (cur) {       if (strcmp(cur->key, key) == 0) {         post = cur->next;                  if (pre == NULL) {           ht->buckets[index] = post;         } else {           pre->next = post;         }            free(cur);            return SUCCESS;       }          pre = cur;       cur = cur->next;     }        return FAILED;   }      /**    * 哈希表銷毀函數    *    * T = O(n)    */   int hashDestory(HashTable *ht)   {     int i;     Bucket *cur, *tmp;        cur = tmp = NULL;        for (i = 0; i < ht->size; i ++) {       cur = ht->buckets[i];          while (cur) {         tmp = cur->next;         free(cur);         cur = tmp;       }     }        free(ht->buckets);        return SUCCESS;   } 


test.c
單元測試文件

  #include <stdio.h>   #include <stdlib.h>   #include <string.h>   #include <assert.h>   #include "hash.h"      int main(int argc, char **argv)   {     HashTable *ht = (HashTable *)malloc(sizeof(HashTable));     int result = hashInit(ht);        assert(result == SUCCESS);        /* Data */     int int1 = 10;     int int2 = 20;     char str1[] = "Hello World!";     char str2[] = "Value";     char str3[] = "Hello New World!";        /* to find data container */     int *j = NULL;     char *find_str = NULL;        /* Test Key Insert */     printf("Key Insert:/n");     hashInsert(ht, "FirInt", &int1);     hashInsert(ht, "FirStr", str1);     hashInsert(ht, "SecStr", str2);     printf("Pass Insert/n");        /* Test Key Lookup*/     printf("Key Lookup:/n");     result = hashLookup(ht, "FirStr", &find_str);     assert(result == SUCCESS);     printf("pass lookup, the value is %s/n", find_str);        /* Test Update */     printf("Key Update:/n");     hashInsert(ht, "FirStr", str3);     result = hashLookup(ht, "FirStr", &find_str);     assert(result == SUCCESS);     printf("pass update, the value is %s/n", find_str);        return 0;   } 


編譯方法

gcc -Wall -g -o main test.c hash.c

運行結果

201581194105153.png (590×141)

開放尋址法
在開放尋址法(open addressing)中,所有的元素都存放在散列表里。亦即,每個表項或包含動態集合的一個元素,或包含NIL。當查找一個元素時,要檢查所有的表項,直到找到所需的元素,或者最終發現該元素不在表中。不像在鏈接法中,這沒有鏈表,也沒有元素存放在散列表外。在這種方法中,散列表可能會被填滿,以致于不能插入任何新的元素,但裝載因子a是絕對不會超過1的

線性探測法
第一次沖突移動1個單位,再次沖突時,移動2個,再次沖突,移動3個單位,依此類推

它的散列函數是:H(x) = (Hash(x) + F(i)) mod TableSize, 且F(0) = 0

舉例(騰訊面試題目)

已知一個線性表(38, 25, 74, 63, 52, 48),假定采用散列函數 h(key) = key % 7 計算散列地址,并散列存儲在散列表 A[0..6]中,若采用線性探測方法解決沖突,則在該散列表上進行等概率成功查找的平均長度為 ?

下邊模擬線性探測:

    38 % 7 == 3,  無沖突, ok
    25 % 7 == 4, 無沖突, ok
    74 % 7 == 4, 沖突, (4 + 1)% 7 == 5, 無沖突,ok
    63 % 7 == 0, 無沖突, ok
    52 % 7 == 3, 沖突, (3 + 1) % 7 == 4. 沖突, (4 + 1) % 7 == 5, 沖突, (5 + 1)%7 == 6,無沖突,ok
    48 % 7 == 6, 沖突, (6 + 1) % 7 == 0, 沖突,  (0 + 1) % 7 == 1,無沖突,ok


畫圖如下:

201581194134572.jpg (466×117)

平均查找長度 = (1 + 3 + 1 + 1 + 2 + 3) % 6 = 2

線性探測方法比較容易實現,但它卻存在一個問題,稱為一次群集(primary clustering).隨著時間的推移,連續被占用的槽不斷增加,平均查找時間也隨著不斷增加。集群現象很容易出現,這是因為當一個空槽前有i個滿的槽時,該空槽為下一個將被占用的槽的概率是 (i + 1) / n.連續占用的槽的序列會變得越來越長,因而平均查找時間也會隨之增加

平方探測
為了避免上面提到的一個群集的問題:第一次沖突時移動1(1的平方)個單位,再次沖突時,移動4(2的平方)個單位,還沖突,移動9個單位,依此類推。F(i) = i * i

發表評論 共有條評論
用戶名: 密碼:
驗證碼: 匿名發表

圖片精選

亚洲香蕉成人av网站在线观看_欧美精品成人91久久久久久久_久久久久久久久久久亚洲_热久久视久久精品18亚洲精品_国产精自产拍久久久久久_亚洲色图国产精品_91精品国产网站_中文字幕欧美日韩精品_国产精品久久久久久亚洲调教_国产精品久久一区_性夜试看影院91社区_97在线观看视频国产_68精品久久久久久欧美_欧美精品在线观看_国产精品一区二区久久精品_欧美老女人bb
欧美成人精品激情在线观看| 久热99视频在线观看| 另类视频在线观看| 欧美成人精品不卡视频在线观看| 国产国语videosex另类| 欧美激情一区二区三区成人| 欧美大胆a视频| 色综合伊人色综合网| 热门国产精品亚洲第一区在线| 国产精品露脸av在线| 日本久久久久久久久| 国产高清在线不卡| 国产免费久久av| 欧美裸体xxxx极品少妇| 国产欧美日韩精品丝袜高跟鞋| 亚洲无限乱码一二三四麻| 这里只有精品在线播放| 亚洲国产精品大全| 国产久一一精品| 欧美精品videos| 色播久久人人爽人人爽人人片视av| 91亚洲国产精品| 日韩动漫免费观看电视剧高清| 亚洲国产精品成人一区二区| 中国日韩欧美久久久久久久久| 欧美成人第一页| 欧美激情亚洲精品| 成人国产在线视频| 91麻豆国产语对白在线观看| 日韩精品中文字幕在线播放| 亚洲欧美三级在线| 自拍偷拍亚洲区| 丝袜美腿亚洲一区二区| 日韩视频免费观看| 欧美日韩国产在线播放| 亚洲国产天堂久久国产91| 国产成+人+综合+亚洲欧洲| 成人久久一区二区三区| 国产日韩在线看| 亚洲色图在线观看| 国产欧美亚洲精品| 国产成人一区二区三区电影| 26uuu日韩精品一区二区| 亚洲丁香婷深爱综合| 国产欧美一区二区白浆黑人| 欧美洲成人男女午夜视频| 91探花福利精品国产自产在线| 成人午夜在线视频一区| 97碰在线观看| 成人免费午夜电影| 91美女高潮出水| 色婷婷综合久久久久中文字幕1| 久久久精品在线观看| 亚洲第一精品久久忘忧草社区| 欧美激情视频一区| 超碰精品一区二区三区乱码| 国产精品444| 亚洲国产精品国自产拍av秋霞| 国产成+人+综合+亚洲欧美丁香花| 国产一区二区在线免费| 欧洲精品在线视频| 亚洲a∨日韩av高清在线观看| 国产精品成人免费视频| 欧美性猛交xxxx久久久| 欧美老女人xx| 国产精品伦子伦免费视频| 久久人91精品久久久久久不卡| 久久视频这里只有精品| 亚洲国产精品推荐| 97av在线视频| 国产成人免费91av在线| 在线播放精品一区二区三区| 在线观看国产成人av片| 久久久精品亚洲| xxxxx91麻豆| 亚洲电影免费观看高清完整版在线| 久久久久久久久久久免费精品| 久久视频这里只有精品| 日韩专区在线播放| 成人网址在线观看| 中日韩美女免费视频网站在线观看| 中文字幕国产亚洲| 国产综合久久久久| 热久久免费视频精品| 精品福利在线视频| 日韩在线中文字幕| 亚洲毛片在线免费观看| 日韩欧美国产激情| 久久久999国产精品| 欧美性猛交xxxx免费看| 欧美寡妇偷汉性猛交| 亚洲国产精品久久久久秋霞不卡| 欧美中文字幕在线播放| 久久精品国产视频| 国产精品视频精品| 在线播放国产精品| 午夜精品久久久久久久久久久久| 91视频88av| 日韩色av导航| 国产精品99久久久久久白浆小说| 大桥未久av一区二区三区| 亚洲精品中文字| 亚洲自拍欧美色图| 欧美日韩精品在线观看| 综合136福利视频在线| 国产欧美一区二区白浆黑人| 97精品国产97久久久久久免费| 午夜精品久久久久久久99热浪潮| 91chinesevideo永久地址| 日韩av在线一区二区| 亚洲一区二区三区在线视频| 欧美高清视频在线观看| 91夜夜揉人人捏人人添红杏| 日本中文字幕久久看| 欧美成年人视频网站| 国产激情视频一区| 91精品国产高清久久久久久91| 欧美成人精品xxx| 国产免费久久av| 欧美成年人视频网站欧美| 国产91精品视频在线观看| 中文字幕免费精品一区高清| 色偷偷偷综合中文字幕;dd| 国产日本欧美一区二区三区在线| 成人国产精品久久久| 国产精品国产自产拍高清av水多| 亚洲欧洲国产一区| 亚洲精品国偷自产在线99热| 亚洲最大成人网色| 超碰日本道色综合久久综合| 夜夜嗨av色综合久久久综合网| 久久999免费视频| 精品色蜜蜜精品视频在线观看| 欧美精品videosex性欧美| 91国产视频在线播放| 国产亚洲欧美aaaa| 精品福利免费观看| 欧美日产国产成人免费图片| 国产精品一区二区久久| 欧美一区二区三区精品电影| 国产一区二区在线播放| 欧美成人免费播放| 亚洲欧美成人一区二区在线电影| 粉嫩老牛aⅴ一区二区三区| 国产999精品久久久| 6080yy精品一区二区三区| www国产精品com| 国产成人精品久久| 欧美性xxxxxx| 成人免费淫片视频软件| 国产成人短视频| 日韩亚洲成人av在线| 亚洲综合在线中文字幕| 91免费在线视频网站| 亚洲欧美色婷婷| 久久久久久久999| 一区二区福利视频| 国产精品v日韩精品| 亚洲已满18点击进入在线看片| 国产综合福利在线| 97香蕉久久超级碰碰高清版| 久久6免费高清热精品| 3344国产精品免费看| 欧美激情一级精品国产|