redis基本数据结构
基本数据结构
String
String是Redis中最常见的数据存储类型:
其基本编码方式是RAW,基于简单动态字符串(SDS)实现,存储上限为512mb。
-
如果存储的SDS长度小于44字节,则会采用EMBSTR编码,此时object head与SDS是一段连续空间。申请内存时只需要调用一次内存分配函数,效率更高。
存储结构如下所示:
源码
-
如果存储的SDS长度小于44字节,则会采用EMBSTR编码,此时object head与SDS是一段连续空间。申请内存时只需要调用一次内存分配函数,效率更高。
存储结构如下所示:
-
如果存储的字符串是整数值,并且大小在LONG_MAX范围内,则会采用INT编码:直接将数据保存在RedisObject的ptr指针位置(刚好8字节),不再需要SDS了。
存储结构如下所示:
List
Redis的List类型可以从首、尾操作列表中的元素:
为了实现从首、尾操作列表中的元素的特点,可以看看之前的底层数据实现哪类可以实现List
-
LinkedList :普通链表,可以从双端访问,内存占用较高,内存碎片较多
-
ZipList :压缩列表,可以从双端访问,内存占用低,存储上限低
-
QuickList:LinkedList + ZipList,可以从双端访问,内存占用较低,包含多个ZipList,存储上限高
这3类都可以实现收尾操作列表
那redis咋选择的呢
在3.2版本之前,Redis采用ZipList和LinkedList来实现List,当元素数量小于512并且元素大小小于64字节时采用ZipList编码,超过则采用LinkedList编码。
在3.2版本之后,Redis统一采用QuickList来实现List:
void pushGenericCommand(client *c, int where, int xx) {int j;// 尝试找到KEY对应的listrobj *lobj = lookupKeyWrite(c->db, c->argv[1]);// 检查类型是否正确if (checkType(c,lobj,OBJ_LIST)) return;// 检查是否为空if (!lobj) {if (xx) {addReply(c, shared.czero);return;}// 为空,则创建新的QuickListlobj = createQuicklistObject();quicklistSetOptions(lobj->ptr, server.list_max_ziplist_size,server.list_compress_depth);dbAdd(c->db,c->argv[1],lobj);}// 略 ...
}
robj *createQuicklistObject(void) {// 申请内存并初始化QuickListquicklist *l = quicklistCreate();// 创建RedisObject,type为OBJ_LIST// ptr指向 QuickListrobj *o = createObject(OBJ_LIST,l);// 设置编码为 QuickListo->encoding = OBJ_ENCODING_QUICKLIST;return o;
}
List底层实现结构如下:
至于为啥3.2版本之后改成了QuickList,原因如下:
LinkedList内存地址不连续,碎片多,内存占用较高
ZipList内存占用低,存储上限低
因此为了吸取优点剔除缺点,LinkedList作为ptr实际指向的存储结构,在LinkedList的节点中指向ZipList,使得内存空间能够连续,同时本质ptr指向的是LinkedList,存储上限大大提高了
Set
Set是Redis中的单列集合,满足下列特点:
-
不保证有序性
-
保证元素唯一
-
求交集、并集、差集
可以看出,Set对查询元素的效率要求非常高,思考一下,什么样的数据结构可以满足?
HashTable,也就是Redis中的Dict,不过Dict是双列集合(可以存键、值对)
其中可以看出通过hashtable的特点:根据key计算出hash值(h),然后利用 h & sizemask来计算元素应该存储到数组中的哪个索引位置。保证元素唯一
在之前使用redis的过程中知道,set只会存储一个数值,和String、List不同都有key、value,因此实际redis在底层实现Set过程中DictEntry的key存储用户输入的数值,而value存储null
Set还有个特点,当存储的所有数据都是整数,并且元素数量不超过set-max-intset-entries时,Set会采用IntSet编码,以节省内存。
set-max-intset-entries的默认值是512
如下为新建Set的底层调用 首先初始化数据结构
robj *setTypeCreate(sds value) {// 判断value是否是数值类型 long long if (isSdsRepresentableAsLongLong(value,NULL) == C_OK)// 如果是数值类型,则采用IntSet编码return createIntsetObject();// 否则采用默认编码,也就是HTreturn createSetObject();
}
INTSET
robj *createIntsetObject(void) {// 初始化INTSET并申请内存空间intset *is = intsetNew();// 创建RedisObjectrobj *o = createObject(OBJ_SET,is);// 指定编码为INTSETo->encoding = OBJ_ENCODING_INTSET;return o;
}
Dict
robj *createSetObject(void) {// 初始化Dict类型,并申请内存dict *d = dictCreate(&setDictType,NULL);// 创建RedisObjectrobj *o = createObject(OBJ_SET,d);// 设置encoding为HTo->encoding = OBJ_ENCODING_HT;return o;
}
其次再调用增加元素函数
当存储的所有数据都是整数,并且元素数量不超过set-max-intset-entries时
Sadd 5 10 20
1,原本set存储数据 5 10 20,由于5 10 20均为整数,且这3个数字未超过set-max-intset-entries即512个字节,所以底层数据实现用的inset编码
2,现在进行插入新数据 sadd s1 m1 此时加入了两个字符串
3,调用底层setTypeAdd函数,判断value不属于整数,则调用setTypeConvert函数进行插入数据和编码转换
插入Dict数据,同时把原本的整数存储进Dict的DictEntry中
ZSet
ZSet也就是SortedSet,其中每一个元素都需要指定一个score值和member值:
-
可以根据score值排序后
-
member必须唯一
-
可以根据member查询分数
因此,zset底层数据结构必须满足键值存储、键必须唯一、可排序这几个需求。之前学习的哪种编码结构可以满足?
SkipList:可以排序,并且可以同时存储score和ele值(member),其本质有点像二分和二叉树
HT(Dict):可以键值存储,并且可以根据key找value
接下来看看zset的底层实现源码
zset结构体定义
// zset结构
typedef struct zset {// Dict指针dict *dict;// SkipList指针zskiplist *zsl;
} zset;
新建zset
// zadd添加元素时,先根据key找到zset,不存在则创建新的zset
zobj = lookupKeyWrite(c->db,key);
if (checkType(c,zobj,OBJ_ZSET)) goto cleanup;
// 判断是否存在
if (zobj == NULL) { // zset不存在if (server.zset_max_ziplist_entries == 0 ||server.zset_max_ziplist_value < sdslen(c->argv[scoreidx+1]->ptr)){ // zset_max_ziplist_entries设置为0就是禁用了ZipList,// 或者value大小超过了zset_max_ziplist_value,采用HT + SkipListzobj = createZsetObject();} else { // 否则,采用 ZipListzobj = createZsetZiplistObject();}dbAdd(c->db,key,zobj);
}
// ....
zsetAdd(zobj, score, ele, flags, &retflags, &newscore);
通过SkipList和Dict新建createZsetObject
robj *createZsetObject(void) {zset *zs = zmalloc(sizeof(*zs));robj *o;// 创建Dictzs->dict = dictCreate(&zsetDictType,NULL);// 创建SkipListzs->zsl = zslCreate(); o = createObject(OBJ_ZSET,zs);o->encoding = OBJ_ENCODING_SKIPLIST;return o;
}
通过ZipList新建createZsetZiplistObject
robj *createZsetZiplistObject(void) {// 创建ZipListunsigned char *zl = ziplistNew();robj *o = createObject(OBJ_ZSET,zl);o->encoding = OBJ_ENCODING_ZIPLIST;return o;
}
从源码中可以看出zset有两种情况
1,当元素数量不多时,HT和SkipList的优势不明显,而且更耗内存。因此zset还会采用ZipList结构来节省内存,即调用createZsetZiplistObject函数,不过需要同时满足两个条件:
-
元素数量小于zset_max_ziplist_entries,默认值128
-
每个元素都小于zset_max_ziplist_value字节,默认值64
2,其它情况调用createZsetObject,是通过两种数据结构即SkipList和Dict一起实现的
Hash
Hash结构与Redis中的Zset非常类似:
-
都是键值存储
-
都需根据键获取值
-
键必须唯一
区别如下:
-
zset的键是member,值是score;hash的键和值都是任意值
-
zset要根据score排序;hash则无需排序
因此,Hash底层采用的编码与Zset也基本一致,只需要把排序有关的SkipList去掉即可
Hash结构默认采用ZipList编码,用以节省内存。 ZipList中相邻的两个entry 分别保存field和value
当数据量较大时,Hash结构会转为HT编码,也就是Dict,触发条件有两个:
-
ZipList中的元素数量超过了hash-max-ziplist-entries(默认512)
-
ZipList中的任意entry大小超过了hash-max-ziplist-value(默认64字节)
Hash存储结构如下:
feild即key和匹配的value存储地址是连续的,这是由于zipList本身的特点
接下来看看在一直存储数据过程中,Hash的底层数据结构如何转换
1,首先存储一系列key、value
2,一直增加数据,这个时候存储的元素数量超过了hash-max-ziplist-entries(默认512),或者key或者value的大小超过了ZipList中的任意entry大小超过了hash-max-ziplist-value(默认64字节),比如
Hset user1 "任意大于hash-max-ziplist-value的数值" value
这个时候entry存储的数值大于hash-max-ziplist-value,则会采用Dict存储
3,此时会进行编码转换,ZipList->Dict
原本存储在ZipList都会复制到DictEntry中
接下来看看redis源码咋实现的
1,存储数据
void hsetCommand(client *c) {// hset user1 name Jack age 21int i, created = 0;robj *o; // 略 ... // 判断hash的key是否存在,不存在则创建一个新的,默认采用ZipList编码if ((o = hashTypeLookupWriteOrCreate(c,c->argv[1])) == NULL) return;// 判断是否需要把ZipList转为DicthashTypeTryConversion(o,c->argv,2,c->argc-1);// 循环遍历每一对field和value,并执行hset命令for (i = 2; i < c->argc; i += 2)created += !hashTypeSet(o,c->argv[i]->ptr,c->argv[i+1]->ptr,HASH_SET_COPY); // 略 ...
}
1.1判断存储的key是否存在过 存在过,返回空
2,key不存在,采用Dict
3,调用hashTypeTryConversion函数进行数据存储
robj *hashTypeLookupWriteOrCreate(client *c, robj *key) {// 查找keyrobj *o = lookupKeyWrite(c->db,key);if (checkType(c,o,OBJ_HASH)) return NULL;// 不存在,则创建新的if (o == NULL) {o = createHashObject();dbAdd(c->db,key,o);}return o;
}
3.1,数据key不存在调用createHashObject函数进行存储 采用ZipList
robj *createHashObject(void) {// 默认采用ZipList编码,申请ZipList内存空间unsigned char *zl = ziplistNew();robj *o = createObject(OBJ_HASH, zl);// 设置编码o->encoding = OBJ_ENCODING_ZIPLIST;return o;
}
调用hashTypeTryConversion函数判断是否需把ZipList结构转换成Dict结构
void hashTypeTryConversion(robj *o, robj **argv, int start, int end) {int i;size_t sum = 0;// 本来就不是ZipList编码,什么都不用做了if (o->encoding != OBJ_ENCODING_ZIPLIST) return;// 依次遍历命令中的field、value参数for (i = start; i <= end; i++) {if (!sdsEncodedObject(argv[i]))continue;size_t len = sdslen(argv[i]->ptr);// 如果field或value超过hash_max_ziplist_value,则转为HTif (len > server.hash_max_ziplist_value) {hashTypeConvert(o, OBJ_ENCODING_HT);return;}sum += len;}// ziplist大小超过1G,也转为HTif (!ziplistSafeToAdd(o->ptr, sum))hashTypeConvert(o, OBJ_ENCODING_HT);
}
最后再调用hashTypeTryConversion函数执行实际存储操作
int hashTypeSet(robj *o, sds field, sds value, int flags) {int update = 0;// 判断是否为ZipList编码if (o->encoding == OBJ_ENCODING_ZIPLIST) {unsigned char *zl, *fptr, *vptr;zl = o->ptr;// 查询head指针fptr = ziplistIndex(zl, ZIPLIST_HEAD);if (fptr != NULL) { // head不为空,说明ZipList不为空,开始查找keyfptr = ziplistFind(zl, fptr, (unsigned char*)field, sdslen(field), 1);if (fptr != NULL) {// 判断是否存在,如果已经存在则更新update = 1;zl = ziplistReplace(zl, vptr, (unsigned char*)value,sdslen(value));}}// 不存在,则直接pushif (!update) { // 依次push新的field和value到ZipList的尾部zl = ziplistPush(zl, (unsigned char*)field, sdslen(field),ZIPLIST_TAIL);zl = ziplistPush(zl, (unsigned char*)value, sdslen(value),ZIPLIST_TAIL);}o->ptr = zl;/* 插入了新元素,检查list长度是否超出,超出则转为HT */if (hashTypeLength(o) > server.hash_max_ziplist_entries)hashTypeConvert(o, OBJ_ENCODING_HT);} else if (o->encoding == OBJ_ENCODING_HT) {// HT编码,直接插入或覆盖} else {serverPanic("Unknown hash encoding");}return update;
}
参考资料:
黑马redis
相关文章:
redis基本数据结构
基本数据结构 String String是Redis中最常见的数据存储类型: 其基本编码方式是RAW,基于简单动态字符串(SDS)实现,存储上限为512mb。 如果存储的SDS长度小于44字节,则会采用EMBSTR编码,此时ob…...
基于STM32景区环境监测系统的设计与实现(论文+源码)
1系统方案设计 根据系统功能的设计要求,展开基于STM32景区环境监测系统设计。如图2.1所示为系统总体设计框图。系统以STM32单片机作为系统主控模块,通过DHT11传感器、MQ传感器、声音传感器实时监测景区环境中的温湿度、空气质量以及噪音数据。系统监测环…...
使用冒泡排序模拟实现qsort函数
1.冒泡排序 #define _CRT_SECURE_NO_WARNINGS 1 #include <stdio.h>int main() {int arr[] { 0,2,5,3,4,8,9,7,6,1 };int sz sizeof(arr) / sizeof(arr[0]);//冒泡排序一共排序 sz-1 趟for (int i 0; i < sz - 1; i){//标志位,如果有序,直接…...
探秘Linux IO虚拟化:virtio的奇幻之旅
在当今数字化时代,虚拟化技术早已成为推动计算机领域发展的重要力量。想象一下,一台物理主机上能同时运行多个相互隔离的虚拟机,每个虚拟机都仿佛拥有自己独立的硬件资源,这一切是如何实现的呢?今天,就让我…...
在React中使用redux
一、首先安装两个插件 1.Redux Toolkit 2.react-redux 第一步:创建模块counterStore 第二步:在store的入口文件进行子模块的导入组合 第三步:在index.js中进行store的全局注入 第四步:在组件中进行使用 第五步:在组件中…...
从 C 到 C++:理解结构体中字符串的存储与操作
对于刚入门 C/C 的程序员来说,字符串的存储和操作可能是个容易混淆的知识点。在 C 中,std::string 提供了非常友好的接口,我们可以轻松地在结构体中使用字符串类型,无需关注底层细节。然而,在 C 语言中,字符…...
2.3学习总结
图: 1.图的基本概念 2.图的存储和遍历 3.最小生成树 4.最短路径 5.拓扑排序和关键路径 一、图的基本概念 图的定义:不允许没有顶点,但边集可以为空 {无向图 {有向图:边弧,弧头(有箭头)…...
wordpress代码结构解析
WordPress 是一个基于 PHP 和 MySQL 的开源内容管理系统(CMS),广泛用于构建网站和博客。要解析 WordPress 代码,首先需要了解其核心结构、主要文件和常用的函数。以下是 WordPress 代码解析的基本指南: --- ### 1. *…...
使用 Numpy 自定义数据集,使用pytorch框架实现逻辑回归并保存模型,然后保存模型后再加载模型进行预测,对预测结果计算精确度和召回率及F1分数
1. 导入必要的库 首先,导入我们需要的库:Numpy、Pytorch 和相关工具包。 import numpy as np import torch import torch.nn as nn import torch.optim as optim from sklearn.metrics import accuracy_score, recall_score, f1_score2. 自定义数据集 …...
FPGA|例化生成的PLL功能IP核
1、例化上一篇文章中调用的IP核,新建文件PLL_test.v 2、代码如图 timescale 1ns / 1ps module PLL_test(input clk,input rst_n,output clkout0,output clkout1,output clkout2,output clkout3,output clkout4);wire locked;PLL pll_inst(.inclk0(clk),.c0(clkout0)…...
K个不同子数组的数目--滑动窗口--字节--亚马逊
Stay hungry, stay foolish 题目描述 给定一个正整数数组 nums和一个整数 k,返回 nums 中 「好子数组」 的数目。 如果 nums 的某个子数组中不同整数的个数恰好为 k,则称 nums 的这个连续、不一定不同的子数组为 「好子数组 」。 例如,[1,2,…...
手机连接WIFI可以上网,笔记本电脑连接WIFI却不能上网? 解决方法?
原因:DNS受污染了 解决办法 step 1:清空域名解析记录(清空DNS) ipconfig /flushdns (Windows cmd命令行输入) step 2:重新从DHCP 获取IP ipconfig /release(释放当前IP地址) ipconfig /renew &…...
大模型综述一镜到底(全文八万字) ——《Large Language Models: A Survey》
论文链接:https://arxiv.org/abs/2402.06196 摘要:自2022年11月ChatGPT发布以来,大语言模型(LLMs)因其在广泛的自然语言任务上的强大性能而备受关注。正如缩放定律所预测的那样,大语言模型通过在大量文本数…...
C语言按位取反【~】详解,含原码反码补码的0基础讲解【原码反码补码严格意义上来说属于计算机组成原理的范畴,不过这也是学好编程初级阶段的必修课】
目录 概述【适合0基础看的简要描述】: 上述加粗下划线的内容提取版: 从上述概述中提取的核心知识点,需背诵: 整数【包含整数,负整数和0】的原码反码补码相互转换的过程图示: 过程详细刨析:…...
本地部署与使用SenseVoice语音大模型简析
前言 SenseVoice 是一种语音基础模型,具有多种语音理解功能,包括自动语音识别 (ASR)、口语识别 (LID)、语音情感识别 (SER) 和音频事件检测 (AED)。本博客将指导您安装和使用 SenseVoice 模型,使其尽可能方便用户使用。 Github 仓库链接: ht…...
QMK启用摇杆和鼠标按键功能
虽然选择了触摸屏,我仍选择为机械键盘嵌入摇杆模块,这本质上是对"操作连续性"的执着。 值得深思的是,本次开发过程中借助DeepSeek的代码生成与逻辑推理,其展现的能力已然颠覆传统编程范式,需求描述可自动…...
排序算法与查找算法
1.十大经典排序算法 我们希望数据以一种有序的形式组织起来,无序的数据我们要尽量将其变得有序 一般说来有10种比较经典的排序算法 简单记忆为Miss D----D小姐 时间复杂度 :红色<绿色<蓝色 空间复杂度:圆越大越占空间 稳定性&…...
基于Spring Security 6的OAuth2 系列之九 - 授权服务器--token的获取
之所以想写这一系列,是因为之前工作过程中使用Spring Security OAuth2搭建了网关和授权服务器,但当时基于spring-boot 2.3.x,其默认的Spring Security是5.3.x。之后新项目升级到了spring-boot 3.3.0,结果一看Spring Security也升级…...
【思维导图】redis
学习计划:将目前已经学的知识点串成一个思维导图。在往后的学习过程中,不断往思维导图里补充,形成自己整个知识体系。对于思维导图里的每个技术知识,自己用简洁的话概括出来, 训练自己的表达能力。...
【Git】使用笔记总结
目录 概述安装Git注册GitHub配置Git常用命令常见场景1. 修改文件2. 版本回退3. 分支管理 常见问题1. git add [中文文件夹] 无法显示中文问题2. git add [文件夹] 文件名中含有空格3. git add 触发 LF 回车换行警告4. git push 提示不存在 Origin 仓库5. Git与GitHub中默认分支…...
cf div3 998 E(并查集)
E : 给出两个简单无向图 (没有重边和自环)f g . 可以对f 进行 删边 和加边 的操作。问至少操作多少次 ,使得 f 和 g 的 点的联通情况相同(并查集的情况相同) 首先思考删边 : 对于 我 f 图存在边 e &#x…...
【C++】string类(上):string类的常用接口介绍
文章目录 前言一、C中设计string类的意义二、string类的常用接口说明1. string类对象的常见构造2. string类对象的容量操作2.1 size、capacity 和 empty的使用2.2 clear的使用2.3 reserve的使用2.4 resize的使用 3. string类对象的访问及遍历操作3.1 下标[ ] 和 at3.2 迭代器it…...
[SAP ABAP] ABAP SQL跟踪工具
事务码ST05 操作步骤 步骤1:使用事务码ST05之前,将要检测的程序生成的页面先呈现出来,这里我们想看下面程序的取数操作,所以停留在选择界面 步骤2: 新建一个GUI窗口,输入事务码ST05,点击 Acti…...
OpenGL学习笔记(六):Transformations 变换(变换矩阵、坐标系统、GLM库应用)
文章目录 向量变换使用GLM变换(缩放、旋转、位移)将变换矩阵传递给着色器坐标系统与MVP矩阵三维变换绘制3D立方体 & 深度测试(Z-buffer)练习1——更多立方体 现在我们已经知道了如何创建一个物体、着色、加入纹理。但它们都还…...
PHP 常用函数2025.02
PHP implode() 函数 语法 implode(separator,array) 参数描述separator可选。规定数组元素之间放置的内容。默认是 ""(空字符串)。array必需。要组合为字符串的数组。 技术细节 返回值:返回一个由数组元素组合成的字符串。PHP 版…...
17.3.4 颜色矩阵
版权声明:本文为博主原创文章,转载请在显著位置标明本文出处以及作者网名,未经作者允许不得用于商业目的。 17.3.4.1 矩阵基本概念 矩阵(Matrix)是一个按照长方阵列排列的复数或实数集合,类似于数组。 由…...
1. 【.NET 8 实战--孢子记账--从单体到微服务--转向微服务】--前言
在我们的专栏《单体开发》中,我们实现了一个简单的记账软件的服务端,并且成功上线。随着用户数量的不断增长,问题逐渐开始显现。访问量逐渐增加,服务端的压力也随之加大。随着访问量的攀升,服务端的响应时间变得越来越…...
02.04 数据类型
请写出以下几个数据的类型: 整数 a ----->int a的地址 ----->int* 存放a的数组b ----->int[] 存放a的地址的数组c ----->int*[] b的地址 ----->int* c的地址 ----->int** 指向printf函数的指针d ----->int (*)(const char*, ...) …...
WPS动画:使图形平移、围绕某个顶点旋转一定角度
1、平移 案例三角形如下图,需求:该三角形的A点平移至原点 (1)在预想动画结束的位置绘制出图形 (2)点击选中原始图像,插入/动画/绘制自定义路径/直线 (3)十字星绘制的直线…...
想表示消息返回值为Customer集合
道奈特(240***10) 14:34:55 EA中序列图。我想表示消息返回值为 Customer 集合。目前只有一个Customer实体类,我需要另外新建一个CustomerList 类吗? 潘加宇(35***47) 17:01:26 不需要。如果是分析,在类的操作中,定义一个参数&…...
93,【1】buuctf web [网鼎杯 2020 朱雀组]phpweb
进入靶场 页面一直在刷新 在 PHP 中,date() 函数是一个非常常用的处理日期和时间的函数,所以应该用到了 再看看警告的那句话 Warning: date(): It is not safe to rely on the systems timezone settings. You are *required* to use the date.timez…...
五、定时器实现呼吸灯
5.1 定时器与计数器简介 定时器是一种通过对内部时钟脉冲计数来测量时间间隔的模块。它的核心是一个递增或递减的寄存器(计数器值)。如果系统时钟为 1 MHz,定时器每 1 μs 计数一次。 计数器是一种对外部事件(如脉冲信号ÿ…...
顺序打印数字的进一步理解
之前博客写了篇博文,面试时要求使用多线程顺序打印ABC循环20次,这是我当时使用join函数实现代码: public class TestABCJoin {public static void main(String[] args) {// 创建任务Runnable taskA () -> {for (int i 0; i < 5; i) …...
使用React和Material-UI构建TODO应用的前端UI
使用React和Material-UI构建TODO应用的前端UI 引言环境准备代码解析1. 导入必要的模块2. 创建React组件3. 定义函数3.1 获取TODO列表3.2 创建TODO项3.3 更新TODO项3.4 删除TODO项3.5 处理编辑点击事件3.6 关闭编辑对话框3.7 保存编辑内容 4. 使用Effect钩子5. 渲染组件 功能实现…...
开屏广告-跳过神器
给大家介绍一款超实用的软件——SKIP,它堪称李跳跳的最佳平替!这款软件已经在Github开源免费,完全无需担心内置源问题,也无需导入任何规则。安装完成后,即可直接使用,非常便捷! 首次打开软件时…...
bat脚本实现自动化漏洞挖掘
bat脚本 BAT脚本是一种批处理文件,可以在Windows操作系统中自动执行一系列命令。它们可以简化许多日常任务,如文件操作、系统配置等。 bat脚本执行命令 echo off#下面写要执行的命令 httpx 自动存活探测 echo off httpx.exe -l url.txt -o 0.txt nuc…...
如何运行Composer安装PHP包 安装JWT库
1. 使用Composer Composer是PHP的依赖管理工具,它允许你轻松地安装和管理PHP包。对于JWT,你可以使用firebase/php-jwt这个库,这是由Firebase提供的官方库。 安装Composer(如果你还没有安装的话): 访问Co…...
(回溯递归dfs 电话号码的字母组合 remake)leetcode 17
只找边界条件和非边界条件,剩下的交给数学归纳法就行,考虑子问题的重复性 [class Solution {vector<string>str { "","","abc","def","ghi","jkl","mno","pqrs"…...
it基础使用--5---git远程仓库
文章目录 it基础使用--5---git远程仓库1. 按顺序看2. 什么是远程仓库3. Gitee操作3.1 新建远程仓库3.2 远程操作基础命令3.3 查看当前所有远程地址别名 git remote -v3.4 创建远程仓库别名 git remote add 别名 远程地址3.4 推送本地分支到远程仓库 git push 别名 分支3.5 拉取…...
Git 的起源与发展
序章:版本控制的前世今生 在软件开发的漫长旅程中,版本控制犹如一位忠诚的伙伴,始终陪伴着开发者们。它的存在,解决了软件开发过程中代码管理的诸多难题,让团队协作更加高效,代码的演进更加有序。 简单来…...
c++提取矩形区域图像的梯度并拟合直线
c提取旋转矩形区域的边缘最强梯度点,并拟合直线 #include <opencv2/opencv.hpp> #include <iostream> #include <vector>using namespace cv; using namespace std;int main() {// 加载图像Mat img imread("image.jpg", IMREAD_GRAYS…...
【PyQt】超级超级笨的pyqt计算器案例
计算器 1.QT Designer设计外观 1.pushButton2.textEdit3.groupBox4.布局设计 2.加载ui文件 导入模块: sys:用于处理命令行参数。 QApplication:PyQt5 应用程序类。 QWidget:窗口基类。 uic:用于加载 .ui 文件。…...
每日一题——小根堆实现堆排序算法
小根堆实现堆排序算法 堆排序的基本思想堆排序的步骤 实现步骤1. 构建小根堆2. 删除最小元素并调整堆 C语言实现输出示例代码解释1. percolateDown 函数2. buildMinHeap 函数3. heapSort 函数4. printArray函数 排序过程详解步骤1:构建小根堆步骤2:删除堆…...
k8s集群
文章目录 项目描述项目环境系统与软件版本概览项目步骤 环境准备IP地址规划关闭selinux和firewall配置静态ip地址修改主机名添加hosts解析 项目步骤一、使用kubeadm安装k8s单master的集群环境(1个master2个node节点)1、互相之间建立免密通道2.关闭交换分…...
数据分析系列--[11] RapidMiner,K-Means聚类分析(含数据集)
一、数据集 二、导入数据 三、K-Means聚类 数据说明:提供一组数据,含体重、胆固醇、性别。 分析目标:找到这组数据中需要治疗的群体供后续使用。 一、数据集 点击下载数据集 二、导入数据 三、K-Means聚类 Ending, congratulations, youre done....
技术架构师成长路线(2025版)
目录 通用知识 计算机原理(1 - 2 个月) 数据结构(2 - 3 个月) 网络编程(1 - 2 个月) 软件工程(1 个月) 基础知识 Java 编程语言基础(2 - 3 个月) JVM&…...
NetLify账号无法登录解决办法
本文收录在【建站】专栏内,专栏目录:【建站】专栏目录 用github账号登录时,说校验失败 Authentication Error Authenticating failed due to the following error: Your account requires additional verification. Please check your email…...
linux本地部署deepseek-R1模型
国产开源大模型追平甚至超越了CloseAI的o1模型,大国崛起时刻!!! DeepSeek R1 本地部署指南 在人工智能技术飞速发展的今天,本地部署AI模型成为越来越多开发者和企业关注的焦点。本文将详细介绍如何在本地部署DeepS…...
集合通讯概览
集合通信概览 (1)通信的算法 是根据通讯的链路组成的 (2)因为通信链路 跟硬件强相关,所以每个CCL的库都不一样 芯片与芯片、不同U之间是怎么通信的 多卡训练:多维并行(xxx并行在上一期已经讲述…...
如何解决云台重力补偿?
如何解决云台重力补偿? 最近在调试步兵云台的时候,由于枪管、图传、摄像头等重力的原因,pitch轴的参数尤其难以调整,又不想抬升和降低使用两套不同的参数,所以使用了重力补偿,效果也是比较理想的,于是整理为一篇文章记录一下 一、问题根源:枪管重力在“搞事情” 想象…...