194 lines
5.2 KiB
C++
194 lines
5.2 KiB
C++
#include "Hash.h"
|
||
|
||
using namespace std;
|
||
|
||
//对字符串进行散列,使用链地址法解决冲突
|
||
|
||
|
||
//返回大于n的下一个素数
|
||
int NextPrime(int n) {
|
||
int i;
|
||
int p = (n % 2) ? n + 2 : n + 1; //从大于n的第一个奇数开始
|
||
|
||
while (p <= MAXCAPACITY) {
|
||
for (i = (int)sqrt(p); i > 2; i--)
|
||
if (!(p % i))
|
||
break;
|
||
if (i == 2)
|
||
break;
|
||
else
|
||
p += 2;
|
||
}
|
||
return p;
|
||
}
|
||
|
||
void InitHashTable(HashTable &hash_table, int init_capacity) {
|
||
if (init_capacity > 0 && init_capacity < MAXCAPACITY)
|
||
hash_table.capacity = NextPrime(init_capacity);
|
||
else
|
||
hash_table.capacity = NextPrime(32);
|
||
hash_table.table = new Node[hash_table.capacity];
|
||
hash_table.size = 0;
|
||
|
||
for (int i = 0; i < hash_table.capacity; i++) {
|
||
hash_table.table[i].next = NULL;
|
||
}
|
||
}
|
||
|
||
unsigned int SumHash(const char *key, int table_size) {
|
||
unsigned int h = 0;
|
||
|
||
while (*key)
|
||
h += *key++;
|
||
|
||
return h % table_size;
|
||
}
|
||
|
||
unsigned int ShiftHash(const char *key, int table_size) {
|
||
unsigned int h = 0;
|
||
while (*key)
|
||
h = (h << 5) + *key++;
|
||
return h % table_size;
|
||
}
|
||
|
||
unsigned int ELFHash(const char *key, int table_size) {
|
||
unsigned long h = 0;
|
||
unsigned long x = 0;
|
||
|
||
while (*key) {
|
||
h = (h << 4) + (*key++); //h左移4位,当前字符ASCII存入h的低四位
|
||
if ((x = h & 0xF0000000L) != 0) {
|
||
//如果最高位不为0,则说明字符多余7个,如果不处理,再加第九个字符时,第一个字符会被移出
|
||
//因此要有如下处理
|
||
h ^= (x >> 24);
|
||
//清空28~31位
|
||
h &= ~x;
|
||
}
|
||
}
|
||
return h % table_size;
|
||
}
|
||
|
||
void ReCapacity(HashTable &hash_table, unsigned int (*Hash)(const char *key, int table_size)) {
|
||
const int ori_capacity = hash_table.capacity;
|
||
|
||
hash_table.capacity = NextPrime(hash_table.capacity * 2);
|
||
Node *ori_table = hash_table.table;
|
||
hash_table.table = new Node[hash_table.capacity];
|
||
for (int i = 0; i < hash_table.capacity; i++) {
|
||
hash_table.table[i].next = NULL;
|
||
}
|
||
|
||
for (int i = 0; i < ori_capacity; i++) {
|
||
Node *p = ori_table[i].next, *q;
|
||
while (p) {
|
||
q = p;
|
||
p = p->next;
|
||
int new_pos = Hash(q->key, hash_table.capacity);
|
||
q->next = hash_table.table[new_pos].next;
|
||
hash_table.table[new_pos].next = q;
|
||
}
|
||
}
|
||
|
||
delete[] ori_table;
|
||
}
|
||
|
||
//将以key为键的元素value放入Hash表,返回是否有旧元素,有返回true,使用value进行替换,否则返回false,old_value为旧元素
|
||
bool Put(HashTable &hash_table, const char *key, ElemType value, ElemType &old_value, unsigned int (*Hash)(const char *key, int table_size)) {
|
||
//若添加新元素后使得元素个数等于哈希表容量*装填因子,进行扩容
|
||
if (hash_table.size + 1 >= hash_table.capacity * LOADFACTOR)
|
||
ReCapacity(hash_table, Hash);
|
||
|
||
unsigned int pos = Hash(key, hash_table.capacity);
|
||
|
||
Node *p = hash_table.table[pos].next;
|
||
while (p) {
|
||
if (!strcmp(p->key, key)) {
|
||
old_value = p->value;
|
||
p->value = value;
|
||
|
||
return true;
|
||
}
|
||
p = p->next;
|
||
}
|
||
|
||
Node *node = new Node;
|
||
strcpy(node->key, key);
|
||
node->value = value;
|
||
node->next = hash_table.table[pos].next;
|
||
hash_table.table[pos].next = node;
|
||
hash_table.size++;
|
||
|
||
return false;
|
||
}
|
||
|
||
bool Get(HashTable &hash_table, const char *key, ElemType &value, unsigned int (*Hash)(const char *key, int table_size)) {
|
||
int pos = Hash(key, hash_table.capacity);
|
||
|
||
Node *p = hash_table.table[pos].next;
|
||
while (p) {
|
||
if (!strcmp(key, p->key)) {
|
||
value = p->value;
|
||
return true;
|
||
}
|
||
p = p->next;
|
||
}
|
||
|
||
return false;
|
||
}
|
||
|
||
double GetASL(HashTable &hash_table, unsigned int (*Hash)(const char *key, int table_size)) {
|
||
double asl = 0.0;
|
||
for (int i = 0; i < hash_table.capacity; i++) {
|
||
int n = 0;
|
||
Node *p = hash_table.table[i].next;
|
||
while (p) {
|
||
asl += (++n);
|
||
p = p->next;
|
||
}
|
||
}
|
||
|
||
return asl / hash_table.size;
|
||
}
|
||
|
||
bool Remove(HashTable &hash_table, const char *key, ElemType &value, unsigned int (*Hash)(const char *key, int table_size)) {
|
||
int pos = Hash(key, hash_table.capacity);
|
||
|
||
Node *p = &hash_table.table[pos];
|
||
while (p ->next) {
|
||
if (!strcmp(p->next->key, key)) {
|
||
value = p->next->value;
|
||
Node *t = p->next;
|
||
p->next = t->next;
|
||
delete t;
|
||
return true;
|
||
}
|
||
p = p->next;
|
||
}
|
||
|
||
return false;
|
||
}
|
||
|
||
void DelHashTable(HashTable &hash_table) {
|
||
for (int i = 0; i < hash_table.capacity; i++) {
|
||
Node *p = hash_table.table[i].next;
|
||
while (p) {
|
||
Node *t = p;
|
||
p = p->next;
|
||
delete t;
|
||
}
|
||
}
|
||
|
||
delete[] hash_table.table;
|
||
}
|
||
|
||
void TraverseHashTable(HashTable &hash_table, void (*visit)(ElemType v)) {
|
||
for (int i = 0; i < hash_table.capacity; i++) {
|
||
Node *p = hash_table.table[i].next;
|
||
while (p) {
|
||
visit(p->value);
|
||
p = p->next;
|
||
}
|
||
}
|
||
}
|
||
|