首先是需要定义一个哈希表的结构以及一些相关的常数。其中 HashTable 就是哈希表结构。结构当中的 elem 为一个动态数组。

#define HASHSIZE 12 // 定义哈希表长为数组的长度
#define NULLKEY -32768 // 空关键码 typedef struct
{
int *elem; // 数据元素存储基址,动态分配数组
int count; // 当前数据元素个数
}HashTable; int m = 0; // 哈希表表长,全局变量

一、哈希表基本操作

1.1 初始化操作

有了结构的定义,我们可以对哈希表进行初始化:

// 初始化哈希表
Status initHashTable(HashTable *H)
{
int i; m = HASHSIZE;
H->count = m;
H->elem = (int *)malloc(m*sizeof(int));
for (i = 0; i<m; i++)
H->elem[i] = NULLKEY; return TRUE;
}

1.2 构造哈希函数操作

为了插入时计算地址,我们需要定义哈希函数,哈希函数可以根据不同情况更改算法。这里我们使用的构造方法为除留余数法

// 构造哈希函数
int hash(int key)
{
return key % m; // 构造方法为除留余数法
}

1.3 插入关键字操作

初始化完成后,我们可以对哈希表进行插入操作。假设我们插入的关键字集合就是前面的 {12,67,56,16,25,37,22,29,15,47,48,34}。这里使用开放定址法来避免哈希冲突:

// 插入关键字进哈希表
void insertHash(HashTable *hash, int key)
{
int addr = hashFun(key); // 求哈希地址
while (hash->elem[addr] != NULLKEY) // 如果不为空,则冲突
{
addr = (addr + 1) % m; // 开放定址法的线性探测
}
hash->elem[addr] = key; // 直到有空位后插入关键字
}

1.4 查找关键字操作

哈希表存在后,我们在需要时就可以通过哈希表查找要的记录。

// 哈希表查找关键字
Status searchHash(HashTable hash, int key, int *addr)
{
*addr = hashFun(key); // 求哈希地址,如果后面的hash.elem[*addr] == key,则说明查找成功,直接返回
while (hash.elem[*addr] != key) // 否则,使用开放定址法继续查找
{
*addr = (*addr + 1) % m; // 开放定址法的线性探测
// 如果 查找到NULLKEY | 循环回到原点,则说明关键字不存在,返回FALSE
if (hash.elem[*addr] == NULLKEY || *addr == hashFun(key))
return FALSE;
} return TRUE;
}

可以看出,查找的代码与插入的代码非常类似,只需做一个不存在关键字的判断而已。

二、完整程序

#include <stdio.h>
#include <stdlib.h> #define TRUE 1
#define FALSE 0 #define MAXSIZE 100 /* 存储空间初始分配量 */ typedef int Status; /* Status是函数的类型,其值是函数结果状态代码,如TRUE等 */ #define HASHSIZE 12 // 定义哈希表长为数组的长度
#define NULLKEY -32768 // 空关键字 typedef struct
{
int *elem; // 数据元素存储基址,动态分配数组
int count; // 当前数据元素个数
}HashTable; int m = 0; // 哈希表表长,全局变量 Status initHashTable(HashTable *hash); // 初始化哈希表
// 构造哈希函数
int hashFun(int key); // 初始化哈希表
Status initHashTable(HashTable *hash)
{
int i; m = HASHSIZE;
hash->count = m;
hash->elem = (int *)malloc(m*sizeof(int));
for (i = 0; i<m; i++)
hash->elem[i] = NULLKEY; return TRUE;
} // 构造哈希函数
int hashFun(int key)
{
return key % m; // 构造方法为除留余数法
} // 插入关键字进哈希表
void insertHash(HashTable *hash, int key)
{
int addr = hashFun(key); // 求哈希地址
while (hash->elem[addr] != NULLKEY) // 如果不为空,则冲突
{
addr = (addr + 1) % m; // 开放定址法的线性探测
}
hash->elem[addr] = key; // 直到有空位后插入关键字
} // 哈希表查找关键字
Status searchHash(HashTable hash, int key, int *addr)
{
*addr = hashFun(key); // 求哈希地址,如果后面的hash.elem[*addr] == key,则说明查找成功,直接返回
while (hash.elem[*addr] != key) // 否则,使用开放定址法继续查找
{
*addr = (*addr + 1) % m; // 开放定址法的线性探测
// 如果 查找到NULLKEY | 循环回到原点,则说明关键字不存在,返回FALSE
if (hash.elem[*addr] == NULLKEY || *addr == hashFun(key))
return FALSE;
} return TRUE;
} int main()
{
int arr[HASHSIZE] = {12, 67, 56, 16, 25, 37, 22, 29, 15, 47, 48, 34}; // 要插入关键字
int key = 39; // 关键字
int addr; // 哈希地址
HashTable hash; // 初始化哈希表
initHashTable(&hash); // 插入关键字到哈希表
for (int i = 0; i<m; i++)
insertHash(&hash, arr[i]); // 查找Key为39的关键字(会失败)
int result = searchHash(hash, key, &addr);
if (result)
printf("查找 %d 的哈希地址为:%d \n\n", key, addr);
else
printf("查找 %d 失败。\n\n", key); // 遍历查找关键字(都会成功) for (int i = 0; i<m; i++)
{
key = arr[i];
searchHash(hash, key, &addr);
printf("查找 %d 的哈希地址为:%d \n", key, addr);
}
printf("\n"); return 0;
}

