码迷,mamicode.com
首页 > 其他好文 > 详细

看数据结构写代码(61) 哈希表

时间:2015-04-30 12:42:19      阅读:151      评论:0      收藏:0      [点我收藏+]

标签:哈希表   哈希表c语言描述   

前面说的 各种查找都是 基于 “比较” 的基础 来进行 查找的。查找的 效率 要 看 比较的 次数。那么 有没有 不需要 比较,就可以 找到 想要的数据的 方法呢?

哈希表 就是 这样的 一种方法,它用  数组 作为 保存 关键字的 数据原型,通过 一个 哈希 函数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://pan.baidu.com/s/1kToXLcj






看数据结构写代码(61) 哈希表

标签:哈希表   哈希表c语言描述   

原文地址:http://blog.csdn.net/fuming0210sc/article/details/45391349

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!