散列表的C语言实现-分离链接法

一:散列表的定义:

散列表的实现常常叫做散列,散列是一种用于以常数平均时间执行插入,查找,删除的技术,但是,那些需要元素间任何排序信息的操作将不会得到支持,如findmin,findmax等等。散列表的优点很明显,它的查询时间为常数,速度非常快,缺点就是元素间没有排序,对于一些需要排序的场合不适用。理想的散列表数据结构就是一个包含有关键字的具有固定大小的数组,用一个散列函数来跟据关键字的值来将关键字插入到表中。这是散列的基本想法,剩下的问题是要选择一个好的散列函数,当俩个关键字散列到同一个值得时候应当如何应对以及如何确定散列表的大小。

二:选择散列函数:

1.如果输入的关键字是整数,一般的方法就是直接返回key mod tablesize;(hashval=key%tablesize;),tablesize的选择最好是素数,这是因为素数没有其他的约数。如果表的大小为10这样的数,如果关键字是以0为各位,那所有的关键字都会映射到同一位置。

2.一般散列的关键字是字符串。

一种散列函数是将字符串所有的字符的ASCII码相加。但是由于ASCII最大值只有127,所以可以映射的范围不够大。

还有一种是这样:

它假设key至少有俩个字符外加一个NULL符,它只考虑前三个字符,如果他们是随机的,那这个函数在小范围内是可以均匀分配关键字的,但是真实使用中英文字母不是随机的。所以当散列表足够大时这个函数还是不合适的。

还有一种是这样的:

这个函数一般可以分配的很好。

分离链接法:

分离连接法一种简单的散列表实现方式。做法是将散列到同一个位置的所有值

都保存到一个链表中。实现方法也比较简单,很多操作都是链表的操作。

头文件:

#ifndef __HASHTABLE_H
#define __HASHTABLE_H

/****************分离链表法************************/

struct ListNode;
typedef struct ListNode *position;
typedef position list;
struct HashTable;
typedef struct HashTable *hashTable;
typedef int ElementType;
#define MINTABLESIZE 5
#define MAXTABLESIZE 20

hashTable initializeTable(int tablesize);
void destroyTable(hashTable H);
position find(ElementType key,hashTable H);
ElementType retrieve(position p);
int nextPrime(int tableSize);
int isPrime(int x);
void insert(ElementType key,hashTable H);
int Hash(ElementType key,int tableSize);
int Delete(ElementType key,hashTable H);

struct ListNode
{
	ElementType element;
	position next;
};

struct HashTable
{
	int tableSize;
	list *thelists;	//指向ListNode的指针的指针
};

/**************************************************/
#endif

实现文件:

#include "HashTable.h"
#include <stdio.h>
#include <stdlib.h>

/***************************分离链表法****************************/

/*构造出了一个指针数组,数组的每一个元素都指向一个链表*/

hashTable initializeTable(int tableSize)
{
	hashTable H;
	int i;

	if(tableSize<MINTABLESIZE)
	{
		printf("table is too small!\n");
		return NULL;
	}
	H=(struct HashTable*)malloc(sizeof(struct HashTable));
	if(H==NULL)
	{
		printf("out of space\n");
		return NULL;
	}
	H->tableSize=nextPrime(tableSize);	//11

	//创建指针数组
	H->thelists=malloc(sizeof(list)*H->tableSize);	//指针数组,数组里不放数据,数据放在链表里

	if(H->thelists==NULL)
	{
		printf("out of space!\n");
		return NULL;
	}
	//创建指针数组元素指向的链表表头
	for(i=0;i<H->tableSize;i++)
	{
		H->thelists[i]=(struct ListNode*)malloc(sizeof(struct ListNode));
		if(H->thelists[i]==NULL)
		{
			printf("out of space!\n");
			return NULL;
		}
		else
			H->thelists[i]->next=NULL;
	}
	return H;
}