输出结果如下图所示:

参考:

《大话数据结构 - 第8章》 查找

[数据结构 - 第8章] 查找之哈希表(C语言实现)的更多相关文章

  1. 数据结构和算法(Golang实现)(26)查找算法-哈希表

    哈希表:散列查找 一.线性查找 我们要通过一个键key来查找相应的值value.有一种最简单的方式,就是将键值对存放在链表里,然后遍历链表来查找是否存在key,存在则更新键对应的值,不存在则将键值对链 ...

  2. perl5 第九章 关联数组/哈希表

    第九章 关联数组/哈希表 by flamephoenix 一.数组变量的限制二.定义三.访问关联数组的元素四.增加元素五.创建关联数组六.从数组变量复制到关联数组七.元素的增删八.列出数组的索引和值九 ...

  3. 数据结构与算法Python版 熟悉哈希表,了解Python字典底层实现

    Hash Table 散列表(hash table)也被称为哈希表,它是一种根据键(key)来存储值(value)的特殊线性结构. 常用于迅速的无序单点查找,其查找速度可达到常数级别的O(1). 散列 ...

  4. Java数据结构和算法(十三)——哈希表

    Hash表也称散列表,也有直接译作哈希表,Hash表是一种根据关键字值(key - value)而直接进行访问的数据结构.它基于数组,通过把关键字映射到数组的某个下标来加快查找速度,但是又和数组.链表 ...

  5. [数据结构 - 第6章] 树之链式二叉树(C语言实现)

    一.什么是二叉树? 1.1 定义 二叉树,是度为二的树,二叉树的每一个节点最多只有二个子节点,且两个子节点有序. 1.2 二叉树的重要特性 (1)二叉树的第 i 层上节点数最多为 2n-1: (2)高 ...

  6. 简单的哈希表实现 C语言

    简单的哈希表实现 简单的哈希表实现 原理 哈希表和节点数据结构的定义 初始化和释放哈希表 哈希散列算法 辅助函数strDup 哈希表的插入和修改 哈希表中查找 哈希表元素的移除 哈希表打印 测试一下 ...

  7. Java基础知识强化之集合框架笔记75:哈希表

    1. 哈希表数据结构(数组): 2. 哈希表确定元素是否相同: (1)判断的是两个元素的哈希值是否相同                     如果相同,再判断两个对象内容是否相同 (2)判断哈希值相 ...

  8. python 字典有序无序及查找效率,hash表

    刚学python的时候认为字典是无序,通过多次插入,如di = {}, 多次di['testkey']='testvalue' 这样测试来证明无序的.后来接触到了字典查找效率这个东西,查了一下,原来字 ...

  9. 【算法】哈希表的诞生(Java)

    参考资料 <算法(java)>                           — — Robert Sedgewick, Kevin Wayne <数据结构>       ...

随机推荐

  1. c#之添加window服务(定时任务)

    本文讲述使用window服务创建定时任务 1.如图,新建项目,windows桌面->windows服务 2.如图,右键,添加安装程序 3.在下图安装程序 serviceInstaller1 上右 ...

  2. Python - 错误和异常 - 第十九天

    Python 错误和异常 作为 Python 初学者,在刚学习 Python 编程时,经常会看到一些报错信息,在前面我们没有提及,这章节我们会专门介绍. Python 有两种错误很容易辨认:语法错误和 ...

  3. PhantomJS简单使用

    PhantomJS下载地址:   http://phantomjs.org/download.html 简单使用: from selenium import webdriver # 要想调用键盘按键操 ...

  4. 在秉火STM32F429挑战者开发板上移植Huawei LiteOS指南

    昨天在B站上突然看到了一个短视频,是在正点原子的战舰V3开发板上移植华为的Huawei LiteOS操作系统,就是这个视频:看完鸿蒙OS发布会,试用华为的物联网操作系统Lite OS(B站),于是呢, ...

  5. 如何搭建wordpress ,wecenter

    14.什么是LNMP架构 LNMP是指一组通常一起使用来运行动态网站或者服务器的自由软件名称首字母缩写.L指Linux,N指Nginx,M一般指MySQL,也可以指MariaDB,P一般指PHP,也可 ...

  6. null,undefined.'',false关系

    null == undefined //truefalse =='' //true boolean类型跟其它类型==时,会转换成Number类型 Number类型跟String类型==时,string ...

  7. iOS中Category和Extension 原理详解

    (一)Category .什么是Category? category是Objective-C .0之后添加的语言特性,别人口中的分类.类别其实都是指的category.category的主要作用是为已 ...

  8. Jmeter参数化、检查点、集合点教程

    在使用Jemeter做压力测试的时候,往往需要参数化用户名,密码以到达到多用户使用不同的用户名密码登录的目的,这个时候我们就可以使用参数化登录. 一.badboy录制需要的脚本.也可以用fiddler ...

  9. [b0017] python 归纳 (三)_类名当参数传入

    # -*- coding: UTF-8 -*- """ 测试传入类名 总结: 似乎python里面的一切东西都可以当参数传入 函数或者方法 ""&qu ...

  10. 8个有意思的JavaScript面试题

    摘要: 神奇的JS系列. 作者:前端小智 原文:8个问题看你是否真的懂 JS Fundebug经授权转载,版权归原作者所有. JavaScript 是一种有趣的语言,我们都喜欢它,因为它的性质.浏览器 ...