C语言实现哈希表(开放地址法)

笔者最近学习数据结构中的哈希表,并用C语言简单实现了。
此博客旨在交流心得。

这篇博客介绍的是开放地址法构造的哈希表

哈希表原理可以参考这篇文章:哈希表原理介绍

如果要参考拉链法构造的哈希表,请参考这篇文章:C语言实现哈希表(拉链法)

结构体说明

typedef struct element
{
	int key;		// key值  唯一不重复 
	int data;		// data 域  
}Element;

其中data域可以改为自定义的结构体(当然后续 main函数 部分代码需要做相应修改)
key 值经由哈希函数的计算会得到一个映射的地址

typedef struct table
{
	Element **elm;	//  
	int count;		// 记录表中记录的数据个数 
	int size;	// 哈希表的大小 = SIZE = 50
}Table;

注意:elm 为一个指向 Element结构体的指针数组 的指针(请好好理解),即创建了一个 Element 类型的指针数组,而 elm 指向这个数组的头地址 故声明为二级指针(指向指针的指针) 。

部分函数说明:
创建哈希表函数:

Table * init_Table()
{
	Table *t = (Table*)malloc(sizeof(Table));
	t->size = REMAINDER;
	t->count = 0;
	t->elm = (Element **)malloc(SIZE*sizeof(Element*));
	/*
	创建一个长度为13的指针数组,类型为Element*
	并将数组头地址赋值给 elm 的二级指针 
	*/ 
	int i;
	for(i=0 ; i<t->size ; i++)
	{
		t->elm[i] = NULL;	// 将数组的每个域赋空 
	}	
	return t;
}

声明 Table 类型的变量,为其开辟空间,并返回其地址。

在初始化时,对指针类型的变量要注意初始化(有的编译器会帮你赋空,有的则不会)

插入函数

void Insert(Table *t,Element * k)		//将key值插入到哈希表中 
{
	int i;
	int position;
	position = hash(k->key);
	
	for(i=1 ; t->elm[position]!=NULL && i<t->size ;i++ )
	{
		position=(hash(position)+i)%t->size;
	}
	t->elm[position] = k;	
	t->count += 1;
	return ;
}

开放地址法的一般形式为:
其中 H(key)是哈希函数,m为表的长度
此种方法容易造成堆积。解决方法是改进哈希函数或用使用拉链法(各有优劣)。

查找函数:

int serch(Table *t, Element * k)		//查找 value 并返回其所在的地址 
{
	int position=hash(k->key);
	while(t->elm[position]->key != k->key)
	{
		position = hash(position+1);
		if(t->elm[position]==NULL || position == hash(k->key))
		/*
		出现以下几种情况即判断查找失败
		1.对应的 position 位置的地址为空 
		2.遍历整个表都没有对应的 key 值 
		*/ 
		return -1;
	}
	
	return position;	
}

出现以下几种情况即判断查找失败
1.对应的 position 位置的地址为空
2.遍历整个表都没有对应的 key 值

完整代码:

#include<stdio.h>
#include<stdlib.h>
#define REMAINDER 13
#define SIZE 50 

typedef struct element
{
	int key;		// key值  唯一不重复 
	int data;		// data 域  
}Element;

typedef struct table
{
	Element **elm;	//  
	int count;		// 记录表中记录的数据个数 
	int size;	// 哈希表的大小 = SIZE = 50
}Table;

int hash(int key)
{
	return key%REMAINDER;	
}

Table * init_Table()
{
	Table *t = (Table*)malloc(sizeof(Table));
	t->size = SIZE;
	t->count = 0;
	t->elm = (Element **)malloc(SIZE*sizeof(Element*));
	/*
	创建一个长度为13的指针数组,类型为Element* 
	并将数组头地址赋值给 elm 的二级指针 
	*/ 
	int i;
	for(i=0 ; i<t->size ; i++)
	{
		t->elm[i] = NULL;	// 将数组的每个域赋空 
	}	
	return t;
}

void Insert(Table *t,Element * k)		//将key值插入到哈希表中 
{
	int i=0;
	int position;
	position = hash(k->key);
	
	for(i=1 ; t->elm[position]!=NULL && i<t->size ;i++ )
	{
		position=(hash(position)+i)%t->size;
	}
	t->elm[position] = k;	
	t->count += 1;
	return ;
}

