在这个静态哈希表中
我们用一个容量为10 的静态数组作为哈希表的底层构造
但是数组的每一个存储空间中又分为两个部分
数据区:data
记录所存储的数据
状态区:state
状态区主要记录这个空间的状态;分别为:EXIST:表示这个位置已经存有元素
EMPTY:表示这个位置为空
DELET:表示这个位置存的元素是无效的被删除的元素
新建头文件;HashTable.h
底层构建:
#pragma once
////////////////////////静态哈希表///////////////////////////////////
#define MAX_SIZE 10
typedef int DataType;
typedef enum {EXIST,EMPTY,DELET}State;
typedef struct HTElem
{
DataType _data; //数据
State _state; //状态
}HTElem;
typedef struct HashTable
{
HTElem _array[MAX_SIZE];
int _size; //记录哈希表格中有效元素个数
int _total; //哈希表中总元素个数:包含状态为 存在的和删除的
int _IsLineDetective; //是否是线性探测
int _capacity;
}HT;
void HashTableInit(HT *ht,int capacity,int IsLineDetective); //初始化
void HashTableInsert(HT *ht, DataType data); //插入元素
void HashTableDelet(HT *ht, DataType data); //删除元素
int HashTableFind(HT *ht, DataType data); //查询
int HashTableSize(HT *ht); //求有效元素个数
int HashTableEmpty(HT *ht); //判空
void PrintfHashBucket(HT* ht); //打印
操作函数
#include<stdio.h>
#include<windows.h>
#include<assert.h>
int HashFunc(DataType data) //获得哈希地址 ( 插入和查询时使用 )
{
return data % MAX_SIZE; //除留余数法
}
int DetectiveLine(int hashAddr) //线性探测 ( 插入和查询时使用 )
{
hashAddr++;
if (hashAddr == MAX_SIZE) // 处理越界 如果地址走到末尾,则又回到起始位置;
hashAddr = 0;
return hashAddr;
}
int Detective2(int hashAddr, int i) //二次探测 ( 插入和查询时使用 )
{
hashAddr = hashAddr + 2 * i + 1;
if (hashAddr >= MAX_SIZE) // 处理越界
hashAddr %= MAX_SIZE;
return hashAddr;
}
void HashTableInit(HT *ht,int capacity,int IsLineDetective) //初始化
{
int i = 0;
for (; i < MAX_SIZE; ++i)
ht->_array[i]._state = EMPTY;
ht->_size = 0;
ht->_total = 0;
ht->_capacity = capacity;
ht->_IsLineDetective = IsLineDetective;
}
void HashTableInsert(HT *ht, DataType data) //插入
{
int hashAddr = 0;
int i = 0;
assert(ht);
if (ht->_total == MAX_SIZE) //空间已满
return;
//计算哈希地址
hashAddr = HashFunc(data);
while (EMPTY != ht->_array[hashAddr]._state)
{
//如果当前哈希地址上已经有了元素
if (EXIST == ht->_array[hashAddr]._state)
{
if (data == ht->_array[hashAddr]._data)
return; //如果当前位置上已经有了相同的元素;则不再重复插入
}
//需要找下一个空位置
if (ht->_IsLineDetective)
hashAddr=DetectiveLine(hashAddr); //以线性探测法找
else
hashAddr =Detective2(hashAddr, ++i); //以二次探测法找
}
//对找到的哈西地址进行插入元素
ht->_array[hashAddr]._data = data;
ht->_array[hashAddr]._state = EXIST;
ht->_size++;
ht->_total++;
}
void HashTableDelete(HT * ht, DataType data) //删除
{
int ret = -1;
assert(ht);
ret = HashTableFind(ht, data);
if(-1 !=ret)
{
ht->_array[ret]._state = DELET;
ht->_size--;
}
}
int HashTableFind(HT *ht, DataType data) //从当前哈希地址找到下一个空位置
{
int hashAddr = -1, starAddr = -1; //开始查找的起始位置
int i = 0;
assert(ht);
hashAddr = HashFunc(data); //哈希地址
starAddr = hashAddr;
while (EMPTY != ht->_array[hashAddr]._state) //看地址内是否有数据
{
if (EXIST == ht->_array[hashAddr]._state) //看当前地址的状态
{
if (data == ht->_array[hashAddr]._data) //看数据是否是我们查找的
return hashAddr;
}
//到此说明在求得的哈西地址内没有找到我们需要的数据,那么就继续往后找;
if (ht->_IsLineDetective)
{
hashAddr=DetectiveLine(hashAddr); //以线性探测法找
if (hashAddr == starAddr) //找了一圈,又回到起始位置 都没有找到
return -1;
}
else
hashAddr=Detective2(hashAddr, ++i); //以二次探测法找
}
return -1;
}
int HashTableSize(HT *ht)
{
assert(ht);
return ht->_size;
}
int HashTableEmpty(HT *ht)
{
assert(ht);
return 0 == ht->_size;
}
void PrintfHashBucket(HT* ht) //打印
{
int i = 0;
for (; i < ht->_capacity; i++)
{
if (EXIST == ht->_array[i]._state)
printf("哈希地址为%d的数据为:%d\n", i, ht->_array[i]._data);
}
}
进行测试
新建源文件:Hash.c
#include"HashTable.h"
int main()
{
HT ht;
HashTableInit(&ht, 10, 1); //初始化
HashTableInsert(&ht, 1);
HashTableInsert(&ht, 4);
HashTableInsert(&ht, 6);
HashTableInsert(&ht, 5);
HashTableInsert(&ht, 3);
HashTableInsert(&ht, 15);
PrintfHashBucket(&ht);
printf("size为:%d \n", HashTableSize(&ht));
HashTableDelete(&ht, 3);
PrintfHashBucket(&ht);
printf("size为:%d \n", HashTableSize(&ht));
system("pause");
return 0;
}
运行结果:
哈希地址为1的数据为:1
哈希地址为3的数据为:3
哈希地址为4的数据为:4
哈希地址为5的数据为:5
哈希地址为6的数据为:6
哈希地址为7的数据为:15
size为:6
哈希地址为1的数据为:1
哈希地址为4的数据为:4
哈希地址为5的数据为:5
哈希地址为6的数据为:6
哈希地址为7的数据为:15
size为:5
请按任意键继续. . .