数据结构之哈希搜索结构(二)

上篇博客我们以闭散列解决哈希冲突的方式实现了哈希搜索结构。闭散列在实际操作时需要考虑一个问题就是如果插入时发现超过了负载因子,那么这个时候就不能插入了,需要扩容。扩容时,则需要创建更大的空间,并且由于空间变大,导致的可放个数变多,进而导致哈希函数所计算出关键值与对应存储位置发生改变。所以在扩容后拷贝的时候更加的麻烦。

开散列解决哈希冲突

同样再提出开散列之前定义哈希函数,方便查看。

int HashFun(int key)
{
    return key % 1000;
}

这里写图片描述
这里写图片描述

同样在插入1001时,遇到了哈希冲突,这时候利用开散列解决哈希冲突。

这里写图片描述

这里相当于在每个下标下存储着一个头指针,这个头指针指向一条单链表。而链表内部存储的元素就是关键码。

实现

//hash.h

#pragma once

#include <stddef.h>

#define HASHMAXSIZE 1000

typedef int Keytype;
typedef int Valtype;

typedef size_t (*HashFun)(Keytype key);

typedef struct HashElem {
  Keytype key;
  Valtype val;
  struct HashElem* next;//尾指针
} HashElem;

typedef struct HashTable {
  HashElem* data[HASHMAXSIZE];
  size_t size;
  HashFun fun;//哈希函数
} HashTable;

void HashInit(HashTable* ht, HashFun fun);//初始化哈希表

void HashInsert(HashTable* ht, Keytype key, Valtype val);//插入哈希表

void HashDestroy(HashTable* ht);//销毁哈希表

void HashRemove(HashTable* ht, Keytype key);//删除哈希表指定元素

int HashFind(HashTable* ht, Keytype key, Valtype* val);//查找哈希表内元素
#include "hash.h"
#include <stdio.h>
#include <stdlib.h>

size_t Function(Keytype key) {
  return key % HASHMAXSIZE;
}

void HashInit(HashTable* ht, HashFun fun)//初始化哈希表
{
  if(ht == NULL) {
    return;
  }
  ht->size = 0;
  ht->fun = fun;

  size_t i = 0;
  for(; i < HASHMAXSIZE; ++i) {
    ht->data[i] = NULL;
  }
  return;
}

HashElem* CreateElem(Keytype key, Valtype val)
{
  HashElem* new_elem = (HashElem*)malloc(sizeof(HashElem));
  new_elem->key = key;
  new_elem->val = val;
  new_elem->next = NULL;
  return new_elem;
}

void HashInsert(HashTable* ht, Keytype key, Valtype val)//插入哈希表
{
  if(ht == NULL) {
    return;
  }
  size_t offset = ht->fun(key);
  HashElem* cur = ht->data[offset];
  while(cur != NULL) {
    if(cur->key == key) {//关键码一样就不插入
      return;
    }
    cur = cur->next;
  }
  HashElem* new_elem = CreateElem(key, val);//链表头插
  new_elem->next = ht->data[offset];
  ht->data[offset] = new_elem;
  ++ht->size;
  return;
}

void Destroy(HashElem* cur)
{
  free(cur);
  cur = NULL;
}

void HashDestroy(HashTable* ht)//销毁哈希表
{
  if(ht == NULL) {
    return;
  }
  if(ht->size == 0) {
    return;
  }
  size_t i = 0;
  for(; i < HASHMAXSIZE; ++i) {
    HashElem* cur = ht->data[i];
    if(cur == NULL) {
      continue;
    }
    while(cur != NULL) {
      HashElem* pre = cur;
      Destroy(cur);
      cur = pre->next;
    }
  }
  ht->size = 0;
  ht->fun = NULL;
  return;
}

void HashRemove(HashTable* ht, Keytype key)//删除哈希表指定元素
{
  if(ht == NULL) {
    return;
  }

  size_t offset = ht->fun(key);
  HashElem* cur = ht->data[offset];
  HashElem* pre = NULL;

  while(cur != NULL) {
    if(cur->key == key) {
      break;
    }
    pre = cur;
    cur = cur->next;
  }
  if(cur == NULL) {
    return;
  }
  if(pre == NULL) {
    HashElem* tmp = ht->data[offset];
    ht->data[offset] = tmp->next;
    Destroy(tmp);
  } else {
    pre->next = cur->next;
    Destroy(cur);
  }
  return;
}

int HashFind(HashTable* ht, Keytype key, Valtype* val)//查找哈希表内元素
{
  if(ht == NULL) {
    return 0;
  }
  if(ht->size == 0) {
    return 0;
  }
  size_t offset = ht->fun(key);
  HashElem* cur = ht->data[offset];
  while(cur != NULL) {
    if(cur->key == key) {
      *val = cur->val;
      return 1;
    }
    cur = cur->next;
  }
  return 0;
}

欢迎大家共同讨论,如有错误及时联系作者指出,并改正。谢谢大家!

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值