/* * 程序名:hash.c,此程序演示哈希表的实现,数据元素单链表带头结点。 * */ #include <stdio.h> #include <stdlib.h> #include <string.h> // 哈希表中数据元素的结构体。 typedef struct Element { unsigned int key; // 关键字。 int value; // 数据元素其它数据项,可以是任意数据类型。 // char value[1001]; // 数据元素其它数据项,可以是任意数据类型。 }Element; // 数据元素单链表。 typedef struct Node { Element elem; // 数据元素。 struct Node *next; // next指针。 }Node; // 哈希表 typedef struct HashTable { struct Node *head; // 数据元素存储基址,动态分配数组。 int tablesize; // 哈希表当前大小,即表长。 int count; // 哈希表中数据元素的个数。 }HashTable; // 初始化哈希表,tablesize为哈希表的表长,返回哈希表的地址。 HashTable *InitHashTable(const unsigned int tablesize) { // 分配哈希表。 HashTable *hh=(HashTable *)malloc(sizeof(HashTable)); hh->tablesize=tablesize; // 哈希表长。 // 分配和初始化数据元素单链表的头结点。 hh->head=(Node *)malloc((hh->tablesize)*sizeof(Node)); memset(hh->head,0,(hh->tablesize)*sizeof(Node)); hh->count=0; // 哈希表中数据元素个数置为0。 return hh; } // 哈希函数。 unsigned int Hash(HashTable *hh,unsigned int key) { return key%hh->tablesize; // 对表长取余。 } // 在哈希表中查找关键字,成功返回单链表结点的地址,失败返回空。 Node *LookUp(HashTable *hh,unsigned int key) { int ii; ii=Hash(hh,key); // 获取关键key的哈希地址。 Node *pp=hh->head[ii].next; // 遍历单链表。 while( (pp!=NULL) && (pp->elem.key!=key) ) { pp=pp->next; } return pp; } // 从哈希表中删除关键及其数据,成功返回1,如果关键字不存在返回0。 int Delete(HashTable *hh,unsigned int key) { int ii; ii=Hash(hh,key); // 获取关键key的哈希地址。 Node *pp=&hh->head[ii]; // 遍历单链表,pp指针停留在待删除关键key的前一结点。 while( (pp->next!=NULL) && (pp->next->elem.key!=key) ) { pp=pp->next; } if (pp->next==NULL) return 0; // 查找失败。 Node *tmp=pp->next; // tmp为将要删除的结点。 pp->next=pp->next->next; // 写成p->next=tmp->next更简洁。 free(tmp); // 释放结点。 hh->count--; // 表中元素个数减1。 return 1; } // 向哈希表中插入数据元素,成功返回1,如果数据元素关键字已存在,返回0。 int Insert(HashTable *hh,Element *ee) { // 查找关键字是否已存在,如果存在,插入失败。 Node *pp=LookUp(hh,ee->key); if (pp!=NULL) { printf("关键字%d已存在。\n",ee->key); return 0; } Node *qq=(Node *)malloc(sizeof(Node)); memcpy(&qq->elem,ee,sizeof(Element)); // 用头插法插入新数据元素。 int ii=Hash(hh,ee->key); qq->next=hh->head[ii].next; hh->head[ii].next=qq; hh->count++; // 表中元素个数加1。 return 1; } // 销毁哈希表 void FreeHashTable(HashTable *hh) { int ii; Node *pp,*qq; // 释放全部的单链表。 for(ii=0;ii<hh->tablesize;ii++) { pp=hh->head[ii].next; while(pp) { qq=pp->next; free(pp); pp=qq; } } // 释放全部单链表的头结点数组。 free(hh->head); free(hh); // 释放哈希表。 } // 打印哈希表。 void PrintTable(HashTable *hh) { int ii; for (ii=0;ii<hh->tablesize;ii++) { Node *pp=hh->head[ii].next; while (pp) { printf("[%d-%d] ",pp->elem.key,pp->elem.value); // printf("[%d-%s] ",pp->elem.key,pp->elem.value); pp=pp->next; } printf("^\n"); } printf("\n"); } int main() { // 初始化哈希表。 HashTable *hh=InitHashTable(10); Element ee; // 插入数据元素,关键字从10到20。 ee.key=10; ee.value=110; Insert(hh,&ee); ee.key=11; ee.value=111; Insert(hh,&ee); ee.key=12; ee.value=112; Insert(hh,&ee); ee.key=13; ee.value=113; Insert(hh,&ee); ee.key=14; ee.value=114; Insert(hh,&ee); ee.key=15; ee.value=115; Insert(hh,&ee); ee.key=16; ee.value=116; Insert(hh,&ee); ee.key=17; ee.value=117; Insert(hh,&ee); ee.key=18; ee.value=118; Insert(hh,&ee); ee.key=19; ee.value=119; Insert(hh,&ee); // 插入数据元素,关键字从20到30。 ee.key=20; ee.value=120; Insert(hh,&ee); ee.key=21; ee.value=121; Insert(hh,&ee); ee.key=22; ee.value=122; Insert(hh,&ee); ee.key=23; ee.value=123; Insert(hh,&ee); ee.key=24; ee.value=124; Insert(hh,&ee); ee.key=25; ee.value=125; Insert(hh,&ee); ee.key=26; ee.value=126; Insert(hh,&ee); ee.key=27; ee.value=127; Insert(hh,&ee); ee.key=28; ee.value=128; Insert(hh,&ee); ee.key=29; ee.value=129; Insert(hh,&ee); // 插入数据元素,关键字从30到32。 ee.key=30; ee.value=130; Insert(hh,&ee); ee.key=31; ee.value=131; Insert(hh,&ee); ee.key=32; ee.value=132; Insert(hh,&ee); printf("count=%d\n",hh->count); PrintTable(hh); // 打印哈希表 Delete(hh,12); // 删除哈希表中关键字为12的数据元素。 printf("count=%d\n",hh->count); PrintTable(hh); // 打印哈希表 // 在哈希表中查找关键字18。 Node *pp=LookUp(hh,18); if (pp==0) printf("LookUp(18) failed.\n"); else printf("key=18,value=%d.\n",pp->elem.value); // ee.key=10; strcpy(ee.value,"<no>00010<no/><name>西施</name><yz>绝世美人</yz>"); Insert(hh,&ee); // PrintTable(hh); // 打印哈希表 FreeHashTable(hh); // 销毁哈希表 return 0; }
C语言数据结构哈希表详解
使用C#判断文件是否为图片的多种方法
目录 0、常见的判断图片文件的方法 1. 根据文件扩展名判断 代码示例 优缺点 2. 通过文件头(Magic Number)判断 代码示例 优缺点 3. 使用 ImageSharp 判断文件是否为图
QT 实现随机验证码功能
目录 1.界面实现效果 2.简介 3.使用1.界面实现效果以下是具体的项目需要用到的效果展示,用于验证字母。2.简介自定义CaptchaMovableLabel,继承自QLabel类:
中间的4个字母,就是Ca
C# Winform截图指定控件范围内的图像的流程步骤
目录 一、函数输入 二、函数输出 三、使用示例一、函数输入输入有两个,参数一:需要截图的容器控件,参数二:保存截图的绝对路径路径<param name="control">控件名</param>
<param
C++解决回调地狱问题的方法小结
目录1. 使用 Lambda 表达式和标准库 std::function2. 使用 std::future 和 std::promise3. 使用协程 (C++20)4. 使用异步框架总结“地狱回调”(Callback Hell)是指
C语言报错:Buffer Overflow的原因和解决办法
目录简介什么是Buffer OverflowBuffer Overflow的常见原因如何检测和调试Buffer Overflow解决Buffer Overflow的最佳实践详细实例解析示例1:数组越界写入示例2:未检查输入长度
C++报错:Segmentation Fault的解决方案
目录引言段错误的产生原因段错误的检测方法段错误的预防措施段错误的解决方案总结引言段错误(Segmentation Fault)是 C++ 编程中常见且令人头疼的错误之一。段错误通常发生在
Qt中QPushButton组件的使用详解
QPushButton是Qt库中的一个重要组件,它是用户界面(UI)设计中常用的一个按钮控件。在Qt程序中,QPushButton用于创建可以在界面上点击响应操作的交互元素。它的主要作用包括:显示文
Qt实现手动切换多种布局的完美方案
目录引言示例需求开发环境代码实现运行结果程序分析注意引言之前写了一个手动切换多个布局的程序,下面来记录一下。
程序运行效果如下:示例需求通过点击程序界面上不同的布局
一篇文章详解Qt中如何访问数据库
目录前言1. 加载数据库驱动2. 创建数据库连接3. 执行SQL查询或命令4. 关闭数据库连接示例完整代码片段打开多个数据库使用建议总结 前言在Qt中访问数据库涉及到几个关键步骤
Qt 编译配置 Protobuf 的详细步骤
目录步骤 1: 安装Protobuf步骤 2: 配置Qt项目步骤 3: 编译和运行项目 运行qmake以生成Makefile:注意事项在Qt项目中使用Protobuf(Protocol Buffers)可以有效地处理数据序列化和
C++ STL iota 和 atoi 用法示例详解
目录一:功能二:用法一:功能 iota 是给定一个初始元素,然后依次对序列中每个元素进行递增++操作,详见代码一; atoi 是将字符串转换成整数;atol, atoll 将字符串转换成
C语言中输出空格的五种方法
目录前言1. 直接在字符串中包含空格2. 使用 %s 和空格3. 使用 \t 输出制表符(Tab)4. 使用循环输出多个空格5. 使用格式控制符输出空格总结前言在C语言中,输出空格可以通过使用
C语言文件操作入门指南
一、为什么使用文件在学习完结构体后,为了检验学习成果,我们写了一个通讯录的小程序,当通讯录运行起来的时候,可以给通讯录中增加、删除数据,此时数据是存放在内存中的,当程序退出
Qt中暂停程序的几种方法小结
目录1. 使用 QThread::sleep示例代码:说明:优点:缺点:2. 使用 QTimer 和事件循环示例代码:说明:优点:缺点:3. 使用 QEventLoop 结合 QTimer示例代码:说明:优点:缺点:4. 使用 QPauseAnima
C语言中实现自定义数据类型的输入输出的方法和技巧
目录C 语言中如何实现自定义数据类型的输入输出一、结构体数据类型的输入输出二、枚举数据类型的输入输出三、联合数据类型的输入输出四、使用指针实现复杂数据结构的输入输
详解C/C++如何发送与接收Kafka消息
目录一、背景二、环境依赖安装三、编写kakfa生产者消费者3.1 生产者3.2 消费者3.3 编译运行3.3.1 编译生产者消费者3.3.2 运行验证3.4 SASL认证kakfa3.5 结束语一、背景在实
C++传值、传址、传引用的区别和选择小结
目录传值传址传引用如何选择合适的参数传递方式在C++中,参数传递方式主要有三种:传值(pass by value)、传址(pass by address)、传引用(pass by reference)。每种方式都有其特定的使
C++如何实现sha256算法
目录概述CHP_Sha256总结概述SHA-256,英文全称为Secure Hash Algorithm 256-bit,是一种广泛使用的密码散列函数,属于SHA-2家族。SHA-256算法由美国国家安全局(NSA)设计,并由美国国
C语言中的断言函数assert详解
简介assert 是 C 语言中的一个宏,用于在程序运行时进行条件检查,主要用于调试目的。它在 <assert.h> 头文件中定义,用于验证程序中的假设条件是否成立,如果不成立,程序将打印错误
C++之assert推荐用法及注意事项
目录1.引言2.简单示例3.推荐使用方法4.常见使用场景和注意事项4.1.检查参数的合法性4.2.assert不能使用改变环境的语句4.3.在未知的逻辑中添加assert(false)5.总结1.引言ass
Qt中connect()函数及用法详解
目录一、基本概念二、用法1.旧版用法(Qt4和早期Qt5)2.新版用法(推荐)3.自动连接(无需使用connect()函数)4.Lambda表达式(Qt5.4)三、断开连接disconnect()1.为什么使用disconnect()2.
深入解读C++ 内联函数inline|nullptr
目录一、inline关键字1.1 什么是内联函数?1.2 为什么会有内联函数?1.2.1 回顾宏1.2.2 宏的改进–内联函数1.3 内联函数的特性二、指针空值nullptr2.1 C和C++中NULL的含义
vscode远程连接服务器(免密登录+远程开发)
目录1.获取服务器IP2.安装并且启用ssh服务3.在vscode中远程连接 4.实现免密登录vscode的远程连接功能十分方便,可以让我们在一个开发工具中实现完整的工作流,下面介绍如何在vs
C++实现LRU缓存的操作方法
目录LRU的概念哈希表(unordered_map)主要特性常用操作双向链表(list)特性常用操作LRU缓存(C++)初始化状态LRU的概念LRU(Least Recently Used,最近最少使用)是一种常用的缓存淘汰策略,
使用C语言生成图片的base64编码的代码实现
目录一、前言二、代码实操2.1 将二进制数据转为Base64编码2.2 实现图片的base64编码和解码一、前言Base64编码是一种广泛使用的编码方案,将任意二进制数据转换为可打印的ASCI
C语言strcat函数详解:字符串追加的利器
目录一、strcat函数的简介二、strcat函数的使用三、strcat函数的注意事项四、strcat函数的模拟实现一、strcat函数的简介strcat函数用于将源字符串追加到目标字符串的末尾,并
C++之thread_local变量的一些用法
目录1.C++ 的存储类型1.1.存储周期(Storage duration)1.2.存储类型说明符(Storage class specifiers)1.3.存储类型说明符与存储周期的关系2.thread_local简介3.thread_local 应
c++栈内存和堆内存的基本使用小结
c++栈内存和堆内存的基本使用#include <iostream>// 定义一个简单的结构体struct Person { std::string name; int age;};int main() { // 栈内存分配 int a = 10; //
C++11标准库 互斥锁 <mutex> 详解
目录<mutex>std::call_once函数例程:使用call_once实现的单例模式std::mutex类 -- 独占互斥锁成员函数std::recursive_mutex类 -- 递归互斥锁使用注意:描述:std::timed_mute
C++实现字符串元音字母反转的两种方法
目录C++实现字符串元音字母反转的巧妙方法示例方法一:利用数据结构存储元音位置和字符并反转代码实现1. 如何在C++中存储数字和字符并支持翻转2. 判断字符是否在列表中3. 巧