前面说的 各种查找都是 基于 “比较” 的基础 来进行 查找的。查找的 效率 要 看 比较的 次数。那么 有没有 不需要 比较,就可以 找到 想要的数据的 方法呢?
哈希表 就是 这样的 一种方法,它用 数组 作为 保存 关键字的 数据原型,通过 一个 哈希 函数f(k),来找到 关键字 存储的位置,从而 找到想要的信息。
例如 我们 想要解决 这样的一个问题:
假设这有一个各种字母组成的字符串,假设这还有另外一个字符串,而且这个字符串里的字母数相对少一些。什么方法能最快的查出所有小字符串里的字母在大字符串里都有?
比如,如果是下面两个字符串:
String 1: ABCDEFGHLMNOPQRS
String
2: DCGSRQPOM
我们 可以用 一个 分配 一个 26 个 int 型的 整形数组 a,将 0~25 分别 代表 A~Z 是否 出现,如果 出现则 值为 1,没有出现 值为0.
则 我们 只需 遍历 String1,然后 将 对应的 元素 设置 为1,然后 遍历 String2 ,如果 查找 过程中 ,遇到了 0 值, 则 不是 。否则 String2 的 字母 在 String1 中 都 存在。
哈希表 虽然 快速,但是 其 数据 原型 基于 数组,同样 有缺陷。
当 查找的 元素 集合 太大,不同的 关键字,却 得到 同样的 地址。即 k1 != k2,, F(K1) = = F(K2),这时 叫做 冲突。冲突 是无法避免的。只能 通过一些方法 减少 冲突。当 我们 插入 元素时,寻找 插入位置,造成的 冲突次数 太多,影响查找效率,我们 只能 重新 建表,这是个 费时的过程。
而且 哈希 是 无法 按 从小到 大 遍历 数据的。
所以 我们在 用哈希的时候得考虑这些:
1.哈希函数
2冲突函数
3初始表长
4冲突多少次,我们就重新建表,
5.是否需要 顺序遍历。
下面代码 用的是
哈希函数:除整取余法
冲突函数:开发定址法(线性)
冲突次数 到达 表长的一半 就重新建表。
哈希表基本结构 ,初始化 和销毁
#include "stdafx.h"
#include <cstdlib>
int hashSize[] = {11,13,17,19};//哈希表容量增加 数组.
#define NULL_KEY 0
struct HashTable{
int * base;//数据的基址
int count;//表的数量
int sizeIndex;//表的容量大小的索引
};
void initHash(HashTable * t){
t->sizeIndex =0;
t->base = (int *)calloc(hashSize[t->sizeIndex],sizeof(int));
t->count = 0;
}
void destoryHash(HashTable * t){
free(t->base);
t->base = NULL;
t->sizeIndex = 0;
t->count = 0;
}
//除留余数法
int hash(HashTable t,int key){
return key % hashSize[t.sizeIndex];
}
//开发定址 线性探索解决冲突法
int collision(HashTable t,int key,int times){
return (key + times) % hashSize[t.sizeIndex];
}
int search(HashTable t,int key,int * index,int *ctimes){
*index = hash(t,key);
*ctimes = 0;
while (t.base[*index] != NULL_KEY && t.base[*index] != key){
(*ctimes)++;
*index = collision(t,key,*ctimes);
}
printf("------------查找%d, 查找了%d次--------------\n",key,*ctimes+1);
if (t.base[*index] == key){
return t.base[*index];
}
else{
return NULL_KEY;
}
}
void reCreateHashTable(HashTable * t,int key);
void insertHash(HashTable *t,int key){
int index;//插入位置
int ctimes;//冲突次数
int result = search(*t,key,&index,&ctimes);
if (result == NULL_KEY && ctimes < hashSize[t->sizeIndex]/2){//没找到
t->base[index] = key;
t->count ++;
}
else{//重新建表
reCreateHashTable(t,key);
}
}
//
void reCreateHashTable(HashTable * t,int key){
printf("--------------重建哈希表----------------\n");
int * oldBase = t->base;//保存老空间.
int oldSize = hashSize[t->sizeIndex];//老空间的容量大小
t->sizeIndex++;
int newSize = hashSize[t->sizeIndex];//新空间大小
t->base = (int *) calloc(newSize,sizeof(int));//新空间
//插入之前将 表的数量置0
t->count = 0;
for (int i = 0; i < oldSize; i++){
if (oldBase[i] != NULL_KEY){
insertHash(t,oldBase[i]);
}
}
free(oldBase);//释放老空间
insertHash(t,key);//插入冲突的关键字.
}
static int testArray[10] = {1,18,7,55,23,45,98,76,35,29};
int _tmain(int argc, _TCHAR* argv[])
{
HashTable table;
initHash(&table);
for (int i = 0; i < 10; i++){
insertHash(&table,testArray[i]);
}
int index ,count;
for (int i = 0; i < 10; i++){
search(table,testArray[i],&index,&count);
}
destoryHash(&table);
return 0;
}
原文地址:http://blog.csdn.net/fuming0210sc/article/details/45391349