【C++】STL性能优化实战
STL性能优化实战
STL (Standard Template Library) 是 C++ 标准库的核心部分,提供了各种容器、算法和迭代器。虽然 STL 提供了强大的功能,但不恰当的使用可能导致性能问题。下面我将详细介绍 STL 性能优化的实战技巧,并通过具体案例说明。
1. 容器选择优化
不同的 STL 容器有不同的性能特性,选择合适的容器对性能影响很大。
案例:从 std::list
到 std::vector
// 优化前:使用list存储大量数据并频繁随机访问
std::list<int> dataList;
for (int i = 0; i < 1000000; i++) {dataList.push_back(i);
}// 查找第500000个元素
auto it = dataList.begin();
std::advance(it, 500000); // O(n)操作,非常慢
int value = *it;// 优化后:使用vector
std::vector<int> dataVector;
dataVector.reserve(1000000); // 预分配内存,避免多次重新分配
for (int i = 0; i < 1000000; i++) {dataVector.push_back(i);
}// 查找第500000个元素,O(1)操作
int value = dataVector[500000];
性能差异:在百万级数据上,vector
的随机访问可能比 list
快数百倍。
2. 内存管理优化
预分配内存
// 优化前
std::vector<int> v;
for (int i = 0; i < 100000; i++) {v.push_back(i); // 可能导致多次重新分配内存
}// 优化后
std::vector<int> v;
v.reserve(100000); // 预先分配足够的内存
for (int i = 0; i < 100000; i++) {v.push_back(i); // 不再需要重新分配内存
}
案例:大型应用中的内存优化
class DataProcessor {
private:std::vector<double> data;std::vector<int> indices;public:// 优化前void processData(const std::vector<double>& input) {// 每次处理都重新分配内存data.clear();indices.clear();for (size_t i = 0; i < input.size(); i++) {if (input[i] > 0) {data.push_back(input[i]);indices.push_back(i);}}}// 优化后void processDataOptimized(const std::vector<double>& input) {// 估计可能的大小并预分配data.clear();indices.clear();data.reserve(input.size() / 2); // 假设约一半的元素符合条件indices.reserve(input.size() / 2);for (size_t i = 0; i < input.size(); i++) {if (input[i] > 0) {data.push_back(input[i]);indices.push_back(i);}}// 释放多余容量data.shrink_to_fit();indices.shrink_to_fit();}
};
3. 迭代器和算法优化
使用合适的算法
std::vector<int> v(1000000);
// 填充数据...// 优化前:手动查找
int target = 42;
bool found = false;
for (auto it = v.begin(); it != v.end(); ++it) {if (*it == target) {found = true;break;}
}// 优化后:使用STL算法
bool found = std::find(v.begin(), v.end(), target) != v.end();// 更优化:如果容器已排序
std::sort(v.begin(), v.end()); // 先排序
bool found = std::binary_search(v.begin(), v.end(), target); // 二分查找,O(log n)
案例:数据分析应用中的算法优化
class DataAnalyzer {
private:std::vector<double> dataset;public:// 优化前:手动实现统计计算std::pair<double, double> calculateMeanAndStdDev() {double sum = 0.0;for (const auto& value : dataset) {sum += value;}double mean = sum / dataset.size();double sumSquaredDiff = 0.0;for (const auto& value : dataset) {double diff = value - mean;sumSquaredDiff += diff * diff;}double stdDev = std::sqrt(sumSquaredDiff / dataset.size());return {mean, stdDev};}// 优化后:使用STL算法std::pair<double, double> calculateMeanAndStdDevOptimized() {double sum = std::accumulate(dataset.begin(), dataset.end(), 0.0);double mean = sum / dataset.size();double sumSquaredDiff = std::transform_reduce(dataset.begin(), dataset.end(),0.0,std::plus<>(),[mean](double value) { return std::pow(value - mean, 2); });double stdDev = std::sqrt(sumSquaredDiff / dataset.size());return {mean, stdDev};}
};
4. 避免不必要的拷贝
使用引用和移动语义
// 优化前:传值和返回值导致多次拷贝
std::vector<int> processData(std::vector<int> data) {std::vector<int> result;// 处理数据...return result;
}// 优化后:使用引用和移动语义
std::vector<int> processDataOptimized(const std::vector<int>& data) {std::vector<int> result;// 处理数据...return std::move(result); // 使用移动语义
}// 调用方式优化
std::vector<int> input = {1, 2, 3, 4, 5};
// 优化前
auto result1 = processData(input); // 拷贝input// 优化后
auto result2 = processDataOptimized(input); // 使用引用,避免拷贝
案例:大型文本处理应用
class TextProcessor {
private:std::vector<std::string> documents;public:// 优化前void addDocument(std::string doc) {documents.push_back(doc); // 拷贝doc}std::vector<std::string> findMatchingDocuments(std::string pattern) {std::vector<std::string> matches;for (const auto& doc : documents) {if (doc.find(pattern) != std::string::npos) {matches.push_back(doc); // 拷贝doc}}return matches; // 拷贝整个matches}// 优化后void addDocumentOptimized(std::string&& doc) {documents.push_back(std::move(doc)); // 移动doc,避免拷贝}std::vector<std::string> findMatchingDocumentsOptimized(const std::string& pattern) {std::vector<std::string> matches;matches.reserve(documents.size() / 10); // 预估匹配数量for (const auto& doc : documents) {if (doc.find(pattern) != std::string::npos) {matches.push_back(doc); // 仍然是拷贝,但预分配了内存}}return std::move(matches); // 移动返回,避免拷贝}
};
5. 使用 emplace
系列函数
struct ComplexObject {std::string name;int id;std::vector<double> data;ComplexObject(std::string n, int i, std::vector<double> d): name(std::move(n)), id(i), data(std::move(d)) {}
};// 优化前
std::vector<ComplexObject> objects;
std::string name = "Object1";
int id = 42;
std::vector<double> data = {1.0, 2.0, 3.0};
objects.push_back(ComplexObject(name, id, data)); // 构造临时对象然后拷贝/移动// 优化后
objects.emplace_back(name, id, data); // 直接在容器内构造对象,避免临时对象
案例:游戏引擎中的实体管理
class EntityManager {
private:std::vector<Entity> entities;std::unordered_map<std::string, Entity*> entityMap;public:// 优化前void addEntity(const std::string& name, int health, const Position& pos) {Entity entity(name, health, pos);entities.push_back(entity);entityMap[name] = &entities.back();}// 优化后void addEntityOptimized(std::string name, int health, Position pos) {entities.emplace_back(std::move(name), health, std::move(pos));Entity& entity = entities.back();entityMap.emplace(entity.getName(), &entity);}
};
6. 使用正确的查找方法
案例:频繁查找操作的优化
// 场景:需要频繁查找元素
// 优化前:使用vector和find算法
std::vector<int> data = {/* 大量数据 */};
bool exists = std::find(data.begin(), data.end(), target) != data.end(); // O(n)// 优化方案1:如果数据已排序,使用binary_search
std::sort(data.begin(), data.end()); // 一次性排序
bool exists = std::binary_search(data.begin(), data.end(), target); // O(log n)// 优化方案2:如果需要频繁查找,使用unordered_set
std::unordered_set<int> dataSet(data.begin(), data.end());
bool exists = dataSet.find(target) != dataSet.end(); // 平均O(1)
实际应用:网络包过滤器
class PacketFilter {
private:// 优化前:使用vector存储IP黑名单std::vector<std::string> blacklistedIPs;// 优化后:使用unordered_set存储IP黑名单std::unordered_set<std::string> blacklistedIPSet;public:// 优化前bool isBlacklisted(const std::string& ip) {return std::find(blacklistedIPs.begin(), blacklistedIPs.end(), ip) != blacklistedIPs.end();// 时间复杂度:O(n),n为黑名单大小}// 优化后bool isBlacklistedOptimized(const std::string& ip) {return blacklistedIPSet.find(ip) != blacklistedIPSet.end();// 时间复杂度:平均O(1)}// 初始化函数void initialize(const std::vector<std::string>& ips) {// 优化前blacklistedIPs = ips;// 优化后blacklistedIPSet.clear();blacklistedIPSet.reserve(ips.size());for (const auto& ip : ips) {blacklistedIPSet.insert(ip);}}
};
7. 自定义比较和哈希函数
案例:复杂对象的高效存储和查找
struct Customer {std::string id;std::string name;std::string address;// 其他字段...bool operator==(const Customer& other) const {return id == other.id; // 只比较ID}
};// 自定义哈希函数
namespace std {template<>struct hash<Customer> {size_t operator()(const Customer& c) const {return hash<std::string>()(c.id); // 只哈希ID}};
}// 使用自定义哈希的容器
std::unordered_set<Customer> customers;
std::unordered_map<Customer, int> customerScores;
实际应用:缓存系统
class CacheSystem {
private:struct CacheKey {std::string resource;std::string version;std::string locale;bool operator==(const CacheKey& other) const {return resource == other.resource && version == other.version && locale == other.locale;}};struct CacheKeyHash {size_t operator()(const CacheKey& key) const {// 组合哈希size_t h1 = std::hash<std::string>()(key.resource);size_t h2 = std::hash<std::string>()(key.version);size_t h3 = std::hash<std::string>()(key.locale);return h1 ^ (h2 << 1) ^ (h3 << 2);}};// 使用自定义键和哈希函数的缓存std::unordered_map<CacheKey, std::vector<char>, CacheKeyHash> cache;public:void store(const std::string& resource, const std::string& version, const std::string& locale, const std::vector<char>& data) {CacheKey key{resource, version, locale};cache[key] = data;}bool retrieve(const std::string& resource, const std::string& version,const std::string& locale, std::vector<char>& outData) {CacheKey key{resource, version, locale};auto it = cache.find(key);if (it != cache.end()) {outData = it->second;return true;}return false;}
};
8. 并行算法优化
C++17 引入了并行算法,可以显著提高性能。
#include <execution>
#include <algorithm>
#include <vector>std::vector<int> data(10000000);
// 填充数据...// 优化前:单线程排序
std::sort(data.begin(), data.end());// 优化后:并行排序
std::sort(std::execution::par, data.begin(), data.end());// 其他并行算法示例
std::for_each(std::execution::par, data.begin(), data.end(), [](int& x) { x *= 2; });
auto sum = std::reduce(std::execution::par, data.begin(), data.end(), 0);
案例:图像处理应用
class ImageProcessor {
private:std::vector<Pixel> imageData; // 假设Pixel是一个表示像素的结构体int width, height;public:// 优化前:单线程处理void applyFilter(const Filter& filter) {for (auto& pixel : imageData) {pixel = filter.process(pixel);}}// 优化后:并行处理void applyFilterParallel(const Filter& filter) {std::for_each(std::execution::par,imageData.begin(),imageData.end(),[&filter](Pixel& pixel) {pixel = filter.process(pixel);});}// 优化前:单线程边缘检测std::vector<Edge> detectEdges() {std::vector<Edge> edges;// 复杂的边缘检测算法...return edges;}// 优化后:分块并行边缘检测std::vector<Edge> detectEdgesParallel() {// 将图像分成多个块const int blockSize = height / std::thread::hardware_concurrency();std::vector<std::vector<Edge>> blockEdges(std::thread::hardware_concurrency());std::vector<std::thread> threads;for (int i = 0; i < std::thread::hardware_concurrency(); ++i) {threads.emplace_back([this, i, blockSize, &blockEdges]() {int startY = i * blockSize;int endY = (i == std::thread::hardware_concurrency() - 1) ? height : (i + 1) * blockSize;// 处理当前块for (int y = startY; y < endY; ++y) {for (int x = 0; x < width; ++x) {// 边缘检测逻辑...if (/* 检测到边缘 */) {blockEdges[i].push_back(Edge{x, y});}}}});}// 等待所有线程完成for (auto& thread : threads) {thread.join();}// 合并结果std::vector<Edge> allEdges;for (const auto& edges : blockEdges) {allEdges.insert(allEdges.end(), edges.begin(), edges.end());}return allEdges;}
};
9. 小字符串优化 (SSO) 和字符串视图
// 优化前:频繁创建临时字符串
std::string extractSubstring(const std::string& str, size_t start, size_t length) {return str.substr(start, length);
}void processSubstrings(const std::string& text) {for (size_t i = 0; i < text.size(); i += 10) {std::string sub = extractSubstring(text, i, 10);// 处理sub...}
}// 优化后:使用string_view避免拷贝
std::string_view extractSubstringView(const std::string& str, size_t start, size_t length) {return std::string_view(str.data() + start, std::min(length, str.size() - start));
}void processSubstringsOptimized(const std::string& text) {for (size_t i = 0; i < text.size(); i += 10) {std::string_view sub = extractSubstringView(text, i, 10);// 处理sub...}
}
案例:日志解析器
class LogParser {
private:std::vector<std::string> logLines;public:// 优化前std::vector<std::string> extractTimestamps() {std::vector<std::string> timestamps;timestamps.reserve(logLines.size());for (const auto& line : logLines) {// 假设时间戳在每行的前19个字符if (line.size() >= 19) {timestamps.push_back(line.substr(0, 19));}}return timestamps;}// 优化后:使用string_viewstd::vector<std::string_view> extractTimestampsOptimized() {std::vector<std::string_view> timestamps;timestamps.reserve(logLines.size());for (const auto& line : logLines) {if (line.size() >= 19) {timestamps.emplace_back(line.data(), 19);}}return timestamps;}// 进一步优化:直接处理而不存储void processTimestamps(std::function<void(std::string_view)> processor) {for (const auto& line : logLines) {if (line.size() >= 19) {processor(std::string_view(line.data(), 19));}}}
};
10. 性能分析与测量
优化的最后一步是测量和验证。
#include <chrono>template<typename Func>
auto measureTime(Func&& func) {auto start = std::chrono::high_resolution_clock::now();std::forward<Func>(func)();auto end = std::chrono::high_resolution_clock::now();return std::chrono::duration_cast<std::chrono::milliseconds>(end - start).count();
}// 使用示例
void comparePerformance() {std::vector<int> data(1000000);// 填充数据...auto timeOriginal = measureTime([&]() {// 原始算法std::sort(data.begin(), data.end());});auto timeOptimized = measureTime([&]() {// 优化算法std::sort(std::execution::par, data.begin(), data.end());});std::cout << "原始算法: " << timeOriginal << "ms\n";std::cout << "优化算法: " << timeOptimized << "ms\n";std::cout << "性能提升: " << (static_cast<double>(timeOriginal) / timeOptimized) << "x\n";
}
案例:大型应用性能分析
class PerformanceAnalyzer {
public:void analyzeDataStructures() {const int dataSize = 1000000;// 测试vector vs list的随机访问性能std::vector<int> vec(dataSize);std::list<int> lst;for (int i = 0; i < dataSize; ++i) {vec[i] = i;lst.push_back(i);}std::cout << "随机访问性能测试:\n";auto vecTime = measureTime([&]() {int sum = 0;for (int i = 0; i < 1000; ++i) {int idx = rand() % dataSize;sum += vec[idx];}});auto lstTime = measureTime([&]() {int sum = 0;for (int i = 0; i < 1000; ++i) {int idx = rand() % dataSize;auto it = lst.begin();std::advance(it, idx);sum += *it;}});std::cout << "Vector随机访问: " << vecTime << "ms\n";std::cout << "List随机访问: " << lstTime << "ms\n";std::cout << "性能差异: " << (static_cast<double>(lstTime) / vecTime) << "x\n";// 测试查找性能std::cout << "\n查找性能测试:\n";std::vector<int> searchVec(dataSize);std::set<int> searchSet;std::unordered_set<int> searchHashSet;for (int i = 0; i < dataSize; ++i) {searchVec[i] = i;searchSet.insert(i);searchHashSet.insert(i);}auto vecSearchTime = measureTime([&]() {int count = 0;for (int i = 0; i < 10000; ++i) {int target = rand() % (dataSize * 2); // 一半会找不到if (std::find(searchVec.begin(), searchVec.end(), target) != searchVec.end()) {count++;}}});auto setSearchTime = measureTime([&]() {int count = 0;for (int i = 0; i < 10000; ++i) {int target = rand() % (dataSize * 2);if (searchSet.find(target) != searchSet.end()) {count++;}}});auto hashSetSearchTime = measureTime([&]() {int count = 0;for (int i = 0; i < 10000; ++i) {int target = rand() % (dataSize * 2);if (searchHashSet.find(target) != searchHashSet.end()) {count++;}}});std::cout << "Vector线性查找: " << vecSearchTime << "ms\n";std::cout << "Set二分查找: " << setSearchTime << "ms\n";std::cout << "Unordered_set哈希查找: " << hashSetSearchTime << "ms\n";}private:template<typename Func>auto measureTime(Func&& func) {auto start = std::chrono::high_resolution_clock::now();std::forward<Func>(func)();auto end = std::chrono::high_resolution_clock::now();return std::chrono::duration_cast<std::chrono::milliseconds>(end - start).count();}
};
总结
STL 性能优化是一个系统性工作,需要从多个角度考虑:
- 选择合适的容器:根据操作特性选择最适合的容器类型
- 内存管理:预分配内存、避免频繁重新分配
- 算法选择:使用 STL 提供的高效算法,考虑并行算法
- 避免拷贝:使用引用、移动语义和 emplace 系列函数
- 高效查找:对于频繁查找操作,使用哈希容器或保持有序状态
- 自定义比较和哈希:为复杂对象提供高效的比较和哈希函数
- 字符串优化:利用 SSO 和 string_view 减少字符串操作开销
- 性能测量:通过实际测量验证优化效果
通过这些技术,可以显著提高 C++ 程序的性能,同时保持代码的可读性和可维护性。
相关文章:
【C++】STL性能优化实战
STL性能优化实战 STL (Standard Template Library) 是 C 标准库的核心部分,提供了各种容器、算法和迭代器。虽然 STL 提供了强大的功能,但不恰当的使用可能导致性能问题。下面我将详细介绍 STL 性能优化的实战技巧,并通过具体案例说明。 1.…...
Playwright + MCP:用AI对话重新定义浏览器自动化,效率提升300%!
一、引言:自动化测试的“瓶颈”与MCP的革新 传统自动化测试依赖开发者手动编写脚本,不仅耗时且容易因页面动态变化失效。例如,一个简单的登录流程可能需要开发者手动定位元素、处理等待逻辑,甚至反复调试超时问题。而MCP…...
12-scala样例类(Case Classes)
例类(Case classes)和普通类差不多,只有几点关键差别,接下来的介绍将会涵盖这些差别。样例类非常适合用于不可变的数据。 定义一个样例类 一个最简单的样例类定义由关键字case class,类名,参数列表&#…...
WPF 与 C# 开发深度剖析
一、引言 在当今的软件开发领域,Windows 平台依旧占据着重要的地位。而 WPF(Windows Presentation Foundation)作为微软推出的一款强大的用户界面(UI)框架,为开发者提供了丰富的功能和灵活的设计方式&…...
【工具使用-编译器】VScode(Ubuntu)使用
1. VScode的快捷键 快捷键功能说明Ctrl+Shift+P / F1显示命令面板Ctrl+P快速打开文件Ctrl+Shift+N新建窗口Ctrl+Shift+W关闭窗口Ctrl+,打开设置Ctrl+K Ctrl+S打开快捷键设置Ctrl+X剪切行(无选中时剪切整行)Ctrl+C复制行(无选中时复制整行)Alt+↑ / Alt+↓向上/向下移动行Sh…...
C# SerialPort 使用详解
总目录 前言 在工业控制、物联网、嵌入式开发等领域,串口通信(Serial Port Communication)是连接串行设备(如条码扫描器、GPS接收器等)与计算机的重要手段。C# 提供了内置的 SerialPort 类,简化了串口开发…...
数据结构--二叉排序树
一、二叉排序树的定义 二叉排序树,又称二叉查找树。 性质: 左子树结点值<根结点值<右子树结点值(进行中序遍历,可以得到一个递增的有序序列) 二、查找操作 利用二叉排序树的性质,如果树空,…...
FPGA的直方图均衡
文章目录 一、直方图均衡二、代码实现三、仿真 一、直方图均衡 直方图均衡(Histogram Equalization)是一种用于增强图像对比度的图像处理技术。它通过重新分配图像像素的灰度值,使得图像的灰度直方图在整个灰度范围内均匀分布,从而…...
使用Python将视频转化为gif
使用Python将视频转化为gif 一、前言二、准备三、测试 一、前言 最近想把喜欢的视频片段作成gif,就试着用Python做了下,感觉效果还行,这里做个记录。 二、准备 先下载安装对应的库,命令如下: pip install moviepy …...
基于javaweb的SpringBoot雪具商城系统设计与实现系统(源码+文档+部署讲解)
技术范围:SpringBoot、Vue、SSM、HLMT、Jsp、PHP、Nodejs、Python、爬虫、数据可视化、小程序、安卓app、大数据、物联网、机器学习等设计与开发。 主要内容:免费功能设计、开题报告、任务书、中期检查PPT、系统功能实现、代码编写、论文编写和辅导、…...
Harbor镜像仓库迁移与高可用集群搭建HTTPS实现实战指南
实验环境 Ubuntu22.04操作系统 registry节点 10.0.0.91 master节点 10.0.0.92 backup节点 10.0.0.93 在企业信息化建设的不同演进阶段,私有镜像仓库的选型策略存在显著差异。近期主导完成某企业级容器镜像仓库升级项目,成功实现Docker Registry至Ha…...
redis--JavaSpring客户端
目录 一、引言 二、配置 三、相关操作 四、总结 一、引言 本篇文章会将redis与spring项目进行结合,看看再spring项目中,redis是如何使用的 二、配置 三、相关操作 四、总结 在spring项目中的使用和在基础项目上的使用有差异,但是差异并不大…...
JavaWeb3
聚合函数:把某一列的数据计算。count,max,min,avg,sum select count(id) from wife;-- 统计个数,不计算null,统计常量表示个数 select count(*) from wife; select min(id) from wife; select avg(age) from wife; 分组查询 select name,c…...
SAP-ABAP:SAP数据集成全场景技术指南(BAPI、RFC、IDOC、BATCHJOB、ODATA、WEBSERVICE):从实时交互到批量处理
SAP数据集成全场景技术指南:从实时交互到批量处理 #mermaid-svg-hpPMerJYUerla0BJ {font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}#mermaid-svg-hpPMerJYUerla0BJ .error-icon{fill:#552222;}#mermaid-svg-hpPMerJYUerla0BJ .er…...
QT笔记----QCheckBox
文章目录 概要1、QCheckBox 的基本概念2、单个QCheckBox3、多个QCheckBox同时应用3.1、实现效果3.2、实现Demo 概要 在 Qt 应用程序开发中,QCheckBox 是一个常用的用户界面元素,它允许用户在两种状态(选中和未选中)之间进行切换&a…...
试试智能体工作流,自动化搞定运维故障排查
APO 1.5.0版本全新推出的智能体工作流功能,让运维经验不再零散!只需将日常的运维操作和故障排查经验转化为标准化流程,就能一键复用,效率翻倍,从此告别重复劳动,把时间留给更有价值的创新工作。更贴心的是&…...
3.24[Q]Linux
我正在学习Linux,Linux设备管理是怎样的?详细解释,越细节越好 我正在学习Linux,在Linux设备管理中,什么是char device?以及block,usb device?详细解释,越细节越好 我正在学习Linux࿰…...
深度学习——图像相似度评价指标
这里写目录标题 PSNR(Peak Signal-to-Noise Ratio,峰值信噪比)定义公式代码 SSIMMS-SSIM (Multi Scale Structural Similarity Index Measure,多尺度结构相似性)CSS (Contrast-Structure Similarity 对比结构相似度)MA…...
CentOS安装sshpass工具-自动化SSH密码认证
sshpass是一个在Linux环境下用于自动化SSH密码认证的工具。 一、功能特点 自动化SSH登录:sshpass允许用户在命令行中直接传递密码,从而无需在SSH连接时手动输入密码。这对于自动化脚本和批处理任务非常有用,因为它可以在非交互式环境下完成…...
js 中 如何获取数组的交集【面试题】
一、数组元素为基本类型:Number、String、等基本类型时 1、使用 Set 和 filter(适用于两个数组) const intersection (arr1, arr2) > {const set new Set(arr2);return [...new Set(arr1)].filter(item > set.has(item)); };将第二…...
value-key 的作用
在 el-autocomplete 组件中,value-key 是一个非常重要的属性,它用于指定选项对象中作为值的字段名。当选项列表是一个包含多个属性的对象数组时,value-key 能帮助组件明确哪个属性是实际要使用的值。比如,选项列表为 [{id: 01, na…...
Spring MVC:从历史演变到实战入门
1. Java Web的发展历史与MVC模式 1.1 Model I与Model II的演进 Model I(JSPJavaBean) 作为早期Java Web开发的主流模式,其核心架构如下: graph LR A[客户端] --> B[JSP页面] B --> C{业务逻辑} C --> D[JavaBean] D -…...
Matlab设置表table的表头
用到matlab的table很好用。经常涉及放入数据,读取数据,下面总结常用的知识点。 1. 把不同数据类型放到同一个表中 想把时间类型和数值类型放到统一table中。困扰的点是,我已经知道了表头名称, 如何批量的为表头命名,…...
预测蓝桥杯16届嵌入式省赛客观题
以下是15道蓝桥杯嵌入式省赛客观题预测,每道题均包含**选项列表**、**答案**和**解析**,格式清晰便于快速查阅: 一、预测1 ### **一、STM32G4硬件基础与外设配置** 1. **STM32G431RBT6的Flash和RAM容量分别为?** **选项**&a…...
综合章节:游戏网络化、模组化与深度扩展
模块一:网络功能与玩家数据同步 目标:实现玩家得分上传、全球排行榜展示及云端数据同步。 # network_manager.py(网络请求封装) import requests import threadingclass NetworkManager:def __init__(self, base_url"http:…...
PostgreSQL:索引与查询优化
🧑 博主简介:CSDN博客专家,历代文学网(PC端可以访问:https://literature.sinhy.com/#/?__c1000,移动端可微信小程序搜索“历代文学”)总架构师,15年工作经验,精通Java编…...
Android Compose 框架的 ViewModel 委托深入剖析(二十)
Android Compose 框架的 ViewModel 委托深入剖析 一、引言 在 Android 开发中,数据的管理和状态的保存是至关重要的。ViewModel 作为 Android 架构组件的一部分,为我们提供了一种在配置更改(如屏幕旋转)时保存数据和管理 UI 状态…...
android|生成二维码qrcode(android)
1.build.gradle implementation com.google.zxing:core:3.4.1引入zxing库 只是生成的话引入core库就可以了 2.封装方法 import android.graphics.Bitmap; import android.graphics.Color;import com.google.zxing.BarcodeFormat; import com.google.zxing.EncodeHintType; imp…...
element-plus中el-empty空盒子组件和Collapse 折叠面板组件的使用
一.el-empty空盒子组件的使用 直接复制下面的代码: <el-empty description"description" /> 展示效果: 还可以自定义文字描述: <el-empty description"暂未选择患者"/> 二.Collapse 折叠面板组件的使用 复制…...
Windows 和 Linux 操作系统架构对比以及交叉编译
操作系统与架构兼容性详解 1. 可执行文件格式:PE vs ELF Windows: PE (Portable Executable) 格式 详细解释: PE 格式是 Windows 下的可执行文件标准 包含多个区段(Sections),如代码段、数据段、资源段 文件头包含…...
【区块链安全 | 第一篇】密码学原理
文章目录 1.哈希函数1.1 哈希函数的性质1.2 常见哈希算法1.3 Merkle Tree(默克尔树)1.4 HMAC(哈希消息认证码) 2. 公钥密码学2.1 对称加密 vs 非对称加密2.2 RSA 算法2.3 ECC(椭圆曲线密码学)2.4 Diffie-He…...
3.23[A]linux
gedit 是 GNOME 桌面环境下的文本编辑器,类似于 Windows 中的记事本,但功能更强大,支持语法高亮、多文件编辑等特性。它是一个图形化界面的文本编辑器,适合在需要直观编辑文本文件的场景中使用。 gedit 通常用于编辑配置文件、源代…...
AI革命之下的前端将会如何发展?
一、AI 为前端开发带来的变革 (一)提升开发效率 传统的 Web 前端开发常常面临大量重复性工作,如编写简单表单、布局组件等,这些工作耗时费力且易出错,严重影响开发效率和项目进度。而 AI 的出现,通过自动…...
【2025】基于springboot+vue的农产品商城系统设计与实现(源码、万字文档、图文修改、调试答疑)
项目完整功能以演示视频为准 基于Spring Boot Vue的农产品商城系统设计与实现功能结构图如下: 课题背景 随着互联网的普及和电子商务的快速发展,农产品线上销售成为推动农业现代化和乡村振兴的重要力量。传统的农产品销售模式存在信息不对称、销售渠道单…...
沪深300股指期货的看涨看跌方式是怎样的?
沪深300指数代表了中国A股市场中300家大公司的整体表现。股指期货交易允许老板们预测指数未来的涨跌,并从中获利。 沪深300股指期货基础操作 首先,沪深300股指期货中的看涨操作:老板们可以通过买入沪深300股指期货合约,代码也就是…...
使用selenium来获取数据集
使用selenium来获取数据集 1、下载最新的chrome浏览器与chromedriver.exe 查看chrome的版本,打开谷歌浏览器,点击右上角的三个点,然后点击【帮助】, 点击【关于Google Chrome】 然后去下载同样为134版本号的chromedriver.exe, 网址:https://googlechromelabs.github.…...
MCP(大模型上下文协议)
以下是关于大模型MCP协议(Model Context Protocol)的详细介绍,综合其定义、技术架构、应用场景及行业影响: 一、定义与核心目标 **MCP(Model Context Protocol,模型上下文协议)**是由Anthropic…...
FPGA中串行执行方式之流水线(Pipeline)
FPGA中串行执行方式之流水线(Pipeline) 在FPGA设计中,流水线(Pipeline) 是一种常见的优化技术,用于提高系统的吞吐量和性能。流水线通过将复杂的逻辑分解为多个阶段,每个阶段在一个时钟周期内完成一部分工作,并将中间结果传递到下一阶段。这种方式可以显著提高时钟…...
Python 3.8 Requests 爬虫教程(2025最新版)
遵守网站的爬虫规则、避免爬取敏感信息、保护个人隐私! 一、环境配置与基础验证 # 验证 Python 版本(需 ≥3.8) import sys print(sys.version) # 应输出类似 3.8.12 的信息# 安装 requests 库(若未安装) # 命令行执…...
【深度学习】GAN生成对抗网络:原理、应用与发展
GAN生成对抗网络:原理、应用与发展 文章目录 GAN生成对抗网络:原理、应用与发展1. 引言2. GAN的基本原理2.1 核心思想2.2 数学表达2.3 训练过程 3. GAN的主要变体3.1 DCGAN (Deep Convolutional GAN)3.2 CGAN (Conditional GAN)3.3 CycleGAN3.4 StyleGAN…...
LINUX基础 [三] - 进程创建
目录 前言 进程创建的初次了解(创建进程的原理) 什么是fork函数? 初识fork函数 写时拷贝 fork函数存在的意义 fork调用失败的原因 进程终止 运行完毕结果不正确 main函数返回 库函数函数exit 系统调用接口_exit 进程异常终止 进…...
AI比人脑更强,因为被植入思维模型【24】替身决策思维模型
定义 替身决策思维模型是一种在面对复杂问题或决策情境时,通过将自己代入到不同的角色(即“替身”)中,从这些角色的视角出发去思考、分析和做出决策的思维方式。这种思维模型要求决策者暂时摆脱自身固有的思维定式和立场…...
数据清洗:基于python抽取jsonl文件数据字段
基于python抽取目录下所有“jsonl”格式文件。遍历文件内某个字段进行抽取并合并。 import os import json import time from tqdm import tqdm # 需要先安装:pip install tqdmdef process_files():# 设置目录路径dir_path r"D:\daku\关键词识别\1623-00000…...
spring后端处理各种请求
在Spring MVC中处理JSON请求和返回JSON消息的步骤如下: 1. 添加依赖 确保项目中包含处理JSON的库,如Jackson。 Maven配置(pom.xml): <dependency><groupId>com.fasterxml.jackson.core</groupId>…...
企业级部署zabbix分布式监控系统
目录 一、Zabbix分布式监控系统介绍 1.什么是“Zabbix” 2.Zabbix分布式监控系统的特点 3.Zabbix分布式监控系统的原理 4.Zabbix分布式监控系统的运用 5. Zabbix分布式监控系统的部署顺序 二、搭建 1.设备硬件配置参考 2.zabbix分布式监控系统各节点设备名称和IP规划 …...
OkHttp 的证书设置
在 Android 开发中,通过 OkHttp 自定义 SSLSocketFactory 和 X509TrustManager 可以有效增强 HTTPS 通信的安全性,防止中间人攻击(如抓包工具 Charles/Fiddler 的拦截)。以下是实现防抓包的关键技术方案: 一、Okhttp设…...
ETL:数据清洗、规范化和聚合的重要性
在当今这个数据呈爆炸式增长的时代,数据已成为企业最为宝贵的资产之一。然而,数据的海量增长也伴随着诸多问题,如数据来源多样、结构复杂以及质量问题等,这些问题严重阻碍了数据的有效处理与深度分析。在此背景下,ETL&…...
蓝桥杯备考:图的遍历
这道题乍一看好像没什么不对的,但是!但是!结点最大可以到10的5次方!!!我们递归的时间复杂度是很高的,我们正常遍历是肯定通过不了的,不信的话我们试一下 #include <iostream>…...
【多媒体交互】Unity Kinect实现UI控件的点击
在Unity中,通过Kinect实现UI控件的点击功能,主要涉及手部追踪、坐标映射和手势检测三个核心环节。 实现步骤 初始化Kinect与关节追踪 使用KinectManager获取用户ID和手部关节点(如JointType.HandLeft)的坐标。 long userId _…...
QinQ项展 VLAN 空间
随着以太网技术在网络中的大量部署,利用 VLAN 对用户进行隔离和标识受到很大限制。因为 IEEE802.1Q 中定义的 VLAN Tag 域只有 12 个比特,仅能表示 4096 个 VLAN,无法满足城域以太网中标识大量用户的需求,于是 QinQ 技术应运而生。…...