c实现哈希查找

100 篇文章 8 订阅
20 篇文章 0 订阅

哈希查找,也称为散列查找(本文以哈希称呼)。哈希它是由一组key/value的键值对组成的集合,它就是应用了散列技术。

那么,什么是哈希查找呢?在弄清楚什么是哈希查找之前,我们要弄清楚哈希技术,哈希技术是在记录的存储位置和记录的关键字之间建立一个确定的对应关系f,使得每个关键字key对应一个存储位置f(key)。查找时,根据这个确定的对应关系找到给定值的映射f(key),若查找集合中存在这个记录,则必定在f(key)的位置上。哈希技术既是一种存储方法,也是一种查找方法。

六种哈希函数的构造方法:

1,直接定址法:

函数公式:f(key)=a*key+b (a,b为常数)

这种方法的优点是:简单,均匀,不会产生冲突。但是需要事先知道关键字的分布情况,适合查找表较小并且连续的情况。

2,数字分析法:

比如我们的11位手机号码“136XXXX7887”,其中前三位是接入号,一般对应不同运营公司的子品牌,如130是联通如意通,136是移动神州行,153是电信等。中间四们是HLR识别号,表示用户归属地。最后四们才是真正的用户号。

若我们现在要存储某家公司员工登记表,如果用手机号码作为关键字,那么极有可能前7位都是相同的,所以我们选择后面的四们作为哈希地址就是不错的选择。

3,平方取中法:

故名思义,比如关键字是1234,那么它的平方就是1522756,再抽取中间的3位就是227作为哈希地址。

4,折叠法:

折叠法是将关键字从左到右分割成位数相等的几个部分(最后一部分位数不够可以短些),然后将这几部分叠加求和,并按哈希表表长,取后几位作为哈希地址。

比如我们的关键字是9876543210,哈希表表长三位,我们将它分为四组,987|654|321|0 ,然后将它们叠加求和987+654+321+0=1962,再求后3位即得到哈希地址为962,哈哈,是不是很有意思。

5,除留余数法:

函数公式:f(key)=key mod p (p<=m)m为哈希表表长。

这种方法是最常用的哈希函数构造方法。

6,随机数法:

函数公式:f(key)= random(key)。

这里random是随机函数,当关键字的长度不等是,采用这种方法比较合适。

两种哈希函数冲突解决方法:

我们设计得最好的哈希函数也不可能完全避免冲突,当我们在使用哈希函数后发现两个关键字key1!=key2,但是却有f(key1)=f(key2),即发生冲突。

方法一:开放定址法:

开放定址法就是一旦发生了冲突,就去寻找下一个空的哈希地址,只要哈希表足够大,空的哈希地址总是能找到,然后将记录插入。这种方法是最常用的解决冲突的方法。

方法二:链地址法:

//采用除数取留法确定地址,利用线性开放地址法处理冲突问题,2016.5.28
#include <stdio.h>
#include <stdlib.h>
#include <io.h>
#include <math.h>
#include<time.h>

#define HASHSIZE 15
#define NULLKEY -32768

typedef struct
{
	int *elem; //数据元素存储地址
	int count;//当前元素个数
}HashTable;
int L = 0; //表的长度

bool init(HashTable *hashTable)//哈希表的初始化
{
	int i;
	L = HASHSIZE;
	hashTable->elem = (int*)malloc(L*sizeof(int));//申请内存
	hashTable->count = L;
	for (i = 0; i < L; i++)
	{
		hashTable->elem[i]=NULLKEY;
	}
	return true;
}

//哈希函数,除留余数法,最常用的哈希函数,还有其它的。
int Hash(int data)
{
	return data%L;
}

void insert( HashTable *hashTable, int data)
{
	int Addr = Hash(data);//求哈希地址
	while (hashTable->elem[Addr] != NULLKEY)//求得地址不是初始化时的空,则表示有元素已经插入,会有冲突
	{
		Addr = (Addr + 1) % L;//开放地址线性探测,还可以二次探测
	}
	hashTable->elem[Addr] = data;
}

int  find(HashTable *hashTable, int data)
{
	int Addr = Hash(data);
	while (hashTable->elem[Addr] != data)
	{
		Addr = (Addr + 1) % L;
		if (hashTable->elem[Addr] == NULLKEY || Addr == Hash(data))
			return 0;
	}
	return Addr;
}

void display(HashTable *hashTable)
{
	int i;
	printf(".........结果展示.........\n");
	for (i = 0; i < hashTable->count; i++)
	{
		printf("%d\n", hashTable->elem[i]);
	}
}

void main()
{
	int i, j, result, x;
	HashTable hashTable;
	int arr[HASHSIZE];
	printf("请输入少于15个,初始化哈希表的元素:\n");
	for (j = 0; j < HASHSIZE; j++)
	{
		scanf("%d", &arr[j]);
	}
	init(&hashTable);
	for (i = 0; i < HASHSIZE; i++)
	{
		insert(&hashTable, arr[i]);
	}
	display(&hashTable);
	printf("请输入你要查找的元素:\n");
	scanf("%d", &x);
	result = find(&hashTable, x);
	if (result)
		printf("查找元素%d在哈希表中的位置为%d\n",x,result);
	else 
		printf("没找到!\n");
	system("pause");
}



评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值