佳能镜头EOS系统EF协议逆向工程(三)解码算法
目录
数据结构
解码算法
解码效果
这篇文章基于上两篇文章继续,
佳能镜头EOS系统EF协议逆向工程(一)转接环电路设计_佳能ef自动对焦协议_岬淢箫声的博客-CSDN博客本文属于专栏——工业相机。此专栏首先提供我人工翻译的法语文档部分,然后通过STM32F103C8T6控制佳能镜头,最后协同上位机或者NVIDIA Xavier实现自动对焦。还有一个用处不大的River文档,它知道如何让相机和镜头通信,也许对当前的摄影实践几乎没有帮助。尽管如此,一些应用程序可能需要独立订购物镜的主要功能。撇开工业世界及其特殊机器不谈,在另一个品牌的图像采集系统上安装佳能光学元件是不可能的,而且是有罪的,无论是出于经济原因还是纯粹的技术原因,获得的组合提供了其他不可用的功能。https://blog.csdn.net/caoshiying/article/details/127609884?spm=1001.2014.3001.5502佳能镜头EOS系统EF协议逆向工程(二)逻辑分析仪测试_岬淢箫声的博客-CSDN博客本章描述了用于解密EF协议函数的思想和分析,如果其读数是可选的,则所获得结果的摘要将在专用章节中进行汇编,这仍然是正确理解EF协议函数的必要来源。随着函数的测试和逐步解码,它们的描述和列表中使用的注释将在过程中变得越来越精确,因为以前的分析或推理错误不会被强制纠正。所使用的逻辑分析仪是一个小型号的低成本8输入TTL USBEE AX Pro,所使用的软件是制造商的标准套件,可免费下载。软件不允许编辑或删除部分结果,某些读数或时钟意外激活,因为通电会导致SPI字解码不同步。
https://blog.csdn.net/caoshiying/article/details/129057004?spm=1001.2014.3001.5502
数据结构
逻辑分析仪没有特别要求,某宝上的大部分逻辑分析仪可以用。数据格式要求很简单,举便如下:
; CSV, generated by libsigrok4DSL 0.2.0 on Fri Jul 29 10:17:48 2022
; Channels (3/16)
; Sample rate: 10 MHz
; Sample count: 50.896 M Samples
Time(s), CLK, DLC, DCL
0,1,1,1
0.0498275,1,1,0
0.0498285,1,1,1
0.0498697,1,1,0
0.049876,1,1,1
0.0499793,1,1,0
0.0499986,0,1,0
0.050005,1,1,0
分号开头表示注释,第一列是时间,这个时间是相对开始捕获的时间,用单词elapse表示列标题更合适。这款逻辑分析仪软件导出数据的表头就是这么写的,无所谓了。第二列是CLK信号,CLK是时钟的简写,搞硬件的同学是不是很熟悉呢?第三列是DLC信号。DLC是Data Lens to Camera的首字母缩写。第四列是DCL,DCL是Data Camera to Lens首字母缩写。所有信号用1表示高电平,0表示低电平。佳能相机的电平为3.3V。
我使用Qt写的解码工具,CMake工程代码如下:
cmake_minimum_required(VERSION 3.20)
project(TAMRON VERSION 1.0)find_package(Qt5 COMPONENTS Widgets REQUIRED PATHS $ENV{Qt515_DIR})
link_libraries(Qt5::Widgets)
add_link_options(/SUBSYSTEM:CONSOLE)
file(GLOB TAMRON_SRCS *.cpp *.h *.ui *.qrc *.rc)
add_executable(${PROJECT_NAME} ${TAMRON_SRCS})
target_compile_definitions(${PROJECT_NAME} PRIVATE $<IF:$<CONFIG:DEBUG>,CWDEBUG,CWNDEBUG>)
Qt515_DIR环境变量是必须的。
解码算法
算法是关键是解决ACK干扰。核心思路是寻找U型特征的连续信号。源代码只有一个main.cpp,代码如下:
#include <QApplication>
#include <QMainWindow>
#include <QFileDialog>
#include <QFile>
#include <QMessageBox>
#include <QTextStream>
#include <QDebug>
#include <QFileInfo>
#include <QMetaEnum>typedef struct _spi_signal_t
{uint32_t line_no;//行号double elapse;//消耗的时间,6位小数,单位为秒,存储化为usbool clk;//时钟是否高位bool dcl;//主机信号是否高位bool dlc;//从机信号是否高位
} spi_signal_t;typedef struct _spi_data_t
{uint32_t order;//序号uint32_t start_line;//信号起始行号uint32_t end_line;//信号结束行号uint8_t dcl;//主机命令uint8_t dlc;//从机返回int frame_no;//字节所属帧号bool bad;//是否发生丢失bit的情况double elapse;//消耗的时间double frequency;//实际通讯频率,存储为KHz
} spi_data_t;//信号数据中的U型结构,全部为引用指针,不管理内存
typedef struct _u_shape_t
{spi_signal_t *high_left;//U槽左端spi_signal_t *low_left;//U槽底左边spi_signal_t *low_right;//U槽底右边spi_signal_t *high_right;//U槽右端spi_signal_t *forward;//遍历前进到达的位置bool ok;//此U型结构是否能用int index_cursor;//信号列表遍历时当前的位置
} u_shape_t;typedef QSharedPointer<spi_signal_t> pspi_signal_t;
typedef QSharedPointer<spi_data_t> pspi_data_t;
typedef QSharedPointer<u_shape_t> pu_shape_t;
#define ZERR_CAPTION u8"系统错误"
#define ZOK_CAPTION u8"系统提示"//CSV文件文件转换为信号数据
QList<pspi_signal_t> resolve_csv(const QString &zcsv_path);
//信号数据转换为真实的主机与从机之间交换的信息
QList<pspi_data_t> resolve_signal(const QList<pspi_signal_t> &ps);
//保存信息
void save_spi_data(const QString &zcsv_path, const QList<pspi_data_t> &ds);
//寻找信号中的U形,返回下一个U形右端索引+1,返回值index_cursor与istart_cursor相等表示结束,ok为false表示出错
pu_shape_t find_u_shape(const QList<pspi_signal_t> &ps, int istart_cursor, int ilen);
//保存程序日志
void save_log(QtMsgType type, const QMessageLogContext &cxt, const QString &zlog);
//解析帧
void resolve_frame(QList<pspi_data_t> &ds);//入口函数
int main(int argc, char **argv)
{qInstallMessageHandler(save_log);QApplication app(argc, argv);auto zcsv_path = QFileDialog::getOpenFileName(nullptr,u8"选择一个CSV文件","D:/tamron");if (zcsv_path.isEmpty())return 1;auto ps = resolve_csv(zcsv_path);if (ps.isEmpty())return 2;auto ds = resolve_signal(ps);if (ds.isEmpty())return 3;resolve_frame(ds);save_spi_data(zcsv_path, ds);return 0;
}//CSV文件文件转换为信号数据
QList<pspi_signal_t> resolve_csv(const QString &zcsv_path)
{QFile f(zcsv_path);QList<pspi_signal_t> ps;if (!f.open(QFile::ReadOnly | QFile::Text)){QMessageBox::warning(nullptr, ZERR_CAPTION, f.errorString());return ps;}QTextStream ts(&f);ts.skipWhiteSpace();//DSView导出数据有5行注释和1行标头,应当跳过。for (short i = 0; i < 4; i++){auto zline = ts.readLine();if (ts.atEnd() || !zline.startsWith(";")){QMessageBox::warning(nullptr, ZERR_CAPTION, u8"无效的CSV文件。");break;}}ts.readLine();if (ts.atEnd())return ps;uint32_t iline = 6;while (!ts.atEnd()){QString zline = ts.readLine();if (zline.isEmpty())continue;QStringList cols = zline.split(u8",");if (cols.length() < 4){QMessageBox::critical(nullptr, ZERR_CAPTION, QString(u8"第%1行无效数据").arg(iline));return ps;}spi_signal_t r;r.line_no = iline++;if (iline >= UINT32_MAX){QMessageBox::warning(nullptr,ZERR_CAPTION,u8"input data amount exceed system capacity.");break;}r.elapse = cols[0].toDouble() * 1000000;r.clk = cols[1].toInt() != 0;r.dlc = cols[2].toInt() != 0;r.dcl = cols[3].toInt() != 0;pspi_signal_t p = QSharedPointer<spi_signal_t>::create(r);ps.append(p);}qInfo() << u8"合计" << ps.length() << u8"个信号\n";return ps;
}//寻找信号中的U形,返回下一个U形右端索引+1,返回值index_cursor与istart_cursor相等表示结束,ok为false表示出错
pu_shape_t find_u_shape(const QList<pspi_signal_t> &ps, int istart_cursor, int ilen)
{pu_shape_t pu(new u_shape_t{0,});u_shape_t *u = pu.data();u->index_cursor = istart_cursor;//1.寻找U槽//1.1.寻找下降沿,定位U槽左端while (u->index_cursor < ilen && ps[u->index_cursor]->clk)u->index_cursor++;u->forward = ps[u->index_cursor].data();if (u->index_cursor - 1 < 0){u->ok = false;u->index_cursor++;return pu;}if (u->index_cursor + 1 >= ilen){qWarning() << "data end on finding u->high_left and u->low_left";u->ok = false;return pu;}u->high_left = ps[u->index_cursor - 1].data();u->low_left = ps[u->index_cursor].data();u->forward = u->low_left;
#ifdef DEBUGqInfo() << "u begin: " << u->high_left->line_no;
#endifu->index_cursor++;if (u->index_cursor >= ilen){qWarning() << "data end on finding u->low_right";u->ok = false;return pu;}//1.2.寻找上升沿,定位U槽底有多长while (u->index_cursor < ilen && !ps[u->index_cursor]->clk)u->index_cursor++;u->low_right = ps[u->index_cursor - 1].data();u->forward = u->low_right;if (u->index_cursor >= ilen){qWarning() << "data end on finding u->high_right";u->ok = false;return pu;}//1.3.寻找下降沿,定位U槽右端//while (u->index_cursor < ilen && ps[u->index_cursor]->clk)// u->index_cursor++;u->high_right = ps[u->index_cursor].data();u->forward = u->high_right;//1.4.如果U槽的时间跨度大于28us则不是数据传输,暂不处理佳能中的拱门double fuspan1 = u->high_right->elapse - u->low_right->elapse;double fuspan2 = u->low_right->elapse - u->low_left->elapse;if (fuspan1 > 28 || fuspan1 < 0 || fuspan2 > 28 || fuspan2 < 0){qWarning() << "elapse time out: " << fuspan2 << ", " << fuspan1;u->ok = false;}elseu->ok = true;
#ifdef DEBUGif (u->ok)qInfo() << "u end: " << u->forward->line_no;
#endifreturn pu;
}//信号数据转换为真实的主机与从机之间交换的信息
QList<pspi_data_t> resolve_signal(const QList<pspi_signal_t> &ps)
{int icursor = 0;//遍历ps列表的索引int ilen = ps.length(); //总长度减2,双指针遍历int iorder = 1;QList<pspi_data_t> ds;if (ilen < 17){QMessageBox::critical(nullptr, ZERR_CAPTION, u8"数据量太少。");return ds;}while (icursor < ilen - 17){int ifor_cursor = icursor;//发现问题则回到U槽右端int iu_cursor = 0;pspi_data_t byte(new spi_data_t);pu_shape_t pu;byte->order = iorder;byte->frame_no = 0;byte->dcl = 0;byte->dlc = 0;byte->bad = false;byte->start_line = 0;byte->end_line = 0;byte->elapse = 0;byte->frequency = 0;qInfo() << "byte " << iorder << " begin: " << ps[icursor]->line_no;for (short i = 0; i < 8; i++){pu = find_u_shape(ps, ifor_cursor, ilen);ifor_cursor = pu->index_cursor;if (iu_cursor == 0)iu_cursor = ifor_cursor;if (pu->ok){
#ifdef DEBUGqInfo() << "byte " << iorder << " bit " << i << " at " << pu->low_left->line_no;
#endifif (byte->start_line == 0){byte->start_line = pu->low_left->line_no;byte->elapse = pu->low_left->elapse;}if (pu->high_right->dcl)byte->dcl |= 1 << (7 - i);if (pu->high_right->dlc)byte->dlc |= 1 << (7 - i);}else{byte->bad = true;break;}}if (byte->bad){icursor = iu_cursor;qWarning() << "byte " << iorder << " break: " << pu->forward->line_no;}else{icursor = ifor_cursor;byte->end_line = pu->forward->line_no;byte->elapse = pu->forward->elapse - byte->elapse;byte->frequency = 8000 / byte->elapse;qInfo() << "byte " << iorder << " end: " << pu->high_right->line_no;icursor++;//跳过第9个下降沿while (ps[icursor]->clk && icursor < ilen)icursor++;while (!ps[icursor]->clk && icursor < ilen)icursor++;iorder++;//80KHz下每个bit用时约为13us,1个byte不超过120usif (byte->elapse > 120)byte->bad = true;ds.append(byte);}}return ds;
}//保存信息
void save_spi_data(const QString &zcsv_path, const QList<pspi_data_t> &ds)
{//避免多次执行QChar的构造函数和析构函数static const QChar cfill('0');QFileInfo fi(zcsv_path);QString zresolve_path = fi.dir().absoluteFilePath(fi.baseName() + "resolve.csv");QFile f(zresolve_path);if (!f.open(QFile::ReadWrite | QFile::Text | QFile::Truncate)){QMessageBox::warning(nullptr, ZERR_CAPTION, f.errorString());return;}QTextStream ts(&f);ts << u8" command,sequence, start, end, dcl, dlc,elapse(us),frequency(KHz),bad\n";for (const pspi_data_t &d : ds){// char c = ' ';// if (d->dlc >= 0x20 && d->dlc <= 0x7E && d->dcl == 0)// c = (char)d->dlc;// if (c == ',')// c = ' ';QString zline = QString("%1,%2,%8,%9, %3, %4,%5,%6,%7\n").arg(d->frame_no, 8).arg(d->order, 8).arg(d->dcl, 2, 16, cfill).arg(d->dlc, 2, 16, cfill).arg(d->elapse, 10, 'f', 0).arg(d->frequency, 14, 'f', 0).arg(d->bad, 3).arg(d->start_line, 8).arg(d->end_line, 8);// .arg(c, 4);zline = zline.toUpper();ts << zline;}ts.flush();f.close();QMessageBox::information(nullptr, ZOK_CAPTION, u8"数据转换完成。");qInfo() << u8"数据转换完成。";
}void save_log(QtMsgType type, const QMessageLogContext &cxt, const QString &zlog)
{static QFile f;static QTextStream output(stdout);static QTextStream ts;if (!f.isOpen()){QDir d(QApplication::applicationDirPath());f.setFileName(d.absoluteFilePath("main.log"));if (!f.open(QFile::Append | QFile::Text | QFile::ReadWrite)){QMessageBox::warning(nullptr, ZERR_CAPTION, u8"无法打开日志文件。");return;}ts.setDevice(&f);ts.setAutoDetectUnicode(true);}QString ztype;switch (type){case QtDebugMsg:ztype = u8"DEBG";break;case QtWarningMsg:ztype = u8"WARN";break;case QtCriticalMsg:ztype = u8"CRIT";break;case QtFatalMsg:ztype = u8"FATA";break;case QtInfoMsg:ztype = u8"INFO";break;default:Q_ASSERT(false);break;}ts << ztype << ", " << zlog.toUtf8() << "\n";ts.flush();output << ztype << " " << zlog.toUtf8() << "\n";output.flush();
}//解析帧
void resolve_frame(QList<pspi_data_t> &ds)
{if (ds.length() < 2)return;int ilen = ds.length();int iframe = 0;for (int i = 0; i < ilen; i++){if (ds[i]->dcl > 0)iframe++;ds[i]->frame_no = iframe;}
}
解码效果
如下图所示

