当前位置: 首页 > news >正文

数据结构C语言描述8(图文结合)--哈希、哈希冲突、开放地址法、链地址法等实现

前言

  • 这个专栏将会用纯C实现常用的数据结构和简单的算法;
  • 有C基础即可跟着学习,代码均可运行;
  • 准备考研的也可跟着写,个人感觉,如果时间充裕,手写一遍比看书、刷题管用很多,这也是本人采用纯C语言实现的原因之一;
  • 欢迎收藏 + 关注,本人将会持续更新。

文章目录

    • 什么是哈希
    • 哈希构造函数
    • 哈希解决冲突方法
      • 开放地址寻址法
      • 链地址法
    • 数组哈希案例实现
      • 封装
      • 创建哈希
      • 得到哈希映射值
      • 插入数据
      • 哈希查找
      • 总代码
    • 链表哈希案例实现
      • 封装
      • 插入
      • 查找
      • 总代码

什么是哈希

📘 概念:哈希结构(Hash Table)也被称为散列表,是一种用于实现字典(Dictionary)的数据结构。

重点:散列表,这个刷过算法的人应该都知道这个数据结果,散列表的特点就是查找特别快典型应用:判断A集合是否存在B集合;字典结构,我感觉学过Python或者JS都很清楚这个特点了;

🔴 重点概念

  • 哈希结构通过键Key映射到值Value的过程称为哈希映射学过数学应该都知道这个概念,函数就是典型的映射关系;
  • 哈希函数:将映射到一个存储位置的函数;

用处

哈希用处很多,最核心的应用是查找,哈希查找速度很快,如:用数组作为哈希结构容器,假设我们要存储一段数据(1, 5, 100, 10000, 100000),想要查找最快,找到数组下标即可但是这个最大值很大(100000),如果申请这么大的内存,储存量却很少,这就造成了内存浪费,但是用哈希结构的一些方法,可以很大的节省时间数组也是一种哈希结构,这个后面我们会讲。

哈希构造函数

🏡 概念 哈希构造函数(Hash Constructor)是哈希结构中的一种函数,用于将键(Key)映射到哈希表中的位置。哈希构造函数通常是一个确定性函数,即对于相同的键,哈希构造函数总是返回相同的哈希值。哈希构造函数的设计非常关键,它直接影响哈希结构的查找、插入和删除等操作的效率。

重点

  • 哈希函数:将键值映射到哈希表中位置;
  • 哈希构造函数通常是一个确定性函数,即对于相同的键,哈希构造函数总是返回相同的哈希值,键与射的值相互对于,具有唯一性
  • 哈希构造函数的设计非常关键,但是这个一般我感觉需要结合业务场景,根据不同数据从而选取不同的哈希函数,下面会有一些常用的哈希函数。

🌓 哈希构造函数的设计需要满足以下几个要求:

  • 一致性:对于相同的键,哈希构造函数应该总是返回相同的哈希值。
  • 均匀性:哈希构造函数应该尽可能均匀地将键映射到哈希表中的位置,以避免哈希冲突。
  • 高效性:哈希构造函数的计算时间应该尽可能短,以提高哈希结构的操作效率。

🌌 哈希构造函数的设计方法有很多种,常见的方法包括:

  • 直接寻址法(Direct Addressing):将键直接作为哈希表中的位置,适用于键的范围比较小的情况。

  • 除留余数法(Division Method):将键除以一个不大于哈希表大小的质数,然后取余数作为哈希值,h*(*k)= k mod mm 是哈希表的大小,即输出哈希值的范围,这个也是最常用的,一般来说,m不能过于靠近2的幂

  • 乘法哈希法(Multiplicative Hashing):将键乘以一个常数A(0<A<1),然后取乘积的小数部分乘以哈希表大小作为哈希值。

    在这里插入图片描述

  • 一次探测法(Linear Probing):当发生哈希冲突时,依次向后探测空桶,直到找到空桶或者遍历整个哈希表。

  • 双重哈希法(Double Hashing):使用两个不同的哈希函数,当发生哈希冲突时,依次使用两个哈希函数计算出新的哈希值,直到找到空桶或者遍历整个哈希表。

🌾 当然还有其他,注意:像除留余数法,为什么需要除以不大于哈希表最大大小的质数,这是是有严格的数学证明,可以减少哈希冲突概率,记住即可。

哈希解决冲突方法

