hashmap c

问题提出:
假如一个结构体,记录有学号,姓名。现在内存块中存在着一批此类结构体。如果已知一个学号,要从这些结构体中找出对应的姓名。
问题解决方法:
如果使用链表保存这些结构体,就要遍历这个链表中的结构体,比较每个结构体的学号成员,如果相等就返回这个结构体,从而得到结构体的姓名成员。
但是遍历效率太低,浪费cpu,有点费电。不如使用hash表直接定位到对应的结构体,而不必遍历。
具体做法见代码。说明如下
1.hash表的构建:除留余数法。
2,冲突处理:开放定址法。如果把hash表大小和元素个数定成一样大小,则一点也不浪费空间。
3.如果预先不知道数组的大小,那几个全局数组可以使用vector代替。
4.这是手工实现的hash表创建,冲突处理。也可以使用boost库的hashmap.待续

the code refer to c/c++ 函数与算法速查手册 陈锐

// hash1.cpp : 定义控制台应用程序的入口点。

#include "stdafx.h"
#include<stdio.h>
#include<malloc.h>
#include<stdlib.h>
#include <string>
typedef struct		/*元素类型定义*/
{
	int value;		/*元素值,学号*/
	int hi;			/*冲突次数*/
	char name[20];
	char sex;
}DataType;
typedef struct		/*哈希表类型定义*/
{
	DataType *data;
	int length;		/*哈希表的长度*/
	int num;		/*表中元素个数*/
}HashTable;
void CreateHashTable(HashTable *H,int m,int n);
int SearchHash(HashTable H,int k);
void HashASL(HashTable H,int m);
void DisplayHash(HashTable H,int m);


int num[]=  {8923,   90,    66,    70,    155,  2456,  123,  987};
char* name[]={"song","rui","lili","mme","feng","ann","tom","min"};
char sex[]={1,2,3,4,5,6,7,8};

int m_TotalLen=99999;
int m_CurLen=8;
int _tmain(int argc, _TCHAR* argv[])
{
	HashTable H;
	int pos,v;
	CreateHashTable(&H,m_TotalLen,m_CurLen);
	DisplayHash(H,m_TotalLen);
	while (1)
	{
		printf("请输入待查找学生的学号:");
		scanf("%d",&v);
		pos=SearchHash(H,v);
		if (pos==-1) continue;

		printf("学号%d在哈希表中的位置:%d,姓名:%s \n",v,pos,H.data[pos].name);

		HashASL(H,m_TotalLen);
	}
	

}
void CreateHashTable(HashTable *H,int m,int n)
/*构造哈希表,并处理冲突*/
{ 
	int i,sum,addr,di;
	/*为哈希表分配存储空间*/
	(*H).data=(DataType*)malloc(m*sizeof(DataType));
	if(!(*H).data)	
		exit(-1); 
	(*H).num=n;			/*初始化哈希表的元素个数*/
	(*H).length=m;		/*初始化哈希表的长度*/

	for(i=0;i<m;i++)	/*初始化哈希表*/
	{
		(*H).data[i].value=-1;
		(*H).data[i].hi=0;
		(*H).data[i].sex=0;
	}

	/*构造哈希表并处理冲突*/
	for(i=0;i<n;i++)
	{
		sum=0;			/*sum记录冲突次数*/
		addr=num[i]%m;	/*利用除留余数法求哈希函数地址*/
		di=addr;
		if((*H).data[addr].value==-1)	/*如果不冲突则将元素存储在表中*/
		{
 			(*H).data[addr].value=num[i];
			(*H).data[addr].hi=1;
			strcpy((*H).data[addr].name,name[i]);
			(*H).data[addr].sex=sex[i];

		}
		else			/*用线性探测再散列法处理冲突*/
		{
			do 
			{
				di=(di+1)%m;
				sum+=1;
			} while((*H).data[di].value!=-1);

			(*H).data[di].value=num[i];
			(*H).data[di].hi=sum+1;
			strcpy((*H).data[di].name,name[i]);
			(*H).data[di].sex=sex[i];

		}
	}
}
int SearchHash(HashTable H,int v)
/*在哈希表H中查找值为v的元素*/
{
	int d,d1,m;
	m=H.length;
	d=d1=v%m;				/*求v的哈希地址*/
	while(H.data[d].value!=-1)
	{
		if(H.data[d].value==v)	/*如果找到要查找的元素v,则返回v的位置*/
			return d;
		else					/*如果不是要找的元素,则继续向后查找*/
			d=(d+1)%m;
		if(d==d1)				/*如果找遍了哈希表中的所有位置还没有找到v,则返回0*/
			return -1;
	}
	return -1;					/*该位置不存在元素v*/
}
void HashASL(HashTable H,int m)
/*求哈希表的平均查找长度*/
{
	float average=0;
	int i;
	for(i=0;i<m;i++)
		average=average+H.data[i].hi;
	average=average/H.num;
	printf("平均查找长度ASL:%.2f",average);
	printf("\n");  
}
void DisplayHash(HashTable H,int m)
/*输出哈希表*/
{
	int i;
	printf("哈希表地址:  ");
	for(i=0;i<m;i++)		/*输出哈希表的地址*/
		printf("%-5d",i);
	printf("\n");
	printf("元素值value: ");
	for(i=0;i<m;i++)		/*输出哈希表的元素值*/
		printf("%-5d",H.data[i].value);
	printf("\n");
	printf("冲突次数:    ");
	for(i=0;i<m;i++)		/*冲突次数*/
		printf("%-5d",H.data[i].hi);

	printf("\n");
	printf("性别:        ");
	for(i=0;i<m;i++)		
		printf("%-5d",H.data[i].sex);

	printf("\n");
	printf("name:      ");
	for(i=0;i<m;i++)		
		printf("%s  ",H.data[i].name);

	printf("\n");
}


posted on 2012-10-20 07:36  _song  阅读(366)  评论(0编辑  收藏  举报