解码结果中通信频率、0A与AA应答信号、0x06与0x05的转动信号与实际匹配,说明解码成功。如果想要更多的通信规律,请与我私聊。下一篇讲解常见的指令。
相关文章:
佳能镜头EOS系统EF协议逆向工程(三)解码算法
目录 数据结构 解码算法 解码效果 这篇文章基于上两篇文章继续, 佳能镜头EOS系统EF协议逆向工程(一)转接环电路设计_佳能ef自动对焦协议_岬淢箫声的博客-CSDN博客本文属于专栏——工业相机。此专栏首先提供我人工翻译的法语文档部分&…...
搞互联网吧,线下生意真不是人干的
搞互联网吧,线下生意真不是人干的 应该是正月初几里吧,好巧不巧的被迫去参加了一下我们初中同学的聚会。其实毕业这么多年,无论大学,高中还是中学,类似的聚会我都是能躲则躲,有特别想见的同学也都是私下单…...
MySQL性能调优与设计——MySQL中的索引
MySQL中的索引 InnoDB存储引擎支持以下几种常见索引:B树索引、全文索引、哈希索引,其中比较关键的是B树索引。 B树索引 InnoDB中的索引自然也是按照B树来组织的,B树的叶子节点用来存放数据。 聚集索引/聚簇索引 InnoDB中使用了聚集索引&…...
这5个代码技巧,让我的 Python 加速了很多倍
Python作为一种功能强大的编程语言,因其简单易学而受到很多初学者的青睐。它的应用领域又非常广泛:科学计算、游戏开发、爬虫、人工智能、自动化办公、Web应用开发等等。 而在数据科学领域中,Python 是使用最广泛的编程语言,并且…...
Sphinx+Scws 搭建千万级准实时搜索应用场景详解
目标: 一、搭建准确的千万级数据库的准实时搜索(见详情) 二、实现词语高亮(客户端JS渲染,服务器端渲染,详见7.3) 三、实现搜索联想(输入框onchange,ajax请求搜索,取10条在…...
kafka缩容后,使用tcpdump抓包找到还在连接的用户
1、使用tcpdump抓包监控端口9092 tcpdump src port 9092 16:23:27.680835 IP host01.XmlIpcRegSvc > 192.168.168.1.36199: Flags [R.], seq 0, ack 1493547965, win 0, length 0 16:23:27.681877 IP host01.XmlIpcRegSvc > 192.168.168.2.50416: Flags [R.], seq 0, ac…...
Spring
Spring Spring 是什么? Spring 是于 2003 年兴起的一个轻量级的,IOC 和 AOP 的 Java 开发框架,它 是为了简化企业级应用开发而生的。 Spring有几大特点如下 轻量级的 Spring 框架使用的 jar 都比较小,一般在 1M 以下或者几百 kb。Spring 核 心功能…...
vue2版本《后台管理模式》(中)
文章目录前言一、创建一个文件夹 utils 里面新增一个 setToken.js 文件(设置token验证)二 、创建一个api文件夹 新增 service.js (axios拦截器)三、在api文件夹里 新增一个 api.js 来接收数据(把api封装哪里需要某项数据直接引入就…...
网络游戏开发-服务器篇
1.网络 网络分为弱联网和强联网。 1.弱联网 弱联网是客户端连接到服务端发送一个请求,然后由服务端回应一个内容,这是单向传输的方式,服务端是无法主动给客户端发送消息的,服务端相应请求之后会自动关闭连接。 缺点:传输采用明文,通过抓包可以看到明文信息,安全性不太…...
智慧校园源码:电子班牌,支持手机移动端以及web端对班牌设备的管控
▶ 智慧校园系统有源码,有演示! (电子班牌)设备管理: 1、 管理员查看全校电子班牌设备信息:含有(班级信息、软件版本、设备型号、开关机信息、班牌截屏信息、教室编号、设备ID、设备描述、在线状态、离线状…...
研报精选230216
目录 【行业230216东吴证券】环保行业月报:2023M1环卫新能源渗透率大增至11.91%,上海地区渗透率高达77%【行业230216国元证券】国元新食饮:一图君:22年白酒产量:同降6.2%【行业230216浙商证券】农林牧渔点评报告&#…...
在华为MateBook Ego的arm windows 11上安装hyper-V虚拟机
入手一台华为matebook Ego的笔记本,由于想要测试一些arm的驱动功能,经常会把系统搞蓝屏,于是想安装一个虚拟机,于是试了vmware ,visual-box,由于本机是arm架构上面两个软件都无法进行正常安装,可能是由于有…...
OpenCV Canny边缘检测
本文是OpenCV图像视觉入门之路的第13篇文章,本文详细的介绍了Canny边缘检测算子的各种操作,例如:Canny算子进行边缘检测等操作。 Canny函数是OpenCV中用于执行边缘检测的函数之一,其参数包括: threshold1:…...
C#.Net正则表达式学习笔记
C#.Net正则表达式学习笔记 在处理字符串时,你会经常有查找符合特定条件的字符串的需求,比如判断一串电话号码是否符合格式、一个邮箱是否符合格式、一个密码是否包含了字母大小写等等。 正则表达式(Regular expressions)用于匹配文本,使用一…...
矩阵理论复习(十二)
已知方阵A的不变因子: 求谱半径求矩阵级数判断矩阵幂级数的收敛性 若矩阵B的某个算子范数小于1,则I-B可逆。 矩阵分析 任何相容矩阵范数都存在与之相容的向量范数。 盖尔圆盘定理一的证明 椭圆范数的证明 若||.||是Cm上的向量范数,A为…...
大数据框架之Hadoop:HDFS(七)HDFS 2.X新特性
7.1集群间数据拷贝 scp实现两个远程主机之间的文件复制 scp -r hello.txt roothadoop103:/root/hello.txt // 推 push scp -r roothadoop103:/root/hello.txt hello.txt // 拉 pull scp -r roothadoop103:/root/hello.txt roothadoop104:/root //是通过本地主机中…...
Fluent工作目录
1 工作目录定义工作目录(working directory)是一种文件存储路径设置方式。基于工作目录的方法,写文件时只需要指定文件名,而不需要指定完全的文件路径,从而简化程序编写,对不同操作系统环境有更好的适应性。…...
Learning C++ No.10【STL No.2】
引言: 北京时间:2023/2/14/23:18,放假两个月,没有锻炼,今天去跑了几圈,一个字,累,感觉人都要原地升天了,所以各位小伙伴,准确的说是各位卷王,一定…...
【java 高并发编程之JUC】2w字带你JUC从入门到精通
点击查看脑图目录地址,实时更新 1 什么是 JUC 1.1 JUC 简介 在 Java 中,线程部分是一个重点,本篇文章说的 JUC 也是关于线程的。JUC 就是 java.util .concurrent 工具包的简称。这是一个处理线程的工具包,JDK 1.5 开始出现的。 1.2 进程与…...
QCon演讲实录(下):多云管理关键能力实现与解析-AppManager
在上篇中,我们已经基本了解了多云管理。现在,我们将深入探讨多云管理关键能力实现:AppManager。 什么是AppManager? 上面我们讲了理论、我们自己使用的交付流程和整体架构,下面我们进入关键能力实现与解析的环节&…...
深度学习在微纳光子学中的应用
深度学习在微纳光子学中的主要应用方向 深度学习与微纳光子学的结合主要集中在以下几个方向: 逆向设计 通过神经网络快速预测微纳结构的光学响应,替代传统耗时的数值模拟方法。例如设计超表面、光子晶体等结构。 特征提取与优化 从复杂的光学数据中自…...
业务系统对接大模型的基础方案:架构设计与关键步骤
业务系统对接大模型:架构设计与关键步骤 在当今数字化转型的浪潮中,大语言模型(LLM)已成为企业提升业务效率和创新能力的关键技术之一。将大模型集成到业务系统中,不仅可以优化用户体验,还能为业务决策提供…...
中南大学无人机智能体的全面评估!BEDI:用于评估无人机上具身智能体的综合性基准测试
作者:Mingning Guo, Mengwei Wu, Jiarun He, Shaoxian Li, Haifeng Li, Chao Tao单位:中南大学地球科学与信息物理学院论文标题:BEDI: A Comprehensive Benchmark for Evaluating Embodied Agents on UAVs论文链接:https://arxiv.…...
Cinnamon修改面板小工具图标
Cinnamon开始菜单-CSDN博客 设置模块都是做好的,比GNOME简单得多! 在 applet.js 里增加 const Settings imports.ui.settings;this.settings new Settings.AppletSettings(this, HTYMenusonichy, instance_id); this.settings.bind(menu-icon, menu…...
CocosCreator 之 JavaScript/TypeScript和Java的相互交互
引擎版本: 3.8.1 语言: JavaScript/TypeScript、C、Java 环境:Window 参考:Java原生反射机制 您好,我是鹤九日! 回顾 在上篇文章中:CocosCreator Android项目接入UnityAds 广告SDK。 我们简单讲…...
Module Federation 和 Native Federation 的比较
前言 Module Federation 是 Webpack 5 引入的微前端架构方案,允许不同独立构建的应用在运行时动态共享模块。 Native Federation 是 Angular 官方基于 Module Federation 理念实现的专为 Angular 优化的微前端方案。 概念解析 Module Federation (模块联邦) Modul…...
排序算法总结(C++)
目录 一、稳定性二、排序算法选择、冒泡、插入排序归并排序随机快速排序堆排序基数排序计数排序 三、总结 一、稳定性 排序算法的稳定性是指:同样大小的样本 **(同样大小的数据)**在排序之后不会改变原始的相对次序。 稳定性对基础类型对象…...
【 java 虚拟机知识 第一篇 】
目录 1.内存模型 1.1.JVM内存模型的介绍 1.2.堆和栈的区别 1.3.栈的存储细节 1.4.堆的部分 1.5.程序计数器的作用 1.6.方法区的内容 1.7.字符串池 1.8.引用类型 1.9.内存泄漏与内存溢出 1.10.会出现内存溢出的结构 1.内存模型 1.1.JVM内存模型的介绍 内存模型主要分…...
Java求职者面试指南:Spring、Spring Boot、Spring MVC与MyBatis技术解析
Java求职者面试指南:Spring、Spring Boot、Spring MVC与MyBatis技术解析 一、第一轮基础概念问题 1. Spring框架的核心容器是什么?它的作用是什么? Spring框架的核心容器是IoC(控制反转)容器。它的主要作用是管理对…...
【Linux】Linux安装并配置RabbitMQ
目录 1. 安装 Erlang 2. 安装 RabbitMQ 2.1.添加 RabbitMQ 仓库 2.2.安装 RabbitMQ 3.配置 3.1.启动和管理服务 4. 访问管理界面 5.安装问题 6.修改密码 7.修改端口 7.1.找到文件 7.2.修改文件 1. 安装 Erlang 由于 RabbitMQ 是用 Erlang 编写的,需要先安…...