int nextPrime(int tableSize)
{
	while(1)
	{
		if(isPrime(tableSize))
			return tableSize;
		else
			tableSize++;
	}
}
int isPrime(int x)
{
	int i;
	for(i=2;i*i<=x;i++)
	{
		if(x%i==0)
			return 0;
	}
	return 1;
}

void destroyTable(hashTable H)
{
	position h,p,q;
	int i;
	for(i=0;i<H->tableSize;i++)
	{
		h=H->thelists[i];
		p=h->next;
		while(p)
		{
			q=p->next;
			if(!q)
			{
				free(p);
				p=NULL;
			}
			else
			{
				free(p);
				p=q;
			}
		}
	}
}

position find(ElementType key,hashTable H)
{
	position p;
	list L;

	L=H->thelists[Hash(key,H->tableSize)];
	p=L->next;
	while(p)
	{
		if(p->element==key)
			return p;
		p=p->next;
	}
	return NULL;
}

void insert(ElementType key,hashTable H)
{
	position pos,newcell;
	list L;

	pos=find(key,H);
	if(pos==NULL)	//错把pos=null当作判断条件,此条件永远为真。
	{
		newcell=(struct ListNode*)malloc(sizeof(struct ListNode));
		if(newcell==NULL)
		{
			printf("out of space\n");
			exit(-1);
		}
		else
		{
			L=H->thelists[Hash(key,H->tableSize)];
			newcell->next=L->next;
			newcell->element=key;
			L->next=newcell;
		}
	}
}

int Hash(ElementType key,int tableSize)
{
	return key%tableSize;
}

int Delete(ElementType key,hashTable H)
{
	position pos,h,L;
	L=H->thelists[Hash(key,H->tableSize)];
	h=L->next;
	while(h!=NULL&&h->next&&h->next->element!=key)
		pos=pos->next;
	if(h==NULL)
	{
		printf("cant find that key!\n");
		return 0;
	}
	else
	{
		pos=h->next;
		h->next=pos->next;
		free(pos);
		return 1;
	}
}

ElementType retrieve(position p)
{
	return p->element;
}

测试:

#include "HashTable.h"
#include <stdio.h>

