哈希表的基本概念
操作
- 插入元素时:根据待插入元素的关键码,以此函数计算出该元素的存储位置并按此位置进行存放
- 搜索元素时:对元素的关键码进行同样的计算,把求得的函数值当做元素的存储位置,在结构中按此位置取元素比较,若关键 码相等,则搜索成功
哈希冲突
不同关键字通过相同哈希函数计算出相同的哈希地址,该种现象称为哈希冲突或哈希碰撞
负载因子
负载因子 = 表中元素个数 / 列表长度
闭散列
当发生哈希冲突时,如果哈希表未被装满,说明在哈希表中必然还有空位置,那么可以把key存放到表中 “下一个” 空位中去(负载因子a不超过 0.7;如果超出必须考虑增容 )
解决哈希冲突的方法
线性探测——从发生冲突的位置开始,依次继续向后探测,直到找到空位置为止
二次探测——发生哈希冲突时,二次探查法在表中寻找“下一个”空位置的公式为: Hi = (H0 + i^2) % m, Hi= ( H0 - i^2) % m, i = 1,2,3…, (m-1)/2H0是通过散列函数Hash(x)对元素的关键码 key 进行计算得到的位置,m是表的大小
辅助定义
#define MAX_SIZE 10 //初始大小
typedef int HDataType;
enum State
{
EMPTY, //空
EXTXT, //存储
DELET, //删除
};
typedef struct HTELEM //哈希表中存储的元素数字及状态
{
HDataType _data; //数据
enum State _state; //状态
}HTELEM, *pHTELEM;
静态实现
定义
typedef struct HashTable
{
HTELEM _ht[MAX_SIZE]; //哈希表
int _size; //元素个数
}HashTable, *pHashTable;
哈希函数
int HashFun(HDataType data) //哈希函数
{
return (data % 10);
}
初始化
void HashInit(pHashTable phashtable)
{
//静态
assert(phashtable); //指针不能为空
//状态置空
for (int i = 0; i < MAX_SIZE; i++)
{
phashtable->_ht[i]._state = EMPTY;
}
//元素个数初始值为0
phashtable->_size = 0;
}
元素个数
int HashSize(pHashTable phashtable)
{
assert(phashtable);
return phashtable->_size;
}
哈希表是否为空
int HashEmpty(pHashTable phashtable)
{
assert(phashtable);
return phashtable->_size == 0;
}
插入
void HashInsert(pHashTable phashtable, HDataType data)
{
//静态
assert(phashtable);
//计算哈希地址
int address = HashFun(data);
int i = 1;
while (phashtable->_ht[address]._state != EMPTY)
{
//线性探测
address = address + 1;
if (address == MAX_SIZE)
address = 0;
/*
//二次探测
address = (address + i * i) % MAX_SIZE;
i++;
if (address == MAX_SIZE)
address = 0;
*/
}
//插入元素
phashtable->_ht[address]._data = data;
phashtable->_ht[address]._state = EXTXT;
phashtable->_size++;
}
查找
int HashFind(pHashTable phashtable, HDataType data)
{
//静态
assert(phashtable);
//计算哈希地址
int address = HashFun(data);
int i = 1;
//状态不为空,且状态为存储状态,查找元素
while (phashtable->_ht[address]._state != EMPTY)
{
//线性探测规则查找
if (phashtable->_ht[address]._state == EXTXT)
{
if (phashtable->_ht[address]._data == data)
{
return address;
}
}
//线性探测
address = address + 1;
if (address == MAX_SIZE)
address = 0;
/*
//二次探测
address = (address + i * i) % MAX_SIZE;
i++;
if (address == MAX_SIZE)
address = 0;
*/
}
return -1;
}
删除
int HashDelete(pHashTable phashtable, HDataType data)
{
//静态
assert(phashtable);
//计算哈希地址
int address = HashFun(data);
int i = 1;
//状态不为空,且状态为存储状态,查找元素,改变状态
while (phashtable->_ht[address]._state != EMPTY)
{
//线性探测规则查找
if (phashtable->_ht[address]._state == EXTXT)
{
if (phashtable->_ht[address]._data == data)
{
phashtable->_ht[address]._state = DELET;
return 1;
}
}
//线性探测
address = address + 1;
if (address == MAX_SIZE)
address = 0;
/*
//二次探测
address = (address + i * i) % MAX_SIZE;
i++;
if (address == MAX_SIZE)
address = 0;
*/
}
return 0;
}
动态实现
定义
typedef struct HashTableDy
{
pHTELEM _ht; //哈希链表表
int _size; //元素个数
int _capacity; //容量 最大元素个数
int _totly; //已经使用位置个数
}HashTableDy, *pHashTableDy;
哈希函数
int HashFunDy(HDataType data, int capacity)
{
return data % capacity;
}
初始化
void HashInit(pHashTableDy phashtabledy, int capacity)
{
assert(phashtabledy); //指针不能为空
//开辟空间
pHTELEM ph = (pHTELEM)malloc(capacity * sizeof(HTELEM));
if (NULL == ph)
{
assert(0);
}
//状态置空
for (int i = 0; i < capacity; i++)
{
(ph + i)->_state = EMPTY;
}
phashtabledy->_ht = ph;
//初始化容量
phashtabledy->_capacity = capacity;
//元素个数初始值为0
phashtabledy->_size = 0;
phashtabledy->_totly = 0;
}
元素个数
int HashSize(pHashTableDy phashtabledy)
{
assert(phashtabledy);
return phashtabledy->_size;
}
哈希表是否为空
int HashEmpty(pHashTableDy phashtabledy)
{
assert(phashtabledy);
return phashtabledy->_size == 0;
}
插入
扩容函数
void Dilatation(pHashTableDy *phashtabledy)
{
//开辟新空间,为原空间的两倍
int capacity = (*phashtabledy)->_capacity * 2;
pHTELEM ph = (pHTELEM)malloc(capacity * sizeof(HTELEM));
if (NULL == ph)
{
assert(0);
}
//新空间的状态为空
for (int i = 0; i < capacity; i++)
{
(ph + i)->_state = EMPTY;
}
//拷贝元素
for (int i = 0; i < (*phashtabledy)->_capacity; i++) //遍历原空间
{
if (((*phashtabledy)->_ht + i)->_state == EXTXT) //存在元素
{
//插入到新空间
int address = HashFunDy(((*phashtabledy)->_ht + i)->_data, capacity);
while ((ph + address)->_state != EMPTY)
{
//线性探测
address = address + 1;
if (address == MAX_SIZE)
address = 0;
/*
//二次探测
address = (address + i * i) % MAX_SIZE;
i++;
if (address == MAX_SIZE)
address = 0;
*/
}
//插入元素
(ph + address)->_data = ((*phashtabledy)->_ht + i)->_data;
(ph + address)->_state = EXTXT;
}
}
//释放旧空间
(*phashtabledy)->_capacity = capacity;
(*phashtabledy)->_totly = (*phashtabledy)->_size;
pHTELEM del = (*phashtabledy)->_ht;
(*phashtabledy)->_ht = ph;
free(del);
del = NULL;
}
插入
void HashInsert(pHashTableDy phashtabledy, HDataType data)
{
//静态
assert(phashtabledy);
//判断是否需要开辟空间-负载因子
if ((phashtabledy->_totly) * 10 / phashtabledy->_capacity >= 7)
{
//扩容
Dilatation(&phashtabledy);
}
//计算哈希地址
int address = HashFunDy(data, phashtabledy->_capacity);
while ((phashtabledy->_ht + address)->_state != EMPTY)
{
//线性探测
address = address + 1;
if (address == MAX_SIZE)
address = 0;
/*
//二次探测
address = (address + i * i) % MAX_SIZE;
i++;
if (address == MAX_SIZE)
address = 0;
*/
}
//插入元素
(phashtabledy->_ht + address)->_data = data;
(phashtabledy->_ht + address)->_state = EXTXT;
phashtabledy->_size++;
phashtabledy->_totly++;
}
查找
int HashFind(pHashTableDy phashtabledy, HDataType data)
{
assert(phashtabledy);
//计算哈希地址
int address = HashFunDy(data, phashtabledy->_capacity);
//状态不为空
while ((phashtabledy->_ht + address)->_state != EMPTY)
{
//线性探测规则查找
if ((phashtabledy->_ht + address)->_state == EXTXT)
{
if ((phashtabledy->_ht + address)->_data == data)
{
return address;
}
}
//线性探测
address = address + 1;
if (address == MAX_SIZE)
address = 0;
/*
//二次探测
address = (address + i * i) % MAX_SIZE;
i++;
if (address == MAX_SIZE)
address = 0;
*/
}
return -1;
}
删除
int HashDelete(pHashTableDy phashtabledy, HDataType data)
{
assert(phashtabledy);
//计算哈希地址
int address = HashFunDy(data, phashtabledy->_capacity);
//状态不为空
while ((phashtabledy->_ht + address)->_state != EMPTY)
{
//线性探测规则查找
if ((phashtabledy->_ht + address)->_state == EXTXT)
{
if ((phashtabledy->_ht + address)->_data == data)
{
(phashtabledy->_ht + address)->_state = DELET;
return 1;
}
}
//线性探测
address = address + 1;
if (address == MAX_SIZE)
address = 0;
/*
//二次探测
address = (address + i * i) % MAX_SIZE;
i++;
if (address == MAX_SIZE)
address = 0;
*/
}
return -1;
}
销毁
void HashDestroy(pHashTableDy phashtabledy)
{
assert(phashtabledy);
free(phashtabledy->_ht);
phashtabledy->_ht = NULL;
phashtabledy->_capacity = 0;
phashtabledy->_size = 0;
phashtabledy->_totly = 0;
}