近来上班划水划得起飞,又有时间可以写文章了。
先总结一下《数据结构与算法分析》中散列的定义:
散列函数:每个关键字被映射到从0到Tablesize -1这个范围中的某个数,并且被放到适当的单元中。这个映射关系被称为散列函数。
散列冲突(哈希冲突):两个关键字散列到同一个值。
哈希代码:
第一种(适用整数):
typedef unsigned int Index;
Index Hash(const char *key, int tableSize)
{
unsigned int hashVal = 0;
while (*key != '\0')
{
hashVal += *key++;
}
return hashVal % tableSize;
}
第二种(适用字符串): 空间利用率极低。
假设Key至少有两个字符外加NULL结尾的字符串。
26个字母+空格=27。 从最高位到最低位分别乘以27的平方、27的一次方和27的0次方。相当于该字符串为27进制的数。
3个字符(忽略空格)有26^3种组合,实际上3个字母组成的单词只有2851种。
最多只能用到表的28%的空间, 空间利用率极低。
Index Hash(const char *key, int tableSize)
{
return (key[0] + 27 * key[1] + 729 * key[2]) % tablesize;
}
第三种(适用字符串):
Index Hash(cosnt char *key, int tableSize)
{
unsigned int hashVal = 0;
while(*key)
{
hashVal = (hashVal << 5) + *key++; //向左移动5位比乘以27的运算速度快。
}
}
解决冲突的方式:
- 分离链接法
将散列到同一个值的所有元素保留到一张表。例如10和20, 采用相同的散列函数Hash(X) = X mod 10。 那么10和20经过散列后得到同一个值,那么在Key[X}中,能找到10和20。
通常在某位置以遍历方式查找某元素。
#pragma once
struct ListNode;
typedef struct ListNode *Position;
struct HashTbl;
typedef struct HashTbl *HashTable;
HashTable InitializeTable(int tableSize);
void DestroyTable(HashTable h);
Position Find(ElementType key, HashTable h)
void Insert(ElementType key, HashTable h);
ElementType Retrieve(Position p);
sturct ListNode
{
ElementType Element; //当前元素值
Position Next; //下一节点
};
typedef Position List;
struct HashTbl
{
int tableSize;
List *TheLists; //二级指针,指向 指向ListNode结构的指针的指针。
};
HashTable InitializeTable(int tableSize)
{
HashTable H;
int i;
if(tableSize < minTableSize)
{
Error("Table size too small");
return nullptr;
}
h = malloc(sizeof(struct HashTbl));
if(H == nullptr)
{
FatalError("Out of space!!!")
}
H->TableSize = NextPrime(tableSize); //设置表的大小为素数
/* Allocate array of lists */
H->TheLists = malloc(sizeof(List) * H->tableSize); //指针数组
if(H->TheLists == nullptr)
{
FatalError("Out of space");
}
/*Allocate list headers
*设置链表头*/
for(i = 0; i < H->tableSize; ++i)
{
H->TheLists[i] = malloc(sizeof(struct ListNode));
if (H->TheLists[i] == nullptr)
{
FatalError("Out of space!!!");
}
else
{
H->TheLists[i]->Next = nullptr;
}
}
return H;
}
Position Find(ElementType key, HashTable H)
{
Position P;
List L;
L = H->TheLists[Hash(key, H->tableSize)];
P = L->Next;
/*遍历链表*/
while(P && P->Element != key)
{
P = P->Next;
}
return P;
}
- 开放定址法
- 线性探测法
- 平方探测法
- 双散列
- 再散列