1.开散列(开放地址法)
思想:发生哈希冲突时,如果哈希表未装满,可以把key存放到表的“下一个”空位中去。即 pos++
缺点:所有冲突连在一起易产生数据堆积,占用别的数据的关键码,导致搜索速率下降
#pragma once
#include <stdio.h>
#include <malloc.h>
#include <assert.h>
typedef int KeyDataType;
typedef int ValueDataType;
typedef enum State
{
EMPTY,
DELETE,
EXITS,
}State;
typedef struct HashData
{
KeyDataType key;
ValueDataType value;
State state;
}HashData;
typedef struct HashTable
{
HashData* _tables;
size_t size;
size_t capacity;
}HashTable;
void HashTableInit(HashTable* ht,size_t capacity);
HashData* HashTableFind(HashTable* ht, KeyDataType key);
int HashTableInsert(HashTable* ht, KeyDataType key, ValueDataType value);
int HashTableRemove(HashTable* ht, KeyDataType key);
void HashTableDestory(HashTable* ht);
void PrintHashTable(HashTable* ht);
#include "HashTable.h"
int HashFunc(HashTable* ht, KeyDataType key)
{
assert(ht);
return (key)%(ht->capacity);
}
void HashTableInit(HashTable* ht, size_t capacity)
{
ht->_tables = (HashData*)malloc(sizeof(HashData)* capacity);
ht->size = 0;
ht->capacity = capacity;
for (size_t i = 0; i < ht->capacity; i++)
{
ht->_tables[i].state = EMPTY;
}
}
int HashTableInsert(HashTable* ht, KeyDataType key, ValueDataType value)
{
assert(ht);
if ((ht->size * 10/ ht->capacity)>7) //负载因子大于0.7,扩容
{
ht->_tables = (HashData*)realloc(ht->_tables, sizeof(HashData)* 2 * (ht->capacity));
ht->capacity = 2 * (ht->capacity);
}
int pos = HashFunc(ht, key);
while (ht->_tables[pos].state == EXITS)
{
pos++;
}
ht->_tables[pos].key = key;
ht->_tables[pos].value = value;
ht->_tables[pos].state = EXITS;
ht->size++;
return 1;
}
HashData* HashTableFind(HashTable* ht, KeyDataType key)
{
assert(ht);
int pos = HashFunc(ht, key);
while (ht->_tables[pos].state != EMPTY)
{
if (ht->_tables[pos].key == key)
{
printf("找到了!\n");
return &(ht->_tables[pos]);
}
else
{
pos++;
}
}
printf("没找到!\n");
return NULL;
}
int HashTableRemove(HashTable* ht, KeyDataType key)
{
assert(ht);
HashData* del = HashTableFind(ht, key);
if (del)
{
del->state = DELETE;
printf("删除成功!\n");
ht->size--;
return 1;
}
return 0;
}
void HashTableDestory(HashTable* ht)
{
assert(ht);
free(ht->_tables);
ht->_tables = NULL;
ht->capacity = 0;
ht->size = 0;
}
void PrintHashTable(HashTable* ht)
{
assert(ht);
size_t pos = 0;
for (pos = 0; pos < ht->capacity; pos++)
{
if (ht->_tables[pos].state == EXITS)
{
printf(" %d : %d\n", ht->_tables[pos].key, ht->_tables[pos].value);
}
}
}
2.开散列(拉链法)
思想:将具有相同关键码的元素用单链表连接起来,每一个链称为一个桶
每个单链表的头节点存在哈希表中。不存在溢出
#pragma once
#include <stdio.h>
#include <malloc.h>
#include <assert.h>
typedef int KeyData;
typedef int ValueData;
typedef enum State
{
EXITS,
EMPTY,
DELETE,
}State;
typedef struct HashData
{
KeyData _key;
ValueData _value;
State _state;
struct HashData* _next;
}HashData;
typedef struct HashTable
{
HashData* _data;
size_t capacity;
}HashTable;
void HashTableInit(HashTable* ht, size_t capacity);
HashData* HashTableFind(HashTable* ht, KeyData key);
int HashTableInsert(HashTable* ht, KeyData key, ValueData value);
int HashTableRemove(HashTable* ht, KeyData key);
void HashTableDestory(HashTable* ht);
void PrintHashTable(HashTable* ht);
#include "HashTable.h"
size_t HashFunc(HashTable* ht, KeyData key) //计算位置
{
assert(ht);
return key%(ht->capacity);
}
HashData* BuyNode(KeyData key, ValueData value)
{
HashData* newNode = (HashData*)malloc(sizeof(HashData));
newNode->_key = key;
newNode->_value = value;
newNode->_next = NULL;
newNode->_state = EXITS;
return newNode;
}
void HashTableInit(HashTable* ht, size_t capacity)
{
assert(ht);
ht->_data = (HashData*)malloc(sizeof(HashData)*capacity);
ht->capacity = capacity;
for (size_t i = 0; i < capacity; i++) //将哈希表中的状态都初始化为空
{
ht->_data[i]._state = EMPTY;
ht->_data[i]._next = NULL;
}
}
HashData* HashTableFind(HashTable* ht, KeyData key)
{
assert(ht);
size_t pos = HashFunc(ht, key);
HashData* cur = &(ht->_data[pos]);
if (cur->_state == EMPTY)
return NULL;
while (cur->_next != NULL && cur->_next->_state == EXITS) //遍历到一个桶的最后一个元素
{
if (cur->_next->_key == key)
{
printf("找到了!\n");
return cur->_next;
}
cur = cur->_next;
}
printf("没找到!\n");
return NULL;
}
int HashTableInsert(HashTable* ht, KeyData key, ValueData value)
{
assert(ht);
size_t pos = HashFunc(ht, key);
if (ht->_data[pos]._state == EMPTY) //插入第一个元素
{
ht->_data[pos]._next = BuyNode(key, value);
ht->_data[pos]._state = EXITS;
return 1;
}
else
{
HashData* cur = &(ht->_data[pos]);
while (cur->_next && cur->_next->_state==EXITS)
{
cur = cur->_next;
}
cur->_next = BuyNode(key, value); //挂到桶最后
return 1;
}
}
int HashTableRemove(HashTable* ht, KeyData key)
{
assert(ht);
HashData* cur = HashTableFind(ht, key);
if (cur == NULL)
{
printf("删除失败!\n");
return 0;
}
if (cur->_next) //删除桶的非尾节点
{
HashData* del = cur->_next;
HashData* next = del->_next;
cur->_key = del->_key;
cur->_value = del->_value;
cur->_next = del->_next;
cur->_state = del->_state;
free(del);
del = NULL;
printf("删除成功!\n");
return 1;
}
else //删除桶的尾节点
{
cur->_state = DELETE;
printf("删除成功!\n");
return 1;
}
}
void HashTableDestory(HashTable* ht)
{
assert(ht);
size_t i = 0;
for (i = 0; i < ht->capacity; i++)
{
HashData* pos = (&(ht->_data[i]));
if (pos->_state == EMPTY)
continue;
pos = pos->_next; //桶中第一个元素
if (pos != NULL && pos->_state != EMPTY) //不能释放哈希表中的元素,只能释放桶中的元素
{
while (pos) //销毁一个位置挂的桶
{
HashData* del = pos->_next;
free(pos);
pos = NULL;
pos = del;
}
}
}
free(ht->_data); //销毁哈希表
ht->_data = NULL;
ht->capacity = 0;
}
void PrintHashTable(HashTable* ht)
{
assert(ht);
size_t i = 0;
for (i = 0; i < ht->capacity; i++)
{
HashData* pos = &(ht->_data[i]);
if (pos->_state == EXITS)
{
while (pos->_next)
{
printf("%d : %d\n", pos->_next->_key, pos->_next->_value);
pos = pos->_next;
}
}
}
}
博客介绍了开散列的两种方法。开放地址法在发生哈希冲突且表未装满时,将key存到表的下一个空位,缺点是易产生数据堆积,降低搜索速率;拉链法把相同关键码元素用单链表连接成桶,头节点存于哈希表,不存在溢出问题。
675

被折叠的 条评论
为什么被折叠?