这个有很多,如:开放地址寻址法、再次哈希法、链地址法、建立公共溢出区,这里只讲解,开放地址寻址法和链地址法。

开放地址寻址法

开发地址寻址法就是在发生哈希冲突的时候,在哈希映射那个点往后寻找,寻找到一个空位即可。

在这里插入图片描述

在这里插入图片描述

链地址法

链地址法就是用一个链表,当发生哈希冲突的时候,在哈希映射那个位置,拉一条链表,将数据填入链表中。

在这里插入图片描述

数组哈希案例实现

封装

// 这里假设存储的数据是这个,key是自己抽象出来的
typedef struct Data {int key;char buffer[20];
}Data;typedef struct Hash {Data** data;int p;int count;
}Hash;

创建哈希

Hash* create_hash(int p)
{Hash* hash = (Hash*)calloc(1, sizeof(Hash));assert(hash);hash->data = (Data**)calloc(p, sizeof(Data));assert(hash->data);hash->p = p;return hash;
}

得到哈希映射值

// 如果相同key值,则覆盖
int get_index(Hash* hash, Data data)
{assert(hash);int pos = data.key % hash->p;int curPos = pos;do {if (hash->data[curPos] == NULL || hash->data[curPos]->key == data.key) {return curPos;}curPos = (curPos + 1) % hash->p;} while (curPos != pos);return -1;   // 找不到,则当前满了,这里假设数据能够存储
}

插入数据

