赞
踩
哈希表(Hash table,也叫散列表),是根据关键码值(Key value)而直接进行访问的数据结构。也就是说,它通过把关键码值映射到表中一个位置来访问记录,以加快查找的速度。
1.1 哈希函数
也叫散列函数,即:根据key,计算出key对应记录的储存位置 position = f(key)
散列函数满足以下的条件:
1、对输入值运算,得到一个固定长度的摘要(Hash value);
2、不同的输入值可能对应同样的输出值;
比较好的哈希函数是time33算法
unsigned int time33(char *str) {
unsigned int hash = 0;
while (*str) {
hash += (hash << 5) + (*str++);
}
return (hash & 0x7FFFFFFF);
}
1.2 哈希冲突(Hash collision)
也就是两个不同输入产生了相同输出值的情况。首先,哈希冲突是无法避免的,因此,哈希算法的选择直接决定了哈希冲突发生的概率;同时必须要对哈希冲突进行处理,方法主要有以下几种:
1、链地址法
链地址法:对Hash表中每个Hash值建立一个冲突表,即将冲突的几个记录以表的形式存储在其中
2、开放地址法
如果遇到冲突的时候怎么办呢?就找hash表剩下空余的空间,找到空余的空间然后插入。就像你去商店买东西,发现东西卖光了,怎么办呢?找下一家有东西卖的商家买呗。
2.1 链地址法实现的哈希表
(1)构建哈希表
首先定义链结点,以结构体Node展示,其中Node有三个属性,一个是key值,一个value值,还有一个是作为链表的指针,还有作为类的哈希表。
#define HASHSIZE 5 typedef struct Node{ char* key; char* value; Node *next; }Node; class HashTable{ private: Node* node[HASHSIZE]; public: HashTable(); ~HashTable(); size_t hash(const char* key); Node* lookup(const char* key); bool install(const char* key,const char* value); const char* get(const char* key); void display(); private: char* strdup(const char *str); //给每个节点分配空间 };
(2)定义哈希表的构造方法、析构、节点空间分配算法
HashTable::HashTable(){ for (int i = 0; i < HASHSIZE; ++i) { node[i] = NULL; } } HashTable::~HashTable(){ for (int i = 0; i < HASHSIZE; ++i) { Node *next = node[i]; while(next) { Node *tmp = next->next; free(next->key); free(next->value); free(next); next = tmp; } } } char* HashTable::strdup(const char *str){ int len=strlen(str)+1; char *ns=(char*)malloc(len*sizeof(char)); strcpy(ns,str); if(ns==nullptr) return nullptr; else return ns; }
(3)定义哈希表的Hash算法,在这里我使用time33算法
size_t HashTable::hash(const char* key){
size_t hash=0;
while (*key) {
hash += (hash << 5) + (*key++);
}
return hash%HASHSIZE;
}
(4)定义一个查找根据key查找结点的方法
思路:首先是用Hash函数计算头地址,然后根据头地址向下一个个去查找结点,如果结点的key和查找的key值相同,则匹配成功。
Node* HashTable::lookup(const char* key){
Node *np;
size_t index;
index = hash(key);
for(np=node[index];np;np=np->next){
if(!strcmp(key,np->key))
return np;
}
return NULL;
}
(5)定义一个插入结点的方法
思路:首先是查看该key值的结点是否存在,如果存在则更改value值就好,如果不存在,则插入新结点。
bool HashTable::install(const char* key,const char* value){ size_t index; Node *np; if(!(np=lookup(key))){ index = hash(key); np = (Node*)malloc(sizeof(Node)); if(!np) return false; np->key=strdup(key); if(np->key == nullptr) return false; np->next = node[index]; //设置新节点的下一个节点 node[index] = np; //把新节点设置为头结点 } else { free(np->value); } np->value=strdup(value); if(np->key == nullptr) return false; return true; }
(6)打印出哈希表,用于Debug
void HashTable::display(){ Node* temp; for (int i = 0; i < HASHSIZE; ++i) { if(!node[i]){ printf("[]\n"); }else{ printf("["); for (temp=node[i]; temp; temp=temp->next) { printf("[%s][%s] ",temp->key,temp->value ); } printf("]\n"); } } }
(7)测试代码是否正确
#include <stdio.h> #include <stdlib.h> #include <string.h> void testHash(HashTable *ht) { const char* key[]={"a","b","c","d","e","f"}; const char* value[]={"value1","value2","value3","value4","value5","value6"}; for (int i = 0; i < 6; ++i) { ht->install(key[i],value[i]); } } int main(int argc, char const *argv[]) { HashTable ht; testHash(&ht); ht.display(); return 0; }
输出如下:
[[d][value4] ]
[[e][value5] ]
[[f][value6] [a][value1] ]
[[b][value2] ]
[[c][value3] ]
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。