哈希表的基本操作

本文介绍了哈希表的基本概念,包括通过散列函数将关键字映射到存储位置,以及处理碰撞的线性探测和链地址法。讨论了散列函数的类型,如直接寻址法、平方取中法和除留余数法,并提供了线性探测和链地址法的实现代码示例。
哈希表

若关键字为k,则其值存放在f(k)的存储位置上。由此,不需比较便可直接取得所查记录。称这个对应关系f()为散列函数,按这个思想建立的表为散列表(即哈希表).

对不同的关键字可能得到同一散列地址,即k1≠k2,而f(k1)=f(k2)
这种现象称为碰撞

散列函数能使对一个数据序列的访问过程更加迅速有效,通过散列函数,数据元素将被更快地定位.

散列函数有很多种
常用的有:

  • 直接寻址法:取关键字或关键字的某个线性函数值为散列地址。即H(key)=key或H(key) = a·key + b,其中a和b为常数(这种散列函数叫做自身函数)。若其中H(key)中已经有值了,就往下一个找,直到H(key)中没有值了,就放进去。
  • 平方取中法:当无法确定关键字中哪几位分布较均匀时,可以先求出关键字的平方值,然后按需要取平方值的中间几位作为哈希地址。这是因为:平方后中间几位和关键字中每一位都相关,故不同关键字会以较高的概率产生不同的哈希地址。
  • 除留余数法:取关键字被某个不大于散列表表长m的数p除后所得的余数为散列地址。即 H(key) = key MOD p,p<=m。不仅可以对关键字直接取模,也可在折叠、平方取中等运算之后取模。对p的选择很重要,一般取素数或m,若p选的不好,容易产生同义词。

同样处理碰撞问题的方法也有很多种
常用的有:

  • 线性探测: 如果k1≠k2,而f(k1)=f(k2), 就继续往后寻找, 找到一个空的位置, 然后放进去.
  • 链地址法: 这种方法数组的每个元素是一个链表的头指针, 如果k1≠k2,而f(k1)=f(k2), 就往链表中头插节点.
实现代码
线性探测
/*================================================================

# File Name: hash.h
# Author: rjm
# mail: rjm96@foxmail.com
# Created Time: 2018年05月18日 星期五 18时26分13秒

================================================================*/


// 哈希表
#pragma once

#define TEST_HEAD printf("\n==================%s===============\n", __FUNCTION__)
#define HashMaxSize 1000

typedef int KeyType; // 要插入的值
typedef int ValueType;
// 计算下标的函数
typedef int (*HashFunc)(KeyType key);

typedef enum Stat {
    Empty, // 空状态, 表示这个位置还没有元素插入
    valid, // 有效状态, 表示这个位置已经有元素插入了
    deleted, // 已删除状态, 表示这个位置的元素已经被删除了
} Stat;

// 键值对
typedef struct HashElem {
    KeyType key;
    ValueType value;
    Stat stat; //每个位置的状态
} HashElem;

int func(KeyType key)
{
    return key % HashMaxSize;
}

typedef struct HashTable {
    HashElem data[HashMaxSize]; //哈希表数组, 存的是包含一组键值对的结构体
    size_t size; //哈希表当前有效元素的个数
    HashFunc func; //计算下标的函数
} HashTable;


// 初始化
void HashInit(HashTable* ht, HashFunc hash_func);

// 插入元素
void HashInsert(HashTable* ht, KeyType key, ValueType value);

// 查找
int HashFind(HashTable* ht, KeyType key, int* to_find);

// 删除
void HashRemove(HashTable* ht, KeyType key);

// 销毁
void HashDestroy(HashTable* ht);
/*================================================================

# File Name: hash.c
# Author: rjm
# mail: rjm96@foxmail.com
# Created Time: 2018年05月18日 星期五 18时25分38秒

================================================================*/

// 哈希表
#include <stdio.h>
#include "hash.h"

// 初始化
void HashInit(HashTable* ht, HashFunc hash_func)
{
    ht->size = 0;
    ht->func = hash_func;
    for(int i=0; i<HashMaxSize; i++)
    {
        ht->data[i].stat = Empty;
    }
    return ;
}
// 插入
void HashInsert(HashTable* ht, KeyType key, ValueType value)
{
    if(ht->size == HashMaxSize)
    {
        // 哈希表已经满了
        return ;
    }
    int offset = func(key);
    ValueType val;
    if(HashFind(ht, key, &val) == 1)
      return ;
    if(ht->data[offset].stat != valid)
    {
        ht->data[offset].key = key;
        ht->data[offset].value = value;
        ht->data[offset].stat = valid;
        ++ht->size;
    }
    else
    {
        while(1)
        {
            offset++;
            if(offset == HashMaxSize)
            {
                offset = 0;
            }
            if(ht->data[offset].stat != valid)
              break;
        }
        h
### Java 中哈希表基本操作 在Java中,`HashMap` 是最常用的一种哈希表实现方式。通过 `HashMap` 可以方便地执行插入、删除和查找等基本操作。 #### 创建 HashMap 实例 要创建一个 `HashMap` 对象,可以使用如下代码: ```java Map<String, Integer> map = new HashMap<>(); ``` 这段代码定义了一个键为字符串类型 (`String`) 而值为整数类型 (`Integer`) 的哈希表实例[^1]。 #### 插入元素 向哈希表中插入新条目可以通过调用 `put()` 方法完成: ```java map.put("Alice", 20); map.put("Bob", 25); ``` 这里分别将两个键值对 `"Alice"` -> `20` 和 `"Bob"` -> `25` 添加到了哈希表里。 #### 查找元素 为了获取某个特定键对应的值,可利用 `get()` 函数来进行查询: ```java int ageOfAlice = map.get("Alice"); System.out.println(ageOfAlice); // 输出:20 ``` 如果尝试访问不存在的键,则返回 null 或者自定义默认值。 #### 删除元素 当不再需要某些记录时,可通过指定其键名来移除它们: ```java map.remove("Bob"); boolean containsKey = map.containsKey("Bob"); // 返回 false 表明该键已被成功删除 ``` 上述例子展示了如何安全有效地管理存储于哈希表内的信息项。 #### 遍历哈希表 遍历整个哈希表并打印所有的键值对: ```java for (Map.Entry<String, Integer> entry : map.entrySet()) { System.out.println(entry.getKey() + ": " + entry.getValue()); } ``` 此循环会依次输出每一对键及其联的数据值。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值