数据结构——哈希表

哈希表(Hash table,也叫散列表),是根据关键码值(Key value)而直接进行访问的数据结构。也就是说,它通过把关键码值映射到表中一个位置来访问记录,以加快查找的速度。它可以用O(1)的复杂度进行数据的插入删除和查找,但是 hash 表不保证表中数据的有序性,这样在 hash 表中查找最大数据或者最小数据的时间是 O(N) 。网上有很多关于怎么映射和处理冲突,我觉得掌握以下两种基本就可以了:

1.除留余数法:

取关键字被某个不大于散列表表长m的数p除后所得的余数为散列地址。即 H(key) = key MOD p,p<=m。不仅可以对关键字直接取模,也可在折叠、平方取中等运算之后取模。对p的选择很重要,一般取素数或m,若p选的不好,容易产生同义词。

2.链地址法(拉链法):

当存储结构是链表时,多采用拉链法,用拉链法处理冲突的办法是:把具有相同散列地址的关键字(同义词)值放在同一个单链表中,称为同义词链表。有m个散列地址就有m个链表,同时用指针数组T[0..m-1]存放各个链表的头指针,凡是散列地址为i的记录都以结点方式插入到以T[i]为指针的单链表中。T中各分量的初值应为空指针。

这个博客写的很好:还有一些高级算法

除留余数法:

#include<stdio.h>
#include<string.h>
#include<stdlib.h>
#define hashsize 32		

char *keywords[] = {
	"auto", "break", "case", "char", "const", "continue", "default","do",
	"double", "else", "enum", "extern", "float", "for", "goto","if",
	"int", "long", "register", "return", "short", "signed", "sizeof","static",
	"struct", "switch", "typedef", "union", "unsigned", "void", "volatile","while"
};
char keybuf[hashsize][100];
bool flag[hashsize];	//标志已经被占用的存储单位

void ClearFlag()	//清空标志
{
	for (int i = 0; i < hashsize; i++)
		flag[i] = true;
}

int Hash(char s[])
{
	int val,count=0;
	for (val = 0; *s != '\0'; s++)
		val = *s + (hashsize - 1)*val;	//计算下标,除留余数法取素数或size产生的冲突比较少
	val = val%hashsize;
	while (!flag[val] && count < hashsize)
	{
		count++;			//count记录已经冲突后寻找其他下标还冲突的个数
		val = (val + count) % hashsize;  //处理冲突,使用开放寻址法
	}
	if (count < hashsize)	//如果count=hashsize说明所有的位置都有冲突
	{
		return val;
	}
	return -1;
}

int main()
{
	int i, size, pos;
	size = sizeof(keywords) / sizeof(keywords[0]);//计算有几个关键字
	ClearFlag();
	for (i = 0; i < size; i++)
		strcpy(keybuf[Hash(keywords[i])], keywords[i]);//hash寻找下标并复制存储
	ClearFlag();
	for (i = 0; i < size; i++)
	{
		pos = Hash(keywords[i]);
		printf("%-10s:%-3d\n", keybuf[pos], pos);
	}
	return 0;
}


posted @ 2016-04-28 17:41  seasonal  阅读(178)  评论(0编辑  收藏  举报