題目:
不使用任何內建的哈希表庫設計一個哈希映射(HashMap)。
實現?MyHashMap
?類:
MyHashMap()
?用空映射初始化對象void put(int key, int value)
?向 HashMap 插入一個鍵值對?(key, value)
?。如果?key
?已經存在于映射中,則更新其對應的值?value
?。int get(int key)
?返回特定的?key
?所映射的?value
?;如果映射中不包含?key
?的映射,返回?-1
?。void remove(key)
?如果映射中存在?key
?的映射,則移除?key
?和它所對應的?value
?。
示例:
輸入: ["MyHashMap", "put", "put", "get", "get", "put", "get", "remove", "get"] [[], [1, 1], [2, 2], [1], [3], [2, 1], [2], [2], [2]] 輸出: [null, null, null, 1, -1, null, 1, null, -1]解釋: MyHashMap myHashMap = new MyHashMap(); myHashMap.put(1, 1); // myHashMap 現在為 [[1,1]] myHashMap.put(2, 2); // myHashMap 現在為 [[1,1], [2,2]] myHashMap.get(1); // 返回 1 ,myHashMap 現在為 [[1,1], [2,2]] myHashMap.get(3); // 返回 -1(未找到),myHashMap 現在為 [[1,1], [2,2]] myHashMap.put(2, 1); // myHashMap 現在為 [[1,1], [2,1]](更新已有的值) myHashMap.get(2); // 返回 1 ,myHashMap 現在為 [[1,1], [2,1]] myHashMap.remove(2); // 刪除鍵為 2 的數據,myHashMap 現在為 [[1,1]] myHashMap.get(2); // 返回 -1(未找到),myHashMap 現在為 [[1,1]]
提示:
0 <= key, value <= 106
- 最多調用?
104
?次?put
、get
?和?remove
?方法
思路:
哈希函數:能夠將集合中任意可能的元素映射到一個固定范圍的整數值,并將該元素存儲到整數值對應的地址上。
沖突處理:由于不同元素可能映射到相同的整數值,因此需要在整數值出現“沖突”時,進行沖突處理。以下代碼使用的解決沖突處理的方法是鏈地址法。
鏈地址法:為每個哈希值維護一個鏈表,并將具有相同哈希值的元素都放入這一鏈表當中。
設哈希表的大小為HSIZE,則可以設計一個簡單的哈希函數計算哈希值x,x=key%HSIZE。
我們開辟一個大小為 HSIZE的數組,數組的每個位置是一個鏈表。當計算出哈希值之后,就插入到對應位置的鏈表當中。
由于我們使用整數除法作為哈希函數,為了盡可能避免沖突,應當將HSIZE 取為一個質數。
代碼:
typedef struct List
{int key;int val;struct List* next;
}List;void Insret(List* l1,int key,int val)
{if(l1==NULL)return;List* p=(List*)malloc(sizeof(List));p->key=key;p->val=val;p->next=l1->next;l1->next=p;
}void Delete(List* l1,int key)
{if(l1==NULL)return;struct List* p=l1;struct List* q=p->next;for(;p->next!=NULL;p=p->next){if(p->next->key==key){q=p->next;p->next=q->next;free(q);break;//不加的話會有崩潰的風險} }
}List* Search(List* l1,int key)
{if(l1==NULL)return NULL;List* p=l1->next;for(;p!=NULL;p=p->next){if(p->key==key){return p;}}return NULL;
}void Free(List* l1)
{if(l1==NULL)return;List* p=l1->next;while(l1->next!=NULL){p=l1->next;l1->next=p->next;free(p);}
}typedef struct {List* data;
} MyHashMap;#define HSIZE 101MyHashMap* myHashMapCreate() {MyHashMap* myhash=(MyHashMap*)malloc(sizeof(MyHashMap));myhash->data=(List*)malloc(sizeof(List)*HSIZE);for(int i=0;i<HSIZE;i++){myhash->data[i].next=NULL;}return myhash;
}void myHashMapPut(MyHashMap* obj, int key, int value) {if(obj==NULL)return;List* p=Search(&(obj->data[key%HSIZE]),key);if(p==NULL){Insret(&(obj->data[key%HSIZE]),key,value);}else {p->val=value;}
}int myHashMapGet(MyHashMap* obj, int key) {if(obj==NULL)return -1;List* p=Search(&(obj->data[key%HSIZE]),key);if(p==NULL)return -1;elsereturn p->val;
}void myHashMapRemove(MyHashMap* obj, int key) {if(obj==NULL)return;Delete(&(obj->data[key%HSIZE]),key);
}void myHashMapFree(MyHashMap* obj) {if(obj==NULL)return;for(int i=0;i<HSIZE;i++){Free(&(obj->data[i]));}free(obj->data);
}/*** Your MyHashMap struct will be instantiated and called as such:* MyHashMap* obj = myHashMapCreate();* myHashMapPut(obj, key, value);* int param_2 = myHashMapGet(obj, key);* myHashMapRemove(obj, key);* myHashMapFree(obj);
*/
心得:
????????一開始編寫Search函數時,將其返回值設為int,即int Search(),返回結果為對應key值的value值,但在后續編寫void myHashMapPut()函數的過程中發現,根據題目要求,我們需要獲取對應key值的節點來修改value值,所以將Search函數的返回值改為List*。
? ? ? ? 在void Delete(List* l1,int key)函數中的for循環語句中,需要加上break,否則如果刪除的是此鏈表的最后一個數據時,會再次執行循環語句,即使用空指針NULL,造成崩潰。