散列ADT的实现(C语言数组)

本文介绍了如何使用C语言实现开放定址法和分离链接法的哈希表,包括初始化、查找、插入和删除操作的代码示例。
摘要由CSDN通过智能技术生成

分离链接法部分代码:

#include<stdio.h>
#include<stdlib.h>
#define MINTABLESIZE 5

//结构体定义
struct ListNode //链表的节点定义
{
	int element;
	struct ListNode* next;
};

struct HashTbl //哈希表定义
{
	int tablesize; //哈希表的大小
	struct ListNode** thelists;  //thelists为指向链表节点ListNode的指针的指针 
};

//初始化操作
struct HashTbl* InitializeTable(int tablesize)
{
	struct HashTbl* H;

	if (tablesize < MINTABLESIZE) //定义的哈希表太小
	{
		printf("Table size too small!");
		return NULL;
	}

	H = (struct HashTbl*)malloc(sizeof(struct HashTbl)); //为哈希表分配空间
	if (H == NULL)
	{
		printf("Out of space!");
		return NULL;
	}

	H->tablesize = NextPrime(tablesize); //哈希表长度应当选择素数

	H->thelists = (struct ListNode**)malloc(sizeof(struct ListNode*) * H->tablesize);
	if (H->thelists == NULL)
	{
		printf("Out of space!");
		return NULL;
	}

	for (int i = 0; i < H->tablesize; i++) //为指向ListNode的指针分配空间
	{
		H->thelists[i] = (struct ListNode*)malloc(sizeof(struct ListNode)); //每一个指针指向ListNode节点

		if (H->thelists[i] == NULL)
		{
			printf("Out of space!");
			return NULL;
		}
		else
			H->thelists[i]->next = NULL;
	}

	return H;
}

//查找操作
struct ListNode* Find(int key, struct HashTbl* H)
{
	struct ListNode* p; //p指向查找的元素所在节点
	struct ListNode* loc; //loc指向链表头结点

	loc = H->thelists[Hash(key, H->tablesize)];

	p = loc->next; 
	while (p != NULL && p->element != key)
	{
		p = p->next;
	}
	return p;
}

//插入操作
void Insert(int key, struct HashTbl* H)
{
	struct ListNode* pos;

	pos = Find(key, H);
	if (pos == NULL) //未找到时插入
	{
		struct ListNode* newlistnode = (struct ListNode*)malloc(sizeof(struct ListNode)); //要插入的新节点
		if (newlistnode == NULL)
		{
			printf("Out of space!");
		}
		else
		{
			struct ListNode* loc = H->thelists[Hash(key, H->tablesize)]; //要插入队列的头结点
			newlistnode->element = key;
			newlistnode->next = loc->next;
			loc->next = newlistnode;  //在队头插入
		}
	}
}

开放定址法完整代码:

#include<stdio.h>
#include<stdlib.h>
#include<math.h>
#define MAXTABLESIZE 999 //允许开辟的最大散列表长度

typedef enum { Legitimate, Empty, Deleted } EntryType; //合法元素、空单元、有已删除元素

//散列表单元类型
struct HashEntry
{
	int Data; //存放元素
	EntryType Info; //单元状态
};

//散列表结点定义
struct TblNode 
{
	int TableSize; //表的最大长度
	struct HashEntry* Cells; //存放散列单元数据的数组
};

//哈希函数
int Hash(int key, int TableSize) //除留余数法
{
	return key % TableSize;
}

//返回大于N且不超过MAXTABLESIZE的最小素数
int NextPrime(int N)
{
	int i, p = (N % 2) ? N + 2 : N + 1; //从大于N的下一个奇数开始

	while (p <= MAXTABLESIZE)
	{
		for (i = (int)sqrt(p); i > 2; i--)
		{
			if (!(p % i)) //p不是素数
			{
				break;
			}
		}
		if (i == 2) //for正常结束,说明p是素数
		{
			break;
		}
		else //否则试探下一个奇数
		{
			p += 2;
		}

	}

	return p;
}

//初始化操作
struct TblNode* CreateTable(int TableSize)
{
	struct TblNode* H;
	int i;

	H = (struct TblNode*)malloc(sizeof(struct TblNode));
	if (H == NULL)
	{
		printf("空间溢出!!!\n");
		return NULL;
	}

	H->TableSize = NextPrime(TableSize); //保证散列表最大长度是素数

	H->Cells = (struct HashEntry*)malloc(H->TableSize * sizeof(struct HashEntry)); //声明单元数组
	if (H->Cells == NULL)
	{
		printf("空间溢出!!!\n");
		return NULL;
	}

	for (i = 0; i < H->TableSize; i++) //初始化单元状态为“空单元”
		H->Cells[i].Info = Empty;

	return H;
}

//查找操作
int Find(struct TblNode* H, int Key)
{
	int CurrentPos, NewPos;
	int CNum = 0; //记录冲突次数

	NewPos = CurrentPos = Hash(Key, H->TableSize); //初始散列位置

	while (H->Cells[NewPos].Info != Empty && H->Cells[NewPos].Data != Key)//当该位置的单元非空,并且不是要找的元素时,发生冲突
	{
		if (++CNum % 2) //奇数次冲突
		{
			NewPos = CurrentPos + (CNum + 1) * (CNum + 1) / 4; //增量为+[(CNum+1)/2]^2

			if (NewPos >= H->TableSize)
				NewPos = NewPos % H->TableSize; //可能超出表大小,调整为合法地址
		}
		else //偶数次冲突
		{
			NewPos = CurrentPos - CNum * CNum / 4; //增量为-(CNum/2)^2

			while (NewPos < 0)
				NewPos += H->TableSize;	//可能超出表大小,调整为合法地址
		}
	}

	return NewPos; //此时NewPos或者是Key的位置,或者是一个空单元的位置(表示找不到)
}

//插入操作
bool Insert(struct TblNode* H, int Key)
{
	int Pos = Find(H, Key); //先检查Key是否已经存在

	if (H->Cells[Pos].Info != Legitimate) //如果这个单元没有被占,说明Key可以插入在此
	{
		H->Cells[Pos].Info = Legitimate;
		H->Cells[Pos].Data = Key;

		return true;
	}
	else
	{
		printf("键值已存在\n");
		return false;
	}
}

//删除操作
bool Delete(struct TblNode* H, int Key)
{
	int Pos = Find(H, Key); //先检查Key是否已经存在
	if (H->Cells[Pos].Info == Legitimate) //如果这个单元没有被占,说明Key可以插入在此
	{
		H->Cells[Pos].Info = Deleted;
		return true;
	}
	else
	{
		printf("键值不存在\n");
		return false;
	}
}

//打印散列中的元素
void printHash(struct TblNode* H)
{
	for (int i = 0; i < H->TableSize; i++)
	{
		if (H->Cells[i].Info == Legitimate)
		{
			printf("Cell[%d]:%d\n", i, H->Cells[i].Data);
		}
	}
}


//主函数
int main()
{
	int a[] = { 47, 27, 29, 30, 29, 66 };
	int lena = sizeof(a) / sizeof(a[0]); //元素个数

	struct TblNode* tab = CreateTable(10);

	printf("表的大小:TableSize=%d\n", tab->TableSize);
	printf("===================================\n\n");

	for (int i = 0; i < lena; i++)
	{
		Insert(tab, a[i]);
	}

	printHash(tab);
	printf("===================================\n");

	Delete(tab, 30);
	printHash(tab);

	return 0;
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值