九种查找算法-哈希查找
哈希查找算法又稱散列查找算法,是一種借助哈希表(散列表)查找目標元素的方法,查找效率最高時對應的時間復雜度為 O(1)。
哈希查找算法適用于大多數場景,既支持在有序序列中查找目標元素,也支持在無序序列中查找目標元素。講解哈希查找算法之前,我們首先要搞清楚什么是哈希表。
哈希表是什么
哈希表(Hash table)又稱散列表,是一種存儲結構,通常用來存儲多個元素。
和其它存儲結構(線性表、樹等)相比,哈希表查找目標元素的效率非常高。每個存儲到哈希表中的元素,都配有一個唯一的標識(又稱“索引”或者“鍵”),用戶想查找哪個元素,憑借該元素對應的標識就可以直接找到它,無需遍歷整個哈希表。
多數場景中,哈希表是在數組的基礎上構建的,下圖給大家展示了一個普通的數組:
哈希表:
我們使用一個下標范圍比較大的數組來存儲元素。可以設計一個函數(哈希函數, 也叫做散列函數),使得每個元素的關鍵字都與一個函數值(即數組下標)相對應,于是用這個數組單元來存儲這個元素;也可以簡單的理解為,按照關鍵字為每一個元素"分類",然后將這個元素存儲在相應"類"所對應的地方。但是,不能夠保證每個元素的關鍵字與函數值是一一對應的,因此極有可能出現對于不同的元素,卻計算出了相同的函數值,這樣就產生了"沖突",換句話說,就是把不同的元素分在了相同的"類"之中。后面我們將看到一種解決"沖突"的簡便做法。
"直接定址"與"解決沖突"是哈希表的兩大特點。
哈希函數:
規則:通過某種轉換關系,使關鍵字適度的分散到指定大小的的順序結構中,越分散,則以后查找的時間復雜度越小,空間復雜度越高。
算法思路:
如果所有的鍵都是整數,那么就可以使用一個簡單的無序數組來實現:將鍵作為索引,值即為其對應的值,這樣就可以快速訪問任意鍵的值。這是對于簡單的鍵的情況,我們將其擴展到可以處理更加復雜的類型的鍵。
用給定的哈希函數構造哈希表;
根據選擇的沖突處理方法(常見方法:拉鏈法和線性探測法)解決地址沖突;
在哈希表的基礎上執行哈希查找;
代碼:
#include<stdio.h> #include<stdlib.h>#define SUCCESS 1 #define UNSUCCESS 0 #define OVERFLOW -1 #define OK 1 #define ERROR -1 #define MAXNUM 9999 // 用于初始化哈希表的記錄 keytypedef int Status; typedef int KeyType;// 哈希表中的記錄類型 typedef struct {KeyType key; }RcdType;// 哈希表類型 typedef struct {RcdType *rcd;int size;int count;int *tag; }HashTable;// 哈希表每次重建增長后的大小 int hashsize[] = { 11, 31, 61, 127, 251, 503 }; int index = 0;// 初始哈希表 Status InitHashTable(HashTable &H, int size) {int i;H.rcd = (RcdType *)malloc(sizeof(RcdType)*size);H.tag = (int *)malloc(sizeof(int)*size);if (NULL == H.rcd || NULL == H.tag) return OVERFLOW;KeyType maxNum = MAXNUM;for (i = 0; i < size; i++){H.tag[i] = 0;H.rcd[i].key = maxNum;}H.size = size;H.count = 0;return OK; }// 哈希函數:除留余數法 int Hash(KeyType key, int m) {return (3 * key) % m; }// 處理哈希沖突:線性探測 void collision(int &p, int m) {p = (p + 1) % m; }// 在哈希表中查詢 Status SearchHash(HashTable H, KeyType key, int &p, int &c) {p = Hash(key, H.size);int h = p;c = 0;while ((1 == H.tag[p] && H.rcd[p].key != key) || -1 == H.tag[p]){collision(p, H.size); c++;}if (1 == H.tag[p] && key == H.rcd[p].key) return SUCCESS;else return UNSUCCESS; }//打印哈希表 void printHash(HashTable H) {int i;printf("key : ");for (i = 0; i < H.size; i++)printf("%3d ", H.rcd[i].key);printf("\n");printf("tag : ");for (i = 0; i < H.size; i++)printf("%3d ", H.tag[i]);printf("\n\n"); }// 函數聲明:插入哈希表 Status InsertHash(HashTable &H, KeyType key);// 重建哈希表 Status recreateHash(HashTable &H) {RcdType *orcd;int *otag, osize, i;orcd = H.rcd;otag = H.tag;osize = H.size;InitHashTable(H, hashsize[index++]);//把所有元素,按照新哈希函數放到新表中for (i = 0; i < osize; i++){if (1 == otag[i]){InsertHash(H, orcd[i].key);}}return OK; }// 插入哈希表 Status InsertHash(HashTable &H, KeyType key) {int p, c;if (UNSUCCESS == SearchHash(H, key, p, c)){ //沒有相同keyif (c*1.0 / H.size < 0.5){ //沖突次數未達到上線//插入代碼H.rcd[p].key = key;H.tag[p] = 1;H.count++;return SUCCESS;}else recreateHash(H); //重構哈希表}return UNSUCCESS; }// 刪除哈希表 Status DeleteHash(HashTable &H, KeyType key) {int p, c;if (SUCCESS == SearchHash(H, key, p, c)){//刪除代碼H.tag[p] = -1;H.count--;return SUCCESS;}else return UNSUCCESS; }int main() {printf("-----哈希表-----\n");HashTable H;int i;int size = 11;KeyType array[8] = { 22, 41, 53, 46, 30, 13, 12, 67 };KeyType key;//初始化哈希表printf("初始化哈希表\n");if (SUCCESS == InitHashTable(H, hashsize[index++])) printf("初始化成功\n");//插入哈希表printf("插入哈希表\n");for (i = 0; i <= 7; i++){key = array[i];InsertHash(H, key);printHash(H);}//刪除哈希表printf("刪除哈希表中key為12的元素\n");int p, c;if (SUCCESS == DeleteHash(H, 12)){printf("刪除成功,此時哈希表為:\n");printHash(H);}//查詢哈希表printf("查詢哈希表中key為67的元素\n");if (SUCCESS == SearchHash(H, 67, p, c)) printf("查詢成功\n");//再次插入,測試哈希表的重建printf("再次插入,測試哈希表的重建:\n");KeyType array1[8] = { 27, 47, 57, 47, 37, 17, 93, 67 };for (i = 0; i <= 7; i++){key = array1[i];InsertHash(H, key);printHash(H);}getchar();return 0; }?
總結
以上是生活随笔為你收集整理的九种查找算法-哈希查找的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: net5 failed to load
- 下一篇: python如何控制伺服驱动_用 pyb