int main()
{

/********************散列分离链接法测试****************************/
/*	hashTable table;
	position p;

	table=initializeTable(10);

	insert(0,table);
	insert(1,table);
	insert(81,table);
	insert(4,table);
	insert(64,table);
	insert(25,table);
	insert(16,table);
	insert(36,table);
	insert(9,table);
	insert(49,table);

	p=find(81,table);
	if(p==NULL)
		printf("cant find 1\n");
	else
		printf("find %d \n",p->element);

	if(Delete(81,table))
	{
		printf("Delete 81\n");
	}

	p=find(81,table);
	if(p==NULL)
		printf("cant find 81\n");
	else
		printf("find %d \n",p->element);

	destroyTable(table);

版权声明:本文为博主原创文章,未经博主允许不得转载。

时间: 2024-10-24 20:19:07

散列表的C语言实现-分离链接法的相关文章

数据结构与算法——散列表类的C++实现(分离链接散列表)

散列表简介: 散列表的实现常被称为散列.散列是一种用于以常数平均时间执行插入.删除和查找的技术. 散列的基本思想: 理想的散列表数据结构只不过是一个包含一些项的具有固定大小的数组.(表的大小一般为素数) 设该数组的大小为TbaleSize,我们向该散列表中插入数据,首先我们将该数据用一个函数(散列函数)映射一个数值x(位于0到TbaleSize1-1之间):然后将该数据插入到散列表的第x的单元.(如果有多个数据映射到同一个数值,这个时候就会发生冲突) 散列函数介绍: 为了避免散列函数生成的值不是

散列表的C语言实现-开放定址法

头文件: #ifndef __HASHTABLE_H #define __HASHTABLE_H /*********************(平方)开放定址散列法***************/ //如果有冲突发生,那么就尝试另外的单元,直到找到空的单元为止 typedef unsigned int index; typedef index position; typedef int ElementType; #define MINTABLESIZE 5 struct hashTable; t

分离链接法实现散列表

散列表是一种用于查找的数据结构.其基本思想来自于索引,也可以看成是数组的一种扩展.对于一些数据信息,比如说图片文件名,如果我们要查找某张图片,通常将图片名作为关键字进行搜索.这个时候是不可能把图片名直接当成数组下标的,因此可以将图片名关键字通过某个函数映射为某个地址,或地址偏移量.那么每次要查找图片的时候直接输入关键字就能直接计算得出存储地址.其定义 T=h(k) 其中k为关键字,h为映射函数,T为得到的散列表,得到的函数值为地址或地址偏移量. 如果不同关键字通过某函数得到的散列值(地址偏移量)

[C++]实现散列表的分离链接法的数据结构

散列表,英文叫做Hash Table,因此也叫哈希表,是一种根据关键字值来确定主存中存储位置的数据结构.通过一个散列函数(关于键值的函数),来确定存储该关键字的位置. 主要的方法有: 1.分离链接法(拉链法) 分离链接法的散列函数为 position = key % n. 即关键字的存储位置为关键字的值对表项的数量取模.若表项大小为13,对于关键值为27的项,存储在1(27 % 13 = 1)的表项处.为了减少冲突,n往往取素数.对于同余的关键字,采用 队列(链表) 的方式连接在一起,新放入的元

数据结构--解决散列冲突,分离链接法

散列表的实现经常叫做散列. 散列是一种用以常数平均时间运行插入.删除,和查找的技术.可是那些须要元素信息排序的树操作不会得到支持. 因此比如findMax,findMin以及排序后遍历这些操作都是散列不支持的. 假设当一个元素被插入时与已经插入的元素散列(比方散列表的数组序号,非常多元素插入到同一个数组序号中).那么就会产生一个冲突,这个冲突须要消除.解决冲突的办法有两种: 1 分离链接法 2  开放定址法(包含线性探測,平方探測,双散列) 两者都有可能须要再散列 以下说明分离链接法,上代码:

散列之分离链接法

1 #include <vector> 2 #include <list> 3 #include <string> 4 #include <algorithm> 5 using std::vector; 6 using std::list; 7 using std::string; 8 using std::find; 9 10 int hash(const string &key) 11 { 12 int hashVal = 0; 13 14 fo

数据结构--散列(分离链接法解决冲突)

散列方法的主要思想是根据结点的关键码值来确定其存储地址:以关键码值K为自变量,通过一定的函数关系h(K)(称为散列函数),计算出对应的函数值来,把这个值解释为结点的存储地址,将结点存入到此存储单元中.检索时,用同样的方法计算地址,然后到相应的 单元里去取要找的结点.通过散列方法可以对结点进行快速检索.散列(hash,也称"哈希")是一种重要的存储方式,也是一种常见的检索方法. 因此,散列函数更像是一种映射,散列函数的选择有很多种,下面以散列函数为关键值对10取余为例,说明散列的插入关键

解决hash冲突之分离链接法

解决hash冲突之分离链接法 分离链接法:其做法就是将散列到同一个值的所有元素保存到一个表中. 这样讲可能比较抽象,下面看一个图就会很清楚,图如下 相应的实现可以用分离链接散列表来实现(其实就是一个linkedList数组) 至于基本的增加.删除和查询的思路都是先根据散列函数来确定遍历哪个链表.然后再到被确定的链表中执行一次查找,然后再进行相应的操作. 接下来就讲几个注意点吧 (一)什么时候需要rehash来扩大散列表的大小 讲这个的时候,先介绍一下什么是装填因子. 装填因子 = 关键字个数 /

习题5.11 分离链接法的删除操作函数 (20分)

试实现分离链接法的删除操作函数. 函数接口定义: bool Delete( HashTable H, ElementType Key ); 其中HashTable是分离链接散列表,定义如下: typedef struct LNode *PtrToLNode; struct LNode { ElementType Data; PtrToLNode Next; }; typedef PtrToLNode Position; typedef PtrToLNode List; typedef struc