4. redis排名系统之C++实战操作对比MySQL

news2024/11/24 3:33:42

一、MySQL实现方法

假设我们要设计一款排名系统,那必然要涉及到两大类数据:武器数据和非武器的通用数据,它他通常有一个共用的属性:那就是主键唯一的,例如玩家的数字编号,通常在MySQL中是自增的无符号整数字段。

非武器的通用数据可以理解为跟武器没有任何关联的数据,例如玩家ID,昵称,签名,注册时间,登录时间等等,在MySQL中就类似如下:

武器数据这里每一个武器对应的种类就相当于MYSQL中的一个字段,大致类似如下:

这个表单数据通常会只会增加并不会出现减少的现象,如果用MYSQL来做排名系统的话,当玩家数量越来越多成几何增长的时候,它会暴露出两个问题:

1、效率过低:大量的select与update语句就可能会显得非常臃肿;

2、不易扩展:如果需要实时增加新的武器数据类型(字段),可能会不方面

这时候如果用redis来做数据存储就会显示格外合适,仿佛天生就是用来干这个事情的!

二、用Redis实现方法

1、存储前字符串编码转换

    通常不建议在REDIS中直接存储明文字符串,建议采用网页编码来存储,转换函数源码如下:

// 十六进制字符表
const UCHAR			g_szHexTable[] = { '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'A', 'B', 'C', 'D', 'E', 'F' };

//
// 获取网页编码
//
int getUrlCode(const UCHAR *pszBuff, const int nSize, char *pszOutput, const int nMaxSize)
{
	int		i = 0;
	char	*pszTemp = NULL;

	if (pszBuff == NULL || nSize == 0)
		return 0;

	if (pszOutput == NULL || nMaxSize == 0)
		return 0;

	memset(pszOutput, 0x00, nMaxSize);
	pszTemp = pszOutput;

	for (int i = 0; i < nSize; i++)
	{
		pszTemp[0] = '%';
		pszTemp[1] = '%';
		pszTemp[2] = g_szHexTable[(pszBuff[i] >> 4) & 0x0F];
		pszTemp[3] = g_szHexTable[pszBuff[i] & 0x0F];
		pszTemp += 4;
	}

	return nSize * 4;
}

// 测试函数
void test_url_code()
{
	UCHAR	szInput[] = "我要打10个!";
	char	szOutput[128] = { 0x00 };

	getUrlCode(szInput, strlen((char *)szInput), szOutput, 128);
	printf("%s\n", szOutput);
}

2、用户表操作

    我们可以采用Redis Hset 命令用于为哈希表中的字段赋值;如果哈希表不存在,一个新的哈希表被创建并进行 HSET 操作;如果字段已经存在于哈希表中,旧值将被覆;

HSET KEY_NAME FIELD VALUE 

KEY_NAME: 键值
FIELD:    字段
VALUE:    值(字符传、数字、浮点)

我们在KEY_NAME这里键值的时候,用一个组合方法来区分:

// KEY_NAME = type : id
#define STATS_ALL		"a"		// 总榜 a:1
#define STATS_YEAR		"y"		// 年榜 y2022:1
#define STATS_MONTH		"m"		// 月榜 m202205:1
#define STATS_DAY		"d"		// 日榜 d20220501:1
#define STATS_SESSION	"s"		// 季榜 s1_2022:1
#define STATS_USER		"user"	// 用户信息 user:1

    那么SQL中修改的语句修改用户名的时候,像这样的:

UPDATE dbuser SET name = 'aa' WHERE index = 1;
UPDATE dbuser SET signature = '我要打10个!' WHERE index = 1;
UPDATE dbuser SET regdate = '2023/10/1' WHERE index = 1;

    而在Redis中应该像这样:

// 注意这里的KEY是组合出来的

// 设置玩家ID=1的游戏昵称为"aa"
HSET user:1 name %%61%%61

// 设置玩家ID=1的游戏昵称为"我要打10个!"
HSET user:1 signature %%CE%%D2%%D2%%AA%%B4%%F2%%31%%30%%B8%%F6%%A3%%A1

// 设置玩家ID=1的注册时间为"2023/10/1"
HSET user:1 regdate %%32%%30%%32%%33%%2F%%31%%30%%2F%%31

// 设置玩家ID=1的经验值时间为100
HSET user:1 exp 100


// 上面redis命令也可以优化成下面的一句执行完
HMSET user:1 name %%61%%61 signature %%CE%%D2%%D2%%AA%%B4%%F2%%31%%30%%B8%%F6%%A3%%A1 regdate %%32%%30%%32%%33%%2F%%31%%30%%2F%%31 exp 100

C++代码片段如下:

	wsprintf(szCommand, /*HSET %s:%u %s %s*/XorStr<0xAB, 17, 0x72ACBFF2>("\xE3\xFF\xE8\xFA\x8F\x95\xC2\x88\x96\xC1\x95\x93\xC4\x98\x9C\xC9" + 0x72ACBFF2).s, STATS_USER, pInfo->m_nDbUid, g_szUserInfo[nPos], szValue);

	reply = (redisReply *)redisCommand(pRedis, szCommand);
	if (NULL == reply) goto STEP_END;
	if (REDIS_REPLY_ERROR == reply->type)goto STEP_END;
	bRet = TRUE;

STEP_END:
	if (NULL != reply)
	{
		freeReplyObject(reply);
		reply = NULL;
	}

3、武器数据操作

    在这方面数据操作就比较容易实现了,而且能随时扩充字段个数,不像SQL那样固定的个数;另外武器的字段的数值操作都是自加来累计,而不会产生添加或删除操作,比如当网关服务器提交一条玩家ID=1,武器=2,累计杀敌总数自加3的命令时,通常对应的SQL语句如下:

// 修改总榜数据
UPDATE dbweapon_all SET kill = kill + 3 where index = 1 AND wid = 2;

// 修改年榜数据
UPDATE dbweapon_2023 SET kill = kill + 3 where index = 1 AND wid = 2;

// 修改赛季榜数据
UPDATE dbweapon_s1_2023 SET kill = kill + 3 where index = 1 AND wid = 2;

    而在Redis中应该像这样:

// HINCRBY命令原型
// 参考地址:https://www.runoob.com/redis/hashes-hincrby.html
HINCRBY KEY_NAME FIELD_NAME INCR_BY_NUMBER

// redis执行3条命令 
HINCRBY a:1 1:kill 3
HINCRBY y2023:1 1:kill 3
HINCRBY s1_2023:1 1:kill 3

键值KEY_NAME注释:
a:1       代表总榜
y2023:1   外表年榜
s1_2023:1 代表2023第一赛季榜

字段FIELD_NAME注释:
1:kill    武器编号为1,类型为kill

字段INCR_BY_NUMBER代表自加或自减数值

4、MySQL修改积分查询排名

    通常来说需要写一个复杂的MySQL语句来计算玩家的积分,大致如下:

// 修改积分
UPDATE SET db_user exp = exp + 3.0 WHERE index = 1;

// 查询积分
SELECT exp FROM db_user WHERE index = 1;

// 查询排名
SELECT COUNT(*) + 1 AS rank 
FROM db_user 
WHERE exp >= (SELECT exp FROM db_user WHERE index = 1);

而在redis中本身就有了现成的,通常在网关中处理武器数据时,会同时修改该榜单的积分值

5、Redis Zincrby 修改积分

    Redis Zincrby 命令对有序集合中指定成员的分数加上增量 increment,可以通过传递一个负数值 increment ,让分数减去相应的值,比如 ZINCRBY key -5 member ,就是让 member 的 score 值减去 5 ;当 key 不存在,或分数不是 key 的成员时, ZINCRBY key increment member 等同于 ZADD key increment member;当 key 不是有序集类型时,返回一个错误;分数值可以是整数值或双精度浮点数。

命令原型如下:

ZINCRBY key increment member

key        同上面的武器榜单
increment  自增或自减的积分
member     玩家id


// 假设1号武器杀敌一次累计3分,那对应命令如下:
ZINCRBY a:1 3.0 1
ZINCRBY y2023:1 3.0 1
ZINCRBY s1_2023:1 3.0 1

C++代码片段如下:

	// 总榜记录
	wsprintf(szCommand, /*ZINCRBY %s %s %u*/XorStr<0x09, 17, 0x5A9256F5>("\x53\x43\x45\x4F\x5F\x4C\x56\x30\x34\x61\x33\x31\x66\x36\x32\x6D" + 0x5A9256F5).s, STATS_ALL, szScore, nDbUid);

	bRet = redisGetReply(m_pRedis, (void **)&reply);
	if (bRet != REDIS_OK)
		goto STEP_END;

	if (reply)
	{
		freeReplyObject(reply);
		reply = NULL;
	}

6、Redis Zscore 查询积分

    Redis 有序集合(sorted set),Redis Zscore 命令返回有序集中,成员的分数值。 如果成员元素不是有序集 key 的成员,或 key 不存在,返回 nil 。

命令原型如下:

ZSCORE key member

key        同上面的武器榜单
member     玩家id


// 查询不同榜单的积分命令:
ZSCORE a:1 1
ZSCORE y2023:1 1
ZSCORE s1_2023:1 1

C++操作代码片段如下:

	// 获取玩家积分(插件中只获取总榜记录)
	wsprintf(szCommand, /*ZSCORE %s %u*/XorStr<0x40, 13, 0xF87B9E21>("\x1A\x12\x01\x0C\x16\x00\x66\x62\x3B\x69\x6F\x3E" + 0xF87B9E21).s, STATS_ALL, nDbUid);
	reply = (redisReply *)redisCommand(pRedis, szCommand);
	if (NULL == reply) goto STEP_END;
	if (REDIS_REPLY_ERROR == reply->type)goto STEP_END;
	if (REDIS_REPLY_STRING == reply->type)
	{
		fScore = strtod(reply->str, NULL);
	}
	if (NULL != reply)
	{
		freeReplyObject(reply);
		reply = NULL;
	}

7、Redis Zrevrank 查询排名

    Redis 有序集合(sorted set),Redis Zrevrank 命令返回有序集中成员的排名。其中有序集成员按分数值递减(从大到小)排序;排名以 0 为底,也就是说, 分数值最大的成员排名为 0 ;使用 ZRANK 命令可以获得成员按分数值递增(从小到大)排列的排名。

命令原型如下:

Zrevrank key member

key        同上面的武器榜单
member     玩家id


// 查询不同榜单的排名命令:
ZREVRANK a:1 1
ZREVRANK y2023:1 1
ZREVRANK s1_2023:1 1

C++操作代码片段如下:

	// 获取在玩家排名(插件中只获取总榜记录)
	wsprintf(szCommand, /*ZREVRANK %s %u*/XorStr<0x01, 15, 0x9CCD219A>("\x5B\x50\x46\x52\x57\x47\x49\x43\x29\x2F\x78\x2C\x28\x7B" + 0x9CCD219A).s, STATS_ALL, nDbUid);
	reply = (redisReply *)redisCommand(pRedis, szCommand);
	if (NULL == reply) goto STEP_END;
	if (REDIS_REPLY_ERROR == reply->type)goto STEP_END;
	if (REDIS_REPLY_NIL == reply->type)
	{
		nRank = pServer->m_nMaxPlayers;
		bRet = TRUE;
	}
	if (REDIS_REPLY_INTEGER == reply->type)
	{
		nRank = (reply->integer & 0xFFFFFFFF) + 1;
		bRet = TRUE;
	}

	if (NULL != reply)
	{
		freeReplyObject(reply);
		reply = NULL;
	}

三、总结避坑

1、尽量不要使用固定字符串做KEY

在编写排名的时候,一般武器数据的KEY中不会用到像"kill"这种字符类型,通常用一个数字代替方面扩展时,只需要修改enum宏即可,武器 + 数据类型 来拼接 %u:%u 的KEY_NAME,类似下面这种:

// push数据类别				// 命令     字符	积分
enum EnumPushType{					
	EPT_UNKNOW = '@',		// 未知		64 @	+0
	EPT_KILL,				// 杀敌		65 A	+2
	EPT_SHOT,				// 射击		66 B	+0
	EPT_HEADSHOT,			// 爆头		67 C	+1
	EPT_HIT,				// 击中		68 D	+0

	EPT_DAMAGE,				// 伤害		69 E	+0
	EPT_DEATH,				// 死亡		70 F	-2
	EPT_FIRSTKILL,			// 首杀		71 G	+1
	EPT_FIRSTDEATH,			// 首死		72 H	+0
	EPT_BOMB_DEFUSION,		// 拆除C4	73 I	+2

	EPT_BOMB_PLANTING,		// 安装C4	74 J	+2
	EPT_TIME_ONLINE,		// 在线		75 K	+0  每秒+0.002分(每小时7.2分)

	EPT_KILL_WORLD,			// 摔死		76 L	+0
	EPT_KILL_SELF,			// 自杀次数	77 M	+0

	EPT_MAX_PLAYER,			// 最大玩家 78 N	+0
	EPT_RANK,				// 当前排名 79 O	+0
	EPT_SCORE,				// 当前积分 80 P	+0

	// 身体伤害
	EPT_DMAGE_NONE,			// 击中空枪 81 Q	+0
	EPT_DMAGE_HEAD,			// 击中头部 82 R	+0
	EPT_DMAGE_CHEST,		// 击中胸部 83 S	+0
	EPT_DMAGE_STOMACH,		// 击中胃部 84 T	+0
	EPT_DMAGE_LEFTARM,		// 击中左臂 85 U	+0
	EPT_DMAGE_RIGHTARM,		// 击中右臂 86 V	+0
	EPT_DMAGE_LEFTEG,		// 击中左脚 87 W	+0
	EPT_DMAGE_RIGHTEG,		// 击中右脚 88 X	+0
	EPT_DMAGE_SHIELD,		// 击中盾牌 89 Y	+0

	// 武器+BKILL
	EPT_BKILL,				// 被击杀	90 Z	+0
	EPT_BHEAD,				// 被爆头	91 [	+0
	
	// 击中次数
	EPT_HIT_NONE,			// 击中空枪 92 \	+0
	EPT_HIT_HEAD,			// 击中头部 93 ]	+0
	EPT_HIT_CHEST,			// 击中胸部 94 ^	+0
	EPT_HIT_STOMACH,		// 击中胃部 95 _	+0
	EPT_HIT_LEFTARM,		// 击中左臂 96 `	+0
	EPT_HIT_RIGHTARM,		// 击中右臂 97 a	+0
	EPT_HIT_LEFTEG,			// 击中左脚 98 b	+0
	EPT_HIT_RIGHTEG,		// 击中右脚 99 c	+0
	EPT_HIT_SHIELD,			// 击中盾牌 100 d	+0

	// 混战参数 add by MT 2023-09-30
	EPT_ROUND,				// 总回合
	EPT_RWIN_T,				// 回合:T杀完胜利
	EPT_RWIN_BOOM,			// 回合:T爆炸胜利
	EPT_RWIN_CT,			// 回合:CT杀完胜利
	EPT_RWIN_DEFUSE,		// 回合:CT爆炸胜利
	EPT_RWIN_SAVED,			// 回合:CT时间结束胜利
	EPT_RWIN_RESCUE,		// 回合:CT解救人质胜利
	EPT_RWIN_NOT_RESCUE,	// 回合:CT未解救人质胜利
	EPT_RWIN_TYPE1,			// 回合:保留胜利1
	EPT_RWIN_TYPE2,			// 回合:保留胜利2

	EPT_RLOSE,				// 失败回合
	EPT_REVEN,				// 平局回合

	// 比赛参数
	EPT_SESSION,			// 总场次
	EPT_SWIN,				// 胜利场次
	EPT_SLOSE,				// 失败场次
	EPT_SEVEN,				// 平局场次

	EPT_MVP,				// 最佳次数
	EPT_RWS,				// 每局贡献评分(伤害占比)

	// 每回合杀敌统计
	EPT_KILL_0,				// 0K 酱油局
	EPT_KILL_1,				// 1K
	EPT_KILL_2,				// 2K
	EPT_KILL_3,				// 3K
	EPT_KILL_4,				// 3K
	EPT_KILL_5,				// 5K
	EPT_KILL_6,				// 6K
	EPT_KILL_7,				// 7K
	EPT_KILL_8,				// 8K
	EPT_KILL_9,				// 9K
	EPT_KILL_10,			// 10K
	EPT_KILL_11,			// 11K
	EPT_KILL_12,			// 12K
	EPT_KILL_13,			// 13K
	EPT_KILL_14,			// 14K
	EPT_KILL_15,			// 15K
	EPT_KILL_16,			// 16K

	// 残局统计
	EPT_1V1,				// 1v1
	EPT_1V2,				// 1v2
	EPT_1V3,				// 1v3
	EPT_1V4,				// 1v4
	EPT_1V5,				// 1v5
	EPT_1V6,				// 1v6
	EPT_1V7,				// 1v7
	EPT_1V8,				// 1v8
	EPT_1V9,				// 1v9
	EPT_1V10,				// 1v10
	EPT_1V11,				// 1v11
	EPT_1V12,				// 1v12
	EPT_1V13,				// 1v13
	EPT_1V14,				// 1v14
	EPT_1V15,				// 1v15
	EPT_1V16,				// 1v16

	// 残局信息
	EPT_1ROUND,				// 残局场次
	EPT_1RWIN,				// 残局胜利

	EPT_ASSIST,				// 助攻次数
	EPT_ADR,				// 场均实际伤害占比累计

	// 穿墙信息
	EPT_WALL_HIT,			// 穿墙累计命中次数
	EPT_WALL_DAMAGE,		// 穿墙累计射击伤害
	EPT_WALL_HEAD,			// 穿墙累计爆头次数
	EPT_WALL_KILL,			// 穿墙累计击杀次数

	EPT_BWALL_HIT,			// 被穿墙累计命中次数
	EPT_BWALL_DAMAGE,		// 被穿墙累计射击伤害
	EPT_BWALL_HEAD,			// 被穿墙累计爆头次数
	EPT_BWALL_KILL,			// 被穿墙累计击杀次数
};

 这一个宏再对应一个double数组来计算得分,如此只需要一个这样的函数作为网关总接口即可:

// 提交排名数据
UINT redis_PushCommand(REDIS_SERVER *pServer, const UINT nDataType, const UINT nWeapon, UINT nDbUid, UINT nValue);


2、尽量用事务方式读写

最后注意一下用事务处理的方法操作,可以加快读写效率,普通的10倍以上,示例代码如下:

	// 新版采用事务方式读取,加快速度
	for (i = 0; i < MAX_WEAPONS; i++)
	{
		nWeapon = i + EPT_UNKNOW;
		for (j = 0; j < MAX_OPT_COUNT; j++)
		{
			wsprintf(szCommand, /*HGET %s:%u %u:%u*/XorStr<0x18, 17, 0xF6DE906E>("\x50\x5E\x5F\x4F\x3C\x38\x6D\x25\x05\x54\x02\x06\x51\x1F\x03\x52" + 0xF6DE906E).s, STATS_ALL, nDbUid, , EPT_UNKNOW + j, nWeapon);
			redisAppendCommand(pRedis, szCommand); // 事务读取
		}
	}

    // 遍历所有武器数据
	for (i = 0; i < MAX_WEAPONS; i++)
	{
		// 遍历所有参数
		for (j = 0; j < MAX_OPT_COUNT; j++)
		{
			nRet = redisGetReply(pRedis, (void **)&reply);
			if (nRet != REDIS_OK)
				continue;

			if (reply->type == REDIS_REPLY_STRING)
			{
				sData.m_nValue[i][j] = atoi(reply->str);
			}
			if (reply->type == REDIS_REPLY_INTEGER)
			{
				sData.m_nValue[i][j] = reply->integer & 0xFFFFFFFF;
			}
		}
	}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1091159.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

【牛客面试必刷TOP101】Day9.BM37 二叉搜索树的最近公共祖先和BM42 用两个栈实现队列

作者简介&#xff1a;大家好&#xff0c;我是未央&#xff1b; 博客首页&#xff1a;未央.303 系列专栏&#xff1a;牛客面试必刷TOP101 每日一句&#xff1a;人的一生&#xff0c;可以有所作为的时机只有一次&#xff0c;那就是现在&#xff01;&#xff01;&#xff01;&…

pycharm安装汉化包失败解决方法

在pycharm -setting-plugins-搜索“Chinese”进入此界面&#xff1a; 点击install&#xff0c;在安装时出现&#xff1a;Plugin "Chinese (Simplified) Language Pack / 中文语言包" was not installed: Invalid filename returned by a server 解决方法&#xff1a…

boot分页

List<ElectricDispatchTodoPO> todoList electricDispatchTodoService.queryTodlList(vo, sysStaffVO);// 计算总记录数int total todoList.size();// 如果总记录数大于0PageInfo<ElectricDispatchTodoPO> pageInfo new PageInfo<>();if (total > 0) {…

手把手教你分析IIS日志——IP访问次数,URI访问统计等

配置IIS网站的日志 下载日志分析工具 https://gitee.com/tangdd369098655/open-network-disk 解压打开 选择文件 指定分析规则&#xff08;还可以自己写规则哦~~&#xff09; 运行规则进行分析 今天就写到这里啦~ 小伙伴们&#xff0c;(&#xffe3;ω&#xffe3;(&#x…

Win10 环境下 VS2022 暴力编译PP-OCRv4

1 环境准备 下载PaddleOCR PaddleOCR C 部署代码位于 PaddleOCR\deploy\cpp_infer目录下 复制cpp_infer目录下include和src到项目目录下paddle_inference paddle_inference opencv 这里使用已经安装好的opencv4.5.5下载dirent-master.zip 下载dirent-master.zip, 解压并复制d…

MyLife - Docker安装Consul

Docker安装Consul 个人觉得像consul之类的基础设施在线上环境直接物理机安装使用可能会好些。但是在开发测试环境用docker容器还是比较方便的。这里学习下docker安装consul使用。 1. Consul 镜像库地址 Consul 镜像库地址&#xff1a;https://hub.docker.com/r/hashicorp/consu…

CleanMyMacX4.12.3最新免费版mac电脑管家

当我们收到一台崭新的mac电脑&#xff0c;第一步肯定是找到一款帮助我们管理电脑运行的“电脑管家”&#xff0c;监控内存运行、智能清理系统垃圾、清理Mac大文件旧文件、消除恶意软件、快速卸载更新软件、隐私保护、监控系统运行状况等。基本在上mac电脑防护一款CleanMyMac就够…

C/C++陷阱——变量名和函数名的冲突问题

C语言/C陷阱——变量名和函数名的冲突问题 先来看这两串代码&#xff1a; 代码一&#xff1a; #include <stdio.h> #include <stdlib.h>int rand 1;int main() {printf("%d\n", rand);return 0; }代码二&#xff1a; #include <stdio.h> #inc…

芯片设计:一颗芯片到底是如何诞生的(上)

目录 芯片设计整体流程 小故事&#xff1a;苹果的芯片设计路 需求分析 架构设计 逻辑设计 前端设计与验证 逻辑综合 DFT&#xff08;可测试性设计&#xff09; 物理实现 小结 芯片设计整体流程 一颗芯片&#xff0c;是如何诞生的呢&#xff1f;其实一颗芯片项目就是…

vue引入jQuery

配置 下载 npm install jquery --save在build的webpack.base.conf中 var webpackrequire("webpack")在module.exports中: plugins: [ //   new webpack.optimize.CommonsChunkPlugin(common.js),new webpack.ProvidePlugin({jQuery: "jquery",$: &quo…

三十五、【进阶】MySQL性能查看

1、基础语法 show global status like Com_______; 2、实际操作 &#xff08;1&#xff09;查看当前数据库sql语句的执行频率 show global status like Com_______; &#xff08;2&#xff09; 执行依次select语句 &#xff08;3&#xff09; 再次查看当前数据库sql语句的执…

GBJ2510-ASEMI电源控制柜专用GBJ2510

编辑&#xff1a;ll GBJ2510-ASEMI电源控制柜专用GBJ2510 型号&#xff1a;GBJ2510 品牌&#xff1a;ASEMI 封装&#xff1a;GBJ-4 恢复时间&#xff1a;&#xff1e;50ns 正向电流&#xff1a;25A 反向耐压&#xff1a;1000V 芯片个数&#xff1a;4 引脚数量&#xf…

python每日一练(7)

&#x1f308;write in front&#x1f308; &#x1f9f8;大家好&#xff0c;我是Aileen&#x1f9f8;.希望你看完之后&#xff0c;能对你有所帮助&#xff0c;不足请指正&#xff01;共同学习交流. &#x1f194;本文由Aileen_0v0&#x1f9f8; 原创 CSDN首发&#x1f412; 如…

【LeetCode热题100】--739.每日温度

739.每日温度 方法&#xff1a;单调栈 可以维护一个存储下标的单调栈&#xff0c;从栈底到栈顶的下标对应的温度列表中的温度依次递减。如果一个下标在单调栈里&#xff0c;则表示尚未找到下一次温度更高的下标。 正向遍历温度列表。对于温度列表中的每个元素 temperatures[i…

YOLOv5算法改进(11)— 主干网络介绍(MobileNetV3、ShuffleNetV2和GhostNet)

前言:Hello大家好,我是小哥谈。主干网络通常指的是深度学习中的主干模型,通常由多个卷积层和池化层组成,用于提取输入数据的特征。在训练过程中,主干网络的参数会被不断优化以提高模型的准确性。YOLOv5算法中的主干网络可以有多种替换方案,为了后面讲解的方便,本篇文章就…

C结构体内定义结构体,不能直接赋值。

现像&#xff1a; 如下代码&#xff1a; 头文件&#xff1a; typedef struct aBlinkGpioPinOutAbst_{void (*initAsOutput)(void);void (*high)(void);void (*low)(void); }aBlinkGpioPinOutAbst;typedef struct aBlinkGpioAbst_{ #if GPIO_CONFIG_PA0 GPIO_CONFIG_AS_OUTPU…

Jetson Orin NX 开发指南(9): MAVROS 的安装、配置与运行

一、前言 由于 Jetson 系列开发板常作为自主无人机的机载电脑&#xff0c;而无人机硬件平台如 PX4 和 ArduPilot 等通过 MAVLink 进行发布无人机状态和位姿等信息&#xff0c;要实现机载电脑与 MAVLink 的通信&#xff0c;必须借助 Mavros 功能包&#xff0c;因此&#xff0c;…

分页机制详解

分页机制详解 《操作系统真象还原》第五章笔记 内存不足&#xff0c;需要分页机制 我们所写的代码仅仅是完成了某件事的一部分而已&#xff0c;也许是大部分&#xff0c;还有一部分是 CPU 硬件上负责的&#xff0c;这部分咱们不用管&#xff0c;由 CPU 自动完成。比如&#x…

内网渗透——隧道代理

文章目录 代理代理使用场景VPS建立隧道frpMSF木马生成监听开启frp服务端和客户端执行exe木马文件 代理 实验环境&#xff1a; 攻击机kali&#xff1a;192.168.188.133&#xff08;NAT模式&#xff09; 模拟的公网服务器&#xff08;本机&#xff09;&#xff1a;10.9.75.239 …