void push(Hash* hash, Data data)
{assert(hash);int pos = get_index(hash, data);if (pos == -1) {return;}if (hash->data[pos] == NULL) {Data* newData = (Data*)calloc(1, sizeof(Data));assert(newData);hash->data[pos] = newData;// 内存拷贝memcpy(hash->data[pos], &data, sizeof(data));}else {if (hash->data[pos]->key == data.key) {// 字符串拷贝strcpy(hash->data[pos]->buffer, data.buffer);}}hash->count++;
}

哈希查找

循环查找一圈看是否能找到。

Data* search(Hash* hash, int key)
{assert(hash);int pos = key % hash->count;int curPos = pos;do {if (hash->data[curPos] == NULL) {return NULL;}if (hash->data[curPos]->key == key) {return hash->data[curPos];}curPos = (curPos + 1) % hash->p;} while (pos != curPos);return NULL;
}

总代码

#include <stdio.h>
#include <stdbool.h>
#include <stdlib.h>
#include <assert.h>
#include <string.h>/*f(key) = key / p;
*/// 这里假设存储的数据是这个,key是自己抽象出来的
typedef struct Data {int key;char buffer[20];
}Data;typedef struct Hash {Data** data;int p;int count;
}Hash;Hash* create_hash(int p)
{Hash* hash = (Hash*)calloc(1, sizeof(Hash));assert(hash);hash->data = (Data**)calloc(p, sizeof(Data));assert(hash->data);hash->p = p;return hash;
}// 如果相同key值,则覆盖
int get_index(Hash* hash, Data data)
{assert(hash);int pos = data.key % hash->p;int curPos = pos;do {if (hash->data[curPos] == NULL || hash->data[curPos]->key == data.key) {return curPos;}curPos = (curPos + 1) % hash->p;} while (curPos != pos);return -1;   // 找不到,则当前满了,这里假设数据能够存储
}void push(Hash* hash, Data data)
{assert(hash);int pos = get_index(hash, data);if (pos == -1) {return;}if (hash->data[pos] == NULL) {Data* newData = (Data*)calloc(1, sizeof(Data));assert(newData);hash->data[pos] = newData;// 内存拷贝memcpy(hash->data[pos], &data, sizeof(data));}else {if (hash->data[pos]->key == data.key) {// 字符串拷贝strcpy(hash->data[pos]->buffer, data.buffer);}}hash->count++;
}void print_hash(Hash* hash)
{assert(hash);for (int i = 0; i < hash->p; i++) {if (hash->data[i] == NULL) {printf("NULL\n");}else {printf("%d %s\n", hash->data[i]->key, hash->data[i]->buffer);}}
}Data* search(Hash* hash, int key)
{assert(hash);int pos = key % hash->count;int curPos = pos;do {if (hash->data[curPos] == NULL) {return NULL;}if (hash->data[curPos]->key == key) {return hash->data[curPos];}curPos = (curPos + 1) % hash->p;} while (pos != curPos);return NULL;
}int size(Hash* hash)
{assert(hash);return hash->count;
}bool empty(Hash* hash)
{assert(hash);return hash->count == 0;
}int main()
{Hash* hash = create_hash(11);Data data[8] = { 1,"小美",11,"小芳",25,"花花",38,"coco",45,"小帅",88,"baby",65,"小丽",75,"小小" };for (int i = 0; i < 8; i++) {push(hash, data[i]);}print_hash(hash);Data* sdata = search(hash, 45);printf("search: %d %s\n", sdata->key, sdata->buffer);return 0;
}

链表哈希案例实现

封装

// 数据封装
typedef struct Data {int key;char buffer[20];
}Data;// 横向链表节点封装(解决冲突节点)
typedef struct LNode {Data data;struct LNode* next;
}LNode;// 纵向链表节点封装
typedef struct SNode {Data data;struct SNode* snext;LNode* lnext;    // 解决冲突链表
}SNode;// 哈希封装
typedef struct Hash {SNode* headNode;int p;   // 余数int count;   // 存储的元素个数
}Hash;LNode* create_lnode(Data data)
{LNode* node = (LNode*)calloc(1, sizeof(LNode));assert(node);node->data = data;return node;
}SNode* create_snode(Data data)
{SNode* node = (SNode*)calloc(1, sizeof(SNode));assert(node);node->data = data;return node;
}Hash* create_hash(int p)
{Hash* hash = (Hash*)calloc(1, sizeof(Hash));assert(hash);hash->p = p;return hash;
}

插入

这个确实规矩有点多,如:

  • 第一步得到哈希映射值
    • 如果在主链表中已经存在了,则在主链表映射位置拉一条链表,头插(这里是)
    • 如果主链表中不存在,则插入主链表中
// 插入
// 规则有点多
void push(Hash* hash, Data data)
{assert(hash);// 创建节点SNode* new_node = create_snode(data);int pos = data.key % hash->p;// 没有,则纵向链表生成if (hash->headNode == NULL) {hash->headNode = new_node;}else {   // 检查SNode* insert = hash->headNode;SNode* prevInsert = NULL;// if (insert->data.key % hash->p > pos) {new_node->snext = hash->headNode;hash->headNode = new_node;hash->count++;}else {while (insert != NULL && (insert->data.key % hash->p < pos)) {prevInsert = insert;insert = insert->snext;}// if (insert == NULL) {prevInsert->snext = new_node;hash->count++;}else if (insert->data.key % hash->p == pos) {//if (insert->data.key == data.key) {strcpy(insert->data.buffer, data.buffer);}else {LNode* curNode = insert->lnext;if (curNode == NULL) {insert->lnext = create_lnode(data);hash->count++;}else {// 横向插入,头插while (curNode != NULL && curNode->data.key != data.key) {curNode = curNode->next;}// 没有,头插if (curNode == NULL) {LNode* temp = create_lnode(data);temp->next = insert->lnext;insert->lnext = temp;hash->count++;}else {   // 有,覆盖strcpy(curNode->data.buffer, data.buffer);}}}}else {new_node->snext = insert;prevInsert->snext = new_node;hash->count++;}}}}

查找

这个查找分为两个步骤:

  1. 主链表中找(纵向)
  2. 在映射值的那个链表中找
// 打印
void print_hash(Hash* hash)
{assert(hash);SNode* rTemp = hash->headNode;while (rTemp) {printf("key: %d, value: %s", rTemp->data.key, rTemp->data.buffer);if (rTemp->lnext != NULL) {printf(" 【");LNode* lTemp = rTemp->lnext;while (lTemp != NULL) {printf("key: %d, value: %s", lTemp->data.key, lTemp->data.buffer);lTemp = lTemp->next;}printf("  】");//  看清楚这个是行的数据}rTemp = rTemp->snext;printf("\n");}}// 查找
enum MatchType
{NoMatch,  // 没有RowMatch,  // 纵找到ColMatch   // 横找到
};typedef struct Match {int type;union {LNode* lnode;SNode* snode;};
}Match;Match search(Hash* hash, Data data)
{assert(hash);Match res = { 0 };int pos = data.key % hash->p;SNode* rTemp = hash->headNode;while (rTemp) {if (pos == rTemp->data.key % hash->p) {if (data.key == rTemp->data.key) {res.type = RowMatch;res.snode = rTemp;return res;}else {LNode* lTemp = rTemp->lnext;while (lTemp) {if (lTemp->data.key == data.key) {res.type = ColMatch;res.lnode = lTemp;return res;}lTemp == lTemp->next;}}}rTemp = rTemp->snext;}return res;
}void print_search(Match match)
{switch (match.type){case NoMatch:printf("没有找到\n");break;case RowMatch:printf("找到了,key: %d, value: %s\n", match.snode->data.key, match.snode->data.buffer);break;case ColMatch:printf("找到了,key: %d, value: %s\n", match.lnode->data.key, match.lnode->data.buffer);break;}
}

总代码

#include <stdio.h>
#include <stdlib.h>
#include <stdbool.h>
#include <assert.h>
#include <string.h>// 链表实现哈希,使用链表法解决冲突,要注意的是封装会比较多
// 假设不处理重复值// 数据封装
typedef struct Data {int key;char buffer[20];
}Data;// 横向链表节点封装(解决冲突节点)
typedef struct LNode {Data data;struct LNode* next;
}LNode;// 纵向链表节点封装
typedef struct SNode {Data data;struct SNode* snext;LNode* lnext;    // 解决冲突链表
}SNode;// 哈希封装
typedef struct Hash {SNode* headNode;int p;   // 余数int count;   // 存储的元素个数
}Hash;LNode* create_lnode(Data data)
{LNode* node = (LNode*)calloc(1, sizeof(LNode));assert(node);node->data = data;return node;
}SNode* create_snode(Data data)
{SNode* node = (SNode*)calloc(1, sizeof(SNode));assert(node);node->data = data;return node;
}Hash* create_hash(int p)
{Hash* hash = (Hash*)calloc(1, sizeof(Hash));assert(hash);hash->p = p;return hash;
}// 插入
// 规则有点多
void push(Hash* hash, Data data)
{assert(hash);// 创建节点SNode* new_node = create_snode(data);int pos = data.key % hash->p;// 没有,则纵向链表生成if (hash->headNode == NULL) {hash->headNode = new_node;}else {   // 检查SNode* insert = hash->headNode;SNode* prevInsert = NULL;// if (insert->data.key % hash->p > pos) {new_node->snext = hash->headNode;hash->headNode = new_node;hash->count++;}else {while (insert != NULL && (insert->data.key % hash->p < pos)) {prevInsert = insert;insert = insert->snext;}// if (insert == NULL) {prevInsert->snext = new_node;hash->count++;}else if (insert->data.key % hash->p == pos) {//if (insert->data.key == data.key) {strcpy(insert->data.buffer, data.buffer);}else {LNode* curNode = insert->lnext;if (curNode == NULL) {insert->lnext = create_lnode(data);hash->count++;}else {// 横向插入,头插while (curNode != NULL && curNode->data.key != data.key) {curNode = curNode->next;}// 没有,头插if (curNode == NULL) {LNode* temp = create_lnode(data);temp->next = insert->lnext;insert->lnext = temp;hash->count++;}else {   // 有,覆盖strcpy(curNode->data.buffer, data.buffer);}}}}else {new_node->snext = insert;prevInsert->snext = new_node;hash->count++;}}}}// 打印
void print_hash(Hash* hash)
{assert(hash);SNode* rTemp = hash->headNode;while (rTemp) {printf("key: %d, value: %s", rTemp->data.key, rTemp->data.buffer);if (rTemp->lnext != NULL) {printf(" 【");LNode* lTemp = rTemp->lnext;while (lTemp != NULL) {printf("key: %d, value: %s", lTemp->data.key, lTemp->data.buffer);lTemp = lTemp->next;}printf("  】");//  看清楚这个是行的数据}rTemp = rTemp->snext;printf("\n");}}// 查找
enum MatchType
{NoMatch,  // 没有RowMatch,  // 纵找到ColMatch   // 横找到
};typedef struct Match {int type;union {LNode* lnode;SNode* snode;};
}Match;Match search(Hash* hash, Data data)
{assert(hash);Match res = { 0 };int pos = data.key % hash->p;SNode* rTemp = hash->headNode;while (rTemp) {if (pos == rTemp->data.key % hash->p) {if (data.key == rTemp->data.key) {res.type = RowMatch;res.snode = rTemp;return res;}else {LNode* lTemp = rTemp->lnext;while (lTemp) {if (lTemp->data.key == data.key) {res.type = ColMatch;res.lnode = lTemp;return res;}lTemp == lTemp->next;}}}rTemp = rTemp->snext;}return res;
}void print_search(Match match)
{switch (match.type){case NoMatch:printf("没有找到\n");break;case RowMatch:printf("找到了,key: %d, value: %s\n", match.snode->data.key, match.snode->data.buffer);break;case ColMatch:printf("找到了,key: %d, value: %s\n", match.lnode->data.key, match.lnode->data.buffer);break;}
}int main()
{Hash* hash = create_hash(11);Data data[8] = { 1,"小美",11,"小芳",25,"花花",38,"coco",42,"小帅",88,"baby",66,"小丽",77,"小小" };for (int i = 0; i < 8; i++) {push(hash, data[i]);}print_hash(hash);printf("********************\n");Match search_res = search(hash, data[3]);print_search(search_res);return 0;
}

相关文章:

数据结构C语言描述8(图文结合)--哈希、哈希冲突、开放地址法、链地址法等实现

前言 这个专栏将会用纯C实现常用的数据结构和简单的算法&#xff1b;有C基础即可跟着学习&#xff0c;代码均可运行&#xff1b;准备考研的也可跟着写&#xff0c;个人感觉&#xff0c;如果时间充裕&#xff0c;手写一遍比看书、刷题管用很多&#xff0c;这也是本人采用纯C语言…...

自动化立体库安全使用管理制度完整版

导语 大家好&#xff0c;我是社长&#xff0c;老K。专注分享智能制造和智能仓储物流等内容。欢迎大家到本文底部评论区留言。 新书《智能物流系统构成与技术实践》人俱乐部 完整版文件和更多学习资料&#xff0c;请球友到知识星球【智能仓储物流技术研习社】自行下载。 以下是《…...

云打印之拼多多打印组件交互协议

拼多多打印组件交互协议相关介绍如下&#xff1a; 1、打印组件下载地址 http://meta.pinduoduo.com/api/one/app/v1/lateststable?appIdcom.xunmeng.pddprint&platformwindows&subTypemain 2、socket连接端口 如果是http的话&#xff0c;端口是5000 socket new …...

TCP 演进之路:软硬件跷跷板与新征程

今天依旧是与 TCP 相关的一个短评。 先看软硬件间的胶着。晶体管诞生以来&#xff0c;硬件一直在突飞猛进发展&#xff0c;后来这个事被摩尔定律正则化&#xff0c;人们开始可以预测未来&#xff0c;但即便如此&#xff0c;软件依然跟不上来&#xff0c;不过几年&#xff0c;老…...

React最小状态管理Jotai

Jotai 状态管理 1. 简介 Jotai 是一个基于原子 atom 概念的 React 状态管理库&#xff0c;它提供了简单且灵活的方式来管理应用状态, 而且非常轻量&#xff0c; 大厂用的非常多。 JotaiRedux适合单个页面&#xff0c;多次用到的属性适合全局公共属性超级轻量&#xff08;与use…...

计算机网络 —— 网络编程(TCP)

计算机网络 —— 网络编程&#xff08;TCP&#xff09; TCP和UDP的区别TCP (Transmission Control Protocol)UDP (User Datagram Protocol) 前期准备listen &#xff08;服务端&#xff09;函数原型返回值使用示例注意事项 accpect &#xff08;服务端&#xff09;函数原型返回…...

字玩FontPlayer开发笔记4 性能优化 首屏加载时间优化

字玩FontPlayer开发笔记4 性能优化 首屏加载时间优化 字玩FontPlayer是笔者开源的一款字体设计工具&#xff0c;使用Vue3 ElementUI开发&#xff0c;源代码&#xff1a; github: https://github.com/HiToysMaker/fontplayer gitee: https://gitee.com/toysmaker/fontplayer …...

RabbitMQ案例

1. 导入依赖 <!--AMQP依赖&#xff0c;包含RabbitMQ--><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-amqp</artifactId></dependency> 发送消息 注入RabbitTemplate Autowired RabbitT…...

智能工厂的设计软件 应用场景的一个例子:为AI聊天工具添加一个知识系统 之13 方案再探之4:特定于领域的模板 之 div模型(完整版)

前景提要 整个“方案再探”篇 围绕着如何将项目附件文档中Part 1 部分中给出的零散问题讨论整理、重组为一个结构化的设计文档。为此提出了讨论题目&#xff1a; 特定于领域的模板--一个三套接的hoc结构 它是本项目actors 的剧本原型。其地位&#xff1a; 祖传代码脚本模板…...

WebRtc02:WebRtc架构、目录结构、运行机制

整体架构 WebRtc主要分为三层&#xff1a; CAPI层&#xff1a;外层调用Session管理核心层&#xff1a;包括视频引擎、音频引擎、网络传输 可由使用者重写视频引擎&#xff1a;编解码器、视频缓存、视频增强音频引擎&#xff1a;编解码器、音频缓存、回音消除、降噪传输&#x…...

数据结构复习 (顺序查找,对半查找,斐波那契查找,插值查找,分块查找)

查找&#xff08;检索&#xff09;&#xff1a; 定义&#xff1a;从给定的数据中找到对应的K 1&#xff0c;顺序查找&#xff1a; O(n)的从前向后的遍历 2&#xff0c;对半查找&#xff0c;要求有序 从中间开始查找&#xff0c;每次检查中间的是否正确&#xff0c;不正确就…...

el-input输入框需要支持多输入,最后传输给后台的字段值以逗号分割

需求&#xff1a;一个输入框字段需要支持多次输入&#xff0c;最后传输给后台的字段值以逗号分割 解决方案&#xff1a;结合了el-tag组件的动态编辑标签 那块的代码 //子组件 <template><div class"input-multiple-box" idinputMultipleBox><div>…...

C# 枚举格式字符串

总目录 前言 当前文章为 C# 中的格式设置(格式化字符串) 大全 中的一个小章节。 一、概述 1. 基本信息 可以使用 Enum.ToString 方法&#xff0c;新建表示枚举成员的数字值、十六进制值或字符串值的字符串对象。枚举格式说明符不区分大小写。 二、自定义数字格式说明符详解…...

【51单片机-零基础chapter1】

安装软件(配套的有,不多赘述) 1.管理员身份运行keil和破解软件kegen 将CID代码复制粘贴到 一定要管理员方式,不然会error 插入板子 我的电脑,管理 1.如果是拯救者,查看端口,如果没有则显示隐藏 2.苹果不知道,好像不可以 3.其他电脑在"其他设备找" (注:本人在校已…...

记录:导出功能:接收文件流数据进行导出(vue3)

请求接口&#xff1a;一定要加responseType: blob 后端返回数据&#xff1a; api.js export function export() {return request({url: dev/api/export,method: get,responseType: blob,//一定要加}) } vue&#xff1a; import {export} from /api// 导出 const exportTab…...

基于Spring Boot + Vue3实现的在线汽车保养维修预约管理系统源码+文档

前言 基于Spring Boot Vue3实现的在线汽车保养维修预约管理系统是一种前后端分离架构的应用&#xff0c;它结合了Java后端开发框架Spring Boot和现代JavaScript前端框架Vue.js 3.0的优势。这样的系统可以为汽车服务站提供一个高效的平台来管理客户的预约请求 技术选型 系统…...

PHP框架+gatewayworker实现在线1对1聊天--接收消息(7)

文章目录 接收消息的原理接收消息JavaScript代码 接收消息的原理 接收消息&#xff0c;就是接受服务器转发的客户端消息。并不需要单独创建函数&#xff0c;因为 ws.onmessage会自动接收消息。我们需要在这个函数里进行处理。因为初始化的时候&#xff0c;已经处理的init类型的…...

18.1、网络安全策略分类 流程 内容

目录 网络安全测评概况网络安全测评类型—基于测评目标分类网络安全测评类型—基于实施方式分类网络安全测评类型—基于测评对象保密性分类网络安全等级保护测评内容网络安全测评流程与内容 网络安全测评概况 网络安全测评&#xff0c;它是指参照一定的标准规范要求&#xff0…...

深入理解连接池:从数据库到HTTP的优化之道

在现代应用开发中&#xff0c;高效的资源管理是关键&#xff0c;其中连接池&#xff08;Connection Pool&#xff09;技术起到了至关重要的作用。本文将带你深入了解连接池的概念及其在数据库和HTTP通信中的应用&#xff0c;结合 JDBC 与 Druid 的关系&#xff0c;以及 HttpURL…...

【2025最新计算机毕业设计】基于SpringBoot+Vue智慧养老医护系统(高质量源码,提供文档,免费部署到本地)【提供源码+答辩PPT+文档+项目部署】

作者简介&#xff1a;✌CSDN新星计划导师、Java领域优质创作者、掘金/华为云/阿里云/InfoQ等平台优质作者、专注于Java技术领域和学生毕业项目实战,高校老师/讲师/同行前辈交流。✌ 主要内容&#xff1a;&#x1f31f;Java项目、Python项目、前端项目、PHP、ASP.NET、人工智能…...

vue3 字体颜色设置的多种方式

在Vue 3中设置字体颜色可以通过多种方式实现&#xff0c;这取决于你是想在组件内部直接设置&#xff0c;还是在CSS/SCSS/LESS等样式文件中定义。以下是几种常见的方法&#xff1a; 1. 内联样式 你可以直接在模板中使用style绑定来设置字体颜色。 <template><div :s…...

论文浅尝 | 基于判别指令微调生成式大语言模型的知识图谱补全方法(ISWC2024)

笔记整理&#xff1a;刘治强&#xff0c;浙江大学硕士生&#xff0c;研究方向为知识图谱表示学习&#xff0c;大语言模型 论文链接&#xff1a;http://arxiv.org/abs/2407.16127 发表会议&#xff1a;ISWC 2024 1. 动机 传统的知识图谱补全&#xff08;KGC&#xff09;模型通过…...

基于Docker Compose部署Java微服务项目

一. 创建根项目 根项目&#xff08;父项目&#xff09;主要用于依赖管理 一些需要注意的点&#xff1a; 打包方式需要为 pom<modules>里需要注册子模块不要引入maven的打包插件&#xff0c;否则打包时会出问题 <?xml version"1.0" encoding"UTF-8…...

[Java恶补day16] 238.除自身以外数组的乘积

给你一个整数数组 nums&#xff0c;返回 数组 answer &#xff0c;其中 answer[i] 等于 nums 中除 nums[i] 之外其余各元素的乘积 。 题目数据 保证 数组 nums之中任意元素的全部前缀元素和后缀的乘积都在 32 位 整数范围内。 请 不要使用除法&#xff0c;且在 O(n) 时间复杂度…...

Java求职者面试指南:Spring、Spring Boot、MyBatis框架与计算机基础问题解析

Java求职者面试指南&#xff1a;Spring、Spring Boot、MyBatis框架与计算机基础问题解析 一、第一轮提问&#xff08;基础概念问题&#xff09; 1. 请解释Spring框架的核心容器是什么&#xff1f;它在Spring中起到什么作用&#xff1f; Spring框架的核心容器是IoC容器&#…...

基于 TAPD 进行项目管理

起因 自己写了个小工具&#xff0c;仓库用的Github。之前在用markdown进行需求管理&#xff0c;现在随着功能的增加&#xff0c;感觉有点难以管理了&#xff0c;所以用TAPD这个工具进行需求、Bug管理。 操作流程 注册 TAPD&#xff0c;需要提供一个企业名新建一个项目&#…...

Go 语言并发编程基础:无缓冲与有缓冲通道

在上一章节中&#xff0c;我们了解了 Channel 的基本用法。本章将重点分析 Go 中通道的两种类型 —— 无缓冲通道与有缓冲通道&#xff0c;它们在并发编程中各具特点和应用场景。 一、通道的基本分类 类型定义形式特点无缓冲通道make(chan T)发送和接收都必须准备好&#xff0…...

【JVM】Java虚拟机(二)——垃圾回收

目录 一、如何判断对象可以回收 &#xff08;一&#xff09;引用计数法 &#xff08;二&#xff09;可达性分析算法 二、垃圾回收算法 &#xff08;一&#xff09;标记清除 &#xff08;二&#xff09;标记整理 &#xff08;三&#xff09;复制 &#xff08;四&#xff…...

ubuntu系统文件误删(/lib/x86_64-linux-gnu/libc.so.6)修复方案 [成功解决]

报错信息&#xff1a;libc.so.6: cannot open shared object file: No such file or directory&#xff1a; #ls, ln, sudo...命令都不能用 error while loading shared libraries: libc.so.6: cannot open shared object file: No such file or directory重启后报错信息&…...

LLaMA-Factory 微调 Qwen2-VL 进行人脸情感识别(二)

在上一篇文章中,我们详细介绍了如何使用LLaMA-Factory框架对Qwen2-VL大模型进行微调,以实现人脸情感识别的功能。本篇文章将聚焦于微调完成后,如何调用这个模型进行人脸情感识别的具体代码实现,包括详细的步骤和注释。 模型调用步骤 环境准备:确保安装了必要的Python库。…...