int serch(Table *t, Element * k)		//查找 value 并返回其所在的地址 
{
	int position=hash(k->key);
	while(t->elm[position]->key != k->key)
	{
		position = hash(position+1);
		if(t->elm[position]==NULL || position == hash(k->key))
		/*
		出现以下几种情况即判断查找失败
		1.对应的 position 位置的地址为空 
		2.遍历整个表都没有对应的 key 值 
		*/ 
		return -1;
	}
	
	return position;	
}


void Print_Table(Table *t)		//打印部分哈希表 
{
	int i;
	for(i=0 ; i<13 ; i++)
	{
		if(t->elm[i])
		printf("[%d %d] ",t->elm[i]->key , t->elm[i]->data);
		else printf("NULL ");
	}	
	printf("\n");
}

int main()
{
	Table *t = init_Table();
	
	Element a[]={{12,99},{13,98},{26,87},{14,77},{15,100},{10,59}};
	int length = sizeof(a)/sizeof(Element);
	
	int i;
	for(i=0 ; i<length ; i++)
	{
		Insert(t,&a[i]);
	}
	Print_Table(t);
	printf("a[3] is locat %d\n",serch(t,&a[3]));
	free(t);
}


运行截图:
在这里插入图片描述

谢谢观看~

  • 9
    点赞
  • 36
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
实现代码及其原理如下: 原理: 哈希表开放地址法,是一种处理哈希碰撞(哈希冲突)的方法。刚开始时,哈希表中全部元素都未被占用,当要将一个新元素添加到哈希表中时,通过哈希函数计算其所对应的哈希地址,如果该地址已经被占用,就继续往下查找,直到找到一个空的地址为止。 实现代码: #include <stdio.h> #include <stdlib.h> #include <string.h> #define HASHSIZE 12 // 定义哈希表数组长度为12 #define NULLKEY -32768 // 定义空关键字,同时也可以做删除标记 typedef struct { int key; // 关键字 } DataNode; // 数据节点类型 DataNode HashTable[HASHSIZE]; // 定义哈希表数组 // 初始化哈希表 void InitHashTable() { for (int i = 0; i < HASHSIZE; ++i) { HashTable[i].key = NULLKEY; // 将哈希表中全部元素的关键字初始化为NULLKEY } } // 散列函数 int Hash(int key) { return key % HASHSIZE; // 除留余数法 } // 插入元素 void InsertElement(int key) { int hashVal = Hash(key); // 计算key的哈希地址 while (HashTable[hashVal].key != NULLKEY) // 如果该地址已被占用 { // 线性探测,继续往下查找 hashVal = (hashVal + 1) % HASHSIZE; } HashTable[hashVal].key = key; // 将新元素插入哈希表 } // 查找元素 void SearchElement(int key) { int hashVal = Hash(key); // 计算key的哈希地址 while (HashTable[hashVal].key != key) // 未找到时继续查找 { if (HashTable[hashVal].key == NULLKEY) { printf("该关键字不存在!\n"); // 哈希表中没有该元素,退出查找 return; } // 线性探测,继续往下查找 hashVal = (hashVal + 1) % HASHSIZE; } printf("该元素的位置是:%d\n", hashVal); // 找到该元素,输出其在哈希表中的位置 } // 删除元素 void DeleteElement(int key) { int hashVal = Hash(key); // 计算key的哈希地址 while (HashTable[hashVal].key != key) // 未找到时继续查找 { if (HashTable[hashVal].key == NULLKEY) { printf("该关键字不存在!\n"); // 哈希表中没有该元素,退出删除 return; } // 线性探测,继续往下查找 hashVal = (hashVal + 1) % HASHSIZE; } HashTable[hashVal].key = NULLKEY; // 将该元素标记为NULLKEY,即删除该元素 } int main() { InitHashTable(); // 初始化哈希表 InsertElement(56); // 插入元素 InsertElement(22); InsertElement(37); InsertElement(15); InsertElement(23); InsertElement(24); printf("输入要查找的数据:"); int key; scanf("%d", &key); SearchElement(key); // 查找元素 printf("输入要删除的数据:"); scanf("%d", &key); DeleteElement(key); // 删除元素 return 0; }
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值