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

浅谈性能优化(基于C++)

本文主要针对C++的性能优化方法展开讨论。虽然这些方法也适用于一些其他语言,但由于C++经常用于底层操作,提供了更多的优化空间;相比之下,诸如Python、Kotlin等高级语言由于其抽象程度更高,优化空间较少。

性能优化原理

要实现性能优化,需要从硬件和软件层面了解优化的实现原理,尤其是围绕运算和存储两个方面。

CPU三级缓存机制

首先来看CPU的三级缓存机制,这是了解性能优化的关键概念。下图展示了CPU三级缓存的结构:

cpu三级缓存

从图中可以看出,越靠近CPU的内存,存储速度越快但空间越小。这涉及到一个关键概念——缓存命中率。CPU对内存的调用逻辑是首先查看L1数据高速缓存是否命中数据,如果没有,再查看L2高速缓存,最后是L3级调用(此时命中率最低)。因此,如何提高CPU的缓存命中率非常重要。

提高缓存命中率

为了提高缓存命中率,可以考虑以下几种方法:

  1. 数据局部性:尽量让数据使用集中在一小块内存区域内。
  2. 批量处理:一次处理尽可能多的数据以减少缓存的更新频率。
  3. 避免跨行访问:尽量避免数据结构导致跨行访问。

CPU对于不同运算的运算速度

不同的运算在CPU上的速度是不同的:

  1. 逻辑运算(如AND, OR, NOT, XOR):这些运算由专用电路实现,速度最快。
  2. 比较运算:使用专门的数字比较器,速度较快。
  3. 赋值运算:由于处理器频繁调用,也被高度优化。
  4. 算术运算
    • 加(+)、减(-)、移位操作(<<, >>):速度较快,接近逻辑运算速度。
    • 乘法(*):相对较慢。
    • 除法(/):最慢。
  5. 浮点运算:速度比整数运算慢得多。

CPU流水线

在大多数CPU中,命令的执行依赖于CPU流水线(Pipeline)。下图展示了一个4级流水线,缓存行(Cache Line,一般是L1,一级缓存)上存放等待执行的指令:

四级流水线

  • Clock 1:取出绿色指令放入流水线。
  • Clock 2:取出紫色指令,解码绿色指令。
  • Clock 3:取出蓝色指令,解码紫色指令,执行绿色指令。
  • Clock 4:取出红色指令,解码蓝色指令,执行紫色指令,回写绿色指令。
  • Clock 5:流水线空出一级,继续执行类似的流程。

CPU会尝试预测接下来的操作并将其置入流水线中。如果操作非线性,且包含频繁的逻辑判断,可能会中断流水线,使所有操作失效,从而降低处理速度。

利用GPU和NPU进行加速

GPU(图形处理单元)擅长处理大量简单的并行任务,适合图像处理等操作。

NPU(神经网络处理器)则是为加速深度学习算法而构建的,可以在AI工作负载中提供比CPU和GPU更高的性能。

代码处优化

优化代码的方法包括:

  1. 减少循环开销:精简循环体,减少不必要的操作。
  2. 减少函数调用:使用内联函数(inline)减少函数调用开销。
  3. 避免不必要的内存分配:尽量减少动态内存分配,使用栈内存或预分配内存。

编译时优化

修改编译时优化级别也能提升性能:

  1. -O0:调试版本,生成的汇编代码与实际代码更好对应,附加调试信息。
  2. -O2:发布版本,启用内联、循环展开、指令顺序优化、常量替换等技术优化代码性能。
  3. -O3:激进优化,过度循环展开、内联等,可能导致可执行文件变大,甚至栈溢出。

对于ARM内核,使用armcc编译器通常比gcc有更好的性能优化。

性能优化方法

基于上述性能优化原理,可以采用以下优化方法:

1. 结合代码处性能优化和CPU三级缓存中提高命中率的方法

以矩阵计算为例,常见的边界问题会用到判断(如if),但if判断是CPU流水线的敌人,会中断CPU的分支预测,拖慢处理速度。以下是一个优化示例:

原始代码

#include <stdio.h>#define ROWS 10
#define COLS 10void matrix_calc(int matrix[ROWS][COLS]) {for (int i = 0; i < COLS; ++i) {for (int j = 0; j < ROWS; ++j) {if (i == 0 || i == ROWS - 1 || j == 0 || j == COLS - 1) {matrix[i][j]--;} else {matrix[i][j]++;}}}
}

优化后代码

#include <stdio.h>
#include <immintrin.h>#define ROWS 16
#define COLS 16void matrix_calc_simd(int matrix[ROWS][COLS]) {__m128i mask = _mm_set1_epi32(0x0000FFFF); // 用于判断是否为边界__m128i inc = _mm_set1_epi32(1);__m128i dec = _mm_set1_epi32(-1);for (int i = 0; i < ROWS; i += 4) {for (int j = 0; j < COLS; j += 4) {__m128i data = _mm_loadu_si128((__m128i*)&matrix[i][j]);__m128i row_mask = _mm_set1_epi32(i == 0 || i == ROWS - 1 ? 0xFFFFFFFF : 0);__m128i col_mask = _mm_set1_epi32(j == 0 || j == COLS - 1 ? 0xFFFFFFFF : 0);__m128i boundary_mask = _mm_or_si128(row_mask, col_mask);__m128i result = _mm_blendv_epi8(data, _mm_add_epi32(data, inc), boundary_mask);result = _mm_blendv_epi8(result, _mm_sub_epi32(data, dec), boundary_mask);_mm_storeu_si128((__m128i*)&matrix[i][j], result);}}
}

在优化后的代码中,利用了SIMD指令集一次处理多个数据,提高了计算效率。SIMD指令集(单指令多数据)是性能优化的一个好办法。更多信息可以参考相关文章。

如果去掉SIMD操作后,代码如下:

#include <stdio.h>#define ROWS 10
#define COLS 10void matrix_calc(int matrix[ROWS][COLS]) {for (int i = 0; i < ROWS; i++) {matrix[i][0]--;matrix[i][COLS-1]--;matrix[0][i]--;matrix[ROWS-1][i]--;for (int j = 1; j < COLS - 1; j += 2) {matrix[i][j]++;matrix[i][j+1]++;}}
}

该代码的优化在于:

  • 首先,将边界值的计算放在循环外面处理,这样就不必在每次迭代中检查是否在边界上,减少了判断次数。
  • 然后,对于非边界上的元素,采用批量增加的方式,每次处理两个数据,加快了计算速度。

2. 滑动窗口

有聪明的小伙伴就发现了,这个词好像在我们计算机网络这门课听说过,但是听的迷迷糊糊的,我们可以理解为一个一直移动的框,举个例子,我们如果要计算一个很长的无序数组的某n个数和,比如说一个数组a内容为{1,7,3,2,4,5,8,0,2,9,1,3,5,7,8,1......}
而我们需要计算每5个数的和。
正常而言,我们需要计算第一个数就是1+7+3+2+4,第二个数就是7+3+2+4+5,第三个数就是3+2+4+5+8…大家发现了什么,其实每次计算哦独有一部分是重复的!这一部分就是滑动窗口。
于是乎我们可以先做一次计算,比如第一个数是1+7+3+2+4 = 17,那么第二个数是多少呢?就是第一个数-a[0]+a[5],也就是17-1+5 =21,第三个数是第二个数-a[1]+a[6]=22,我们会惊奇的发现,通过这种方法我们省下了3个运算!
给个例子,比如在计算无重复字符的最长子串问题中,原代码如下
问题描述: 给定一个字符串 s ,请你找出其中不含有重复字符的 最长子串 的长度。

#include <iostream>
#include <unordered_set>
#include <string>using namespace std;int lengthOfLongestSubstring(string s) {int n = s.size();unordered_set<char> set;int ans = 0, i = 0, j = 0;while (j < n) {if (set.count(s[j]) == 0) {set.insert(s[j++]);ans = max(ans, j - i);} else {set.erase(s[i++]);}}return ans;
}int main() {string s = "abcabcbb";cout << lengthOfLongestSubstring(s) << endl;  // 输出 3return 0;
}

我们完全可以利用滑动窗口优化,每次滑动窗口就是最长子串

#include <iostream>
#include <unordered_map>
#include <vector>
#include <string>using namespace std;vector<int> findAnagrams(string s, string p) {vector<int> res;if (s.size() < p.size()) return res;unordered_map<char, int> need, window;for (char c : p) need[c]++;int left = 0, right = 0, valid = 0;while (right < s.size()) {char c = s[right];right++;// 窗口内字符数量变化if (need.count(c)) {window[c]++;if (window[c] == need[c]) valid++;}// 判断窗口是否有效while (right - left == p.size()) {if (valid == need.size()) res.push_back(left);// 左指针向右移动char d = s[left];left++;if (need.count(d)) {if (window[d] == need[d]) valid--;window[d]--;}}}return res;
}

3. 映射表

这也是一种常见的优化手段,多用于图像处理,比如,我想让RGB图像的绿色值都加1,封顶是绿色为256
传统方法下操作如下

void adjustBrightness(uint8_t* imageData, int width, int height, int brightness) {for (int y = 0; y < height; ++y) {for (int x = 0; x < width; ++x) {for (int c = 0; c < 3; ++c) { // RGB 三个通道int pixel = imageData[(y * width + x) * 3 + c];pixel = std::min(std::max(pixel + brightness, 0), 255);imageData[(y * width + x) * 3 + c] = pixel;}}}
}

可以看到,再循环中每次循环都进行了比较和运算操作,虽然单次的运算操作速度很快,但是架不住数量多啊!
这时候我们可以将已知值进行与计算(计算256次)

vector<uint8_t> createGreenLUT() {vector<uint8_t> lut(256);for (int i = 0; i < 256; ++i) {lut[i] = min(i + 1, 255);}return lut;
}// 假设 imageData 是一个 uint8_t 的数组,存储了图像的像素数据
void applyGreenLUT(uint8_t* imageData, int width, int height, vector<uint8_t>& lut) {for (int y = 0; y < height; ++y) {for (int x = 0; x < width; ++x) {int index = (y * width + x) * 3 + 1; // 假设 RGB 格式,绿色通道在第二个位置imageData[index] = lut[imageData[index]];}}
}

此时我们就大大降低了计算数量!

4. 量化数据

前面提到,浮点数运算会大大拖慢运算速度,因此我们可以考虑对浮点数据进行量化,将其量化为更小的数据类型。
比如我们已知浮点数的范围为0.1-0.8,那么我们就可以将其量化为8位无符号整数,取值范围为0-255
代码如下

#include <iostream>int quantize(float value) {// 假设浮点数范围为0.1-0.8,量化为8位无符号整数float min_val = 0.1;float max_val = 0.8;int quant_level = 255;int quantized_value = round((value - min_val) / (max_val - min_val) * quant_level);return quantized_value;
}int main() {float f = 0.5;int q = quantize(f);std::cout << "Quantized value: " << q << std::endl;return 0;
}

此时对循环读取等操作都变得更加友好了,这种方法被广泛用于诸如ai模型优化等方面,可以将一个浮点数40mb的ai模型给优化成10mb!但是在使用时需要将其反量化为40mb的大小,这就涉及一个点——精度损失。

float dequantize(int quantized_value, float min_val, float max_val, int quant_level) {// 反量化公式:// dequantized_value = quantized_value * (max_val - min_val) / quant_level + min_valreturn quantized_value * (max_val - min_val) / quant_level + min_val;
}

我们将其中的数字进行反量化后发现原本的0.1-0.8经过这一过程后变为了

Original: 0.1, Quantized: 0, Dequantized: 0.1, Error: 0
Original: 0.2, Quantized: 36, Dequantized: 0.198824, Error: 0.00117648
Original: 0.3, Quantized: 73, Dequantized: 0.300392, Error: 0.000392139
Original: 0.4, Quantized: 109, Dequantized: 0.399216, Error: 0.000784338
Original: 0.5, Quantized: 146, Dequantized: 0.500784, Error: 0.000784338
Original: 0.6, Quantized: 182, Dequantized: 0.599608, Error: 0.000392139
Original: 0.7, Quantized: 219, Dequantized: 0.701177, Error: 0.00117648

可以看到或多或少都出现了误差,但是误差范围都在小数点后三位以后,对精度要求不是很高的情况下可以使用该方法。

5. 其他优化策略

可以多用内敛函数inline减少函数调用,多用引用少用指针提高内存利用率,在做运算时用乘法移位代替除法,用加法移位代替乘法等等

6. 最后的手段:多线程

现代计算机的处理器大都支持多线程操作,可以在同一时间处理多个任务,这也能大大提高处理效率。

7. 硬件层面的,善用GPU和NPU加速

利用OpenGL等硬件加速手段来辅助加快运行速度

8. 编译器编译时参数优化

优化选项

-O1, -O2, -O3

GCC编译器的-O1, -O2, -O3优化选项可以自动进行一些优化操作,例如内联函数、循环展开、指令调度等。你可以根据实际需求选择合适的优化级别。一般来说,-O3优化选项提供最高级别的优化,但同时可能增加代码的编译时间和执行文件的体积。

-flto

链接时优化(Link Time Optimization, -flto)可以在链接阶段进一步优化代码,特别是当多个源文件链接在一起时。这个选项可以在编译时使用-flto参数,然后在链接时也需要使用这个选项。例如:

g++ -O3 -flto -o myprogram main.cpp module1.cpp module2.cpp

-march=native

-march=native选项会让编译器针对当前机器的硬件架构生成优化的代码。这个选项可以启用处理器支持的所有优化指令,例如SIMD指令集。使用示例:

g++ -O3 -march=native -o myprogram main.cpp

-ffast-math

-ffast-math选项启用对浮点运算的激进优化。这个选项会让编译器忽略一些浮点运算的标准规则,以提高代码执行速度。但需要注意,使用这个选项可能导致结果精度下降或不符合IEEE 754标准。

结论

性能优化是一个复杂的过程,需要综合考虑硬件架构、软件算法和编译器优化。不同的应用场景需要不同的优化策略。通过结合数据局部性、批量处理、编译器优化选项以及使用SIMD指令等方法,可以大大提高程序的运行效率。这次只是浅探一下,更深入的内容还需要再进行探索。

相关文章:

浅谈性能优化(基于C++)

本文主要针对C的性能优化方法展开讨论。虽然这些方法也适用于一些其他语言&#xff0c;但由于C经常用于底层操作&#xff0c;提供了更多的优化空间&#xff1b;相比之下&#xff0c;诸如Python、Kotlin等高级语言由于其抽象程度更高&#xff0c;优化空间较少。 性能优化原理 …...

Python 报错:ModuleNotFoundError: No module named ‘Crypto‘

Crypto报错解决方案 Python 报错&#xff1a;ModuleNotFoundError: No module named Crypto前言问题解决方案 Python 报错&#xff1a;ModuleNotFoundError: No module named ‘Crypto’ 前言 Crypto是一个加密模块&#xff0c;它包含了多种加密算法&#xff0c;如 AES、DES、…...

UE(User Equipment) 和 UA(User Agent)

UE&#xff08;User Equipment&#xff09; UE 是 用户设备&#xff0c;这是一个泛指的术语&#xff0c;涵盖了所有类型的终端设备&#xff0c;例如手机、电脑、平板、智能手表等。这些设备可以连接到网络并进行通信。UE可以包含多种功能&#xff0c;包括对话&#xff08;语音…...

视觉SLAM ch3补充——在Linux中配置VScode以及CMakeLists如何添加Eigen库

ch3中的所有代码&#xff0c;除了在kdevelop中运行&#xff0c;还可以在VScode中运行。下面将简要演示配置过程&#xff0c;代码不再做解答&#xff0c;详细内容在下面的文章中。&#xff08;这一节中的pangolin由于安装过程中会出现很多问题&#xff0c;且后续内容用不到该平台…...

开关电源:优化电子产品中的能源使用

电压转换器是许多技术系统的支柱。根据应用的不同&#xff0c;所需的电源单元由变压器、整流器 AC/DC 转换器实现。当高性能开关电源尚未上市时&#xff0c;几乎只使用 50 Hz 变压器解决方案。 电源注意事项 电能几乎完全以三相电流的形式提供&#xff0c;系统电压为 10 ...3…...

Java语言程序设计——篇十三(2)

&#x1f33f;&#x1f33f;&#x1f33f;跟随博主脚步&#xff0c;从这里开始→博主主页&#x1f33f;&#x1f33f;&#x1f33f; 欢迎大家&#xff1a;这里是我的学习笔记、总结知识的地方&#xff0c;喜欢的话请三连&#xff0c;有问题可以私信&#x1f333;&#x1f333;&…...

python结合csv和正则实现条件筛选数据统计分数

前景提要&#xff1a; 有一个项目的数值和员工统计的对不上&#xff0c;如果一页一页翻找自己手动算&#xff0c;一个就有16、7页&#xff0c; 功能实现 1、创建csv文件 需要将每一个模块的所有数据头提取出来&#xff0c;这个可以直接用爬虫或者手工复制出来&#xff0c;因…...

Ubuntu系统的基础操作和使用|Linux|安装|网络连接|更新与升级系统|系统维护|故障排除|监控|桌面环境|虚拟机|快捷键

目录 1. Ubuntu系统的安装与初步设置 1.1 下载与安装Ubuntu 1.2 创建用户和设置密码 1.3 配置网络连接 1.4 更新与升级系统 2. Ubuntu的基本操作 2.1 文件与目录管理 2.2 系统进程管理 2.3 软件安装与管理 2.4 权限与用户管理 3. 系统维护与故障排除 3.1 系统日志查…...

day 38

2824.统计和小于目标的下标对数目 int countPairs(int* nums, int numsSize, int target){int x0;for(int i0;i<numsSize;i){for(int ji1;j<numsSize;j){if(nums[i]nums[j]<target){x;}}}return x; }2951.找出峰值 int* findPeaks(int* mountain, int mountainSize,…...

352532

c语言中的小小白-CSDN博客c语言中的小小白关注算法,c,c语言,贪心算法,链表,mysql,动态规划,后端,线性回归,数据结构,排序算法领域.https://blog.csdn.net/bhbcdxb123?spm1001.2014.3001.5343 给大家分享一句我很喜欢我话&#xff1a; 知不足而奋进&#xff0c;望远山而前行&am…...

Day.38 | 1143.最长公共子序列 1035.不相交的线 53.最大子序和 392.判断子序列

1143.最长公共子序列 要点&#xff1a;dp[i][j] dp[i - 1][j - 1] 1; dp[i][j] max(dp[i - 1][j], dp[i][j - 1]); class Solution { public:int longestCommonSubsequence(string text1, string text2) {vector<vector<int>> dp(text1.size() 1, vector<…...

pytorch 3 计算图

计算图结构 分析&#xff1a; 起始节点 ab 5 - 3ac 2b 3d 5b 6e 7c d^2f 2e最终输出 g 3f - o&#xff08;其中 o 是另一个输入&#xff09; 前向传播 前向传播按照上述顺序计算每个节点的值。 反向传播过程 反向传播的目标是计算损失函数&#xff08;这里假设为…...

一文吃透:暗水印是什么?企业防泄密可以加暗水印吗?

设计部主管&#xff1a;昨天下班的时候我在办公室捡到一张文件&#xff0c;上面可是我们最新产品的设计草稿&#xff0c;严禁打印的&#xff0c;到底是谁干的&#xff1f; 员工&#xff1a;办公室没有监控&#xff0c;似乎很难查到哦。 网络部经理&#xff1a;不用担心&#…...

Ajax-02.Axios

Axios入门 1.引入Axios的js文件 <script src"js/axios-0.18.0.js"></script> Axios 请求方式别名: axios.get(url[,config]) axios.delete(url[,config]) axios.post(url[,data[,config]]) axios.put(url[,data[,config]]) 发送GET/POST请求 axios.get…...

NodeJS的核心配置文件package.json和package.lock.json详解

package.json 文件 package.json 文件是 Node.js 项目的核心配置文件&#xff0c;它包含了项目的基本信息、依赖关系以及一些脚本命令等。以下是 package.json 文件的主要字段说明&#xff1a; name&#xff1a;项目的名称&#xff0c;必须是小写&#xff0c;可以包含字母、数…...

开源数据采集和跟踪系统:助力营销决策的关键工具

开源数据采集和跟踪系统&#xff1a;助力营销决策的关键工具 在现代营销中&#xff0c;数据是最重要的资产之一。了解用户行为、优化广告效果、提升转化率&#xff0c;这一切都离不开精准的数据分析。为了帮助商家更好地掌握这些数据&#xff0c;市场上出现了许多开源的数据采…...

Luminar Neo for Mac/Win:创新AI图像编辑软件的强大功能

Luminar Neo&#xff0c;这款由Skylum公司倾力打造的图像编辑软件&#xff0c;为Mac和Windows用户带来了前所未有的创作体验与编辑便利。作为一款融合了先进AI技术的图像处理工具&#xff0c;Luminar Neo以其独特的功能和高效的操作流程&#xff0c;成为了摄影师、设计师及摄影…...

Mac平台M1PRO芯片MiniCPM-V-2.6网页部署跑通

Mac平台M1PRO芯片MiniCPM-V-2.6网页部署跑通 契机 ⚙ 2.6的小钢炮可以输入视频了&#xff0c;我必须拉到本地跑跑。主要解决2.6版本默认绑定flash_atten问题&#xff0c;pip install flash_attn也无法安装&#xff0c;因为强制依赖cuda。主要解决的就是这个问题&#xff0c;还…...

MyBatis:Maven,Git,TortoiseGit,Gradle

1&#xff0c;Maven Maven是一个非常优秀的项目管理工具&#xff0c;采用一种“约定优于配置&#xff08;CoC&#xff09;”的策略来管理项目。使用Maven不仅可以把源代码构建成可发布的项目&#xff08;包括编译、打包、测试和分发&#xff09;&#xff0c;还可以生成报告、生…...

获取链表中间位置的两种方法方法

方法一&#xff1a; 我们可以计算链表节点的数量&#xff0c;然后遍历链表找到前半部分的尾节点。 方法二: 我们也可以使用快慢指针在一次遍历中找到&#xff1a;慢指针一次走一步&#xff0c;快指针一次走两步&#xff0c;快慢指针同时出发。当快指针移动到链表的末尾时&am…...

第二十天的学习(2024.8.8)Vue拓展

昨天的笔记中&#xff0c;我们进行的项目已经可以在网页上显示查询到数据库中的数据&#xff0c;今天的笔记中将会完成在网页上进行增删改查的操作 1.删除表中数据 现在网页上只能呈现出数据库中的数据&#xff0c;我们首先添加一个删除按钮&#xff0c;使其可以对数据库数据…...

微信小程序教程011:全局配置:Window

文章目录 1、window1.1、`window`-小程序窗口的组成部分1.2、了解 window 节点常用的配置项1.3、设置导航栏的标题1.4、设置导航栏的背景色1.5、设置导航栏的标题颜色1.6、全局开启下拉刷新功能1.7、设置下拉刷新时窗口的背景色1.8、设置下拉刷新时 loading 的样式1.9、设置上拉…...

Tomcat服务器和Web项目的部署

目录 一、概述和作用 二、安装 1.进入官网 2.Download下面选择想要下载的版本 3.点击Which version查看版本所需要的JRE版本 4.返回上一页下载和电脑和操作系统匹配的Tomcat 5. 安装完成后&#xff0c;点击bin目录下的startup.bat&#xff08;linux系统下就运行startup.sh&…...

PCIe学习笔记(22)

Transaction Ordering Transaction Ordering Rules 表2-40定义了PCI Express Transactions的排序要求。该表中定义的规则统一适用于PCI Express上所有类型的事务&#xff0c;包括内存、I/O、配置和消息。该表中定义的排序规则适用于单个流量类(TC)。不同TC标签的事务之间没有…...

Vue3 依赖注入Provide / Inject

在实际开发中&#xff0c;我们经常需要从父组件向子组件传递数据&#xff0c;一般情况下&#xff0c;我们使用 props。但有时候会遇到深度嵌套的组件&#xff0c;而深层的子组件只需要父组件的部分内容。在这种情况下&#xff0c;如果仍然将 prop 沿着组件链逐级传递下去&#…...

Python | Leetcode Python题解之第332题重新安排行程

题目&#xff1a; 题解&#xff1a; class Solution:def findItinerary(self, tickets: List[List[str]]) -> List[str]:def dfs(curr: str):while vec[curr]:tmp heapq.heappop(vec[curr])dfs(tmp)stack.append(curr)vec collections.defaultdict(list)for depart, arri…...

React状态管理:react-redux和redux-saga(适合由vue转到react的同学)

注意&#xff1a;本文不会把所有知识点都写一遍&#xff0c;并不适合纯新手阅读 首先Redux是一种状态管理方案&#xff0c;本身和react并没有什么联系&#xff0c;redux也可以结合其他框架来用。 react-redux是基于react的一种状态管理实现&#xff0c;他不像vuex那样直接内置在…...

刷题技巧:双指针法的核心思想总结+例题整合+力扣接雨水双指针c++实现

双指针法的核心思想是通过同时操作两个指针来遍历数据结构&#xff0c;通常是数组或链表&#xff0c;以达到优化算法性能的目的。具体来说&#xff0c;双指针法能够减少时间复杂度、空间复杂度&#xff0c;或者简化逻辑结构。以下是双指针法的几个核心思想&#xff1a; ps 下面…...

什么是前端微服务,有何优势

随着互联网技术的发展&#xff0c;传统的单体应用架构已经无法满足复杂业务场景的需求。微服务架构的兴起为后端应用的开发和部署提供了灵活性和可扩展性。与此同时&#xff0c;前端开发也经历了类似的演变&#xff0c;前端微服务作为一种新兴的架构模式应运而生。 一、前端微服…...

小论文写作——02:编故事

一篇论文&#xff0c;可以发水刊&#xff0c;也可以发顶刊顶会&#xff0c;这两者的区别就是一个故事编的好不好。 你的论文ABC&#xff0c;但不能之说有ABC。创新就是看你故事编的怎么样&#xff1f;创新是编出来的。 我们要说&#xff1a;我发现了问题&#xff0c;然后准备…...

南阳阿里巴巴网站推广/可以打广告的平台

1. 从json数组 返回一个数组。 let _Row responseObject.map((key)>{ return (key.id); }),//返回数组。[29, 28, 26, 2, 3] 2. 返回一个新 json数组 let _Row2 responseObject.map((key)>{ return ({id: key.id, name: key.value}); })...

古董交易网站怎么做/今日国内重大新闻

这几天照着home featured模块写了一个add ons的模块&#xff0c;需要挂到order-delivery.tpl中去&#xff0c;下面是 这个模块的使用和安装步骤&#xff0c;当然了模块还在完善中。 addons安装步骤&#xff1a;1, 在数据库表ps_hook中添加一条记录&#xff0c;也是就创建一个新…...

罗湖网站建设的公司哪家好/自己如何制作网页

算术运算符 对变量和数组进行算术运算。 算术运算符&#xff1a;&#xff0c;-&#xff0c;*&#xff0c;/&#xff0c;% &#xff1a;将连个或者多个数值相加 -&#xff1a;将两个数值相减 *&#xff1a;将两个数值相乘 /&#xff1a;将两个数值相除 %&#xff1a;取相除的余数…...

做学校的网站推广发展前景/九江seo

分期花呗 真有这么一个公司&#xff0c;坑人的短信 诈骗的最高境界就是&#xff1a;制造证据链。 证明对方是诈骗。得警惕千万别小看诈骗短信&#xff0c; 有些短信你不理&#xff0c;就是一埋下了一个邪恶的种子。收到 分期花呗 两条短信&#xff0c;第一条是注册成功&#xf…...

云南网站建设方法/外贸营销渠道

SpringCloud Function作为SpringCloud家族成员最早在2017年提出&#xff0c;项目主要负责人为Mark Fisher&#xff0c;目前已经来到了3.0版本。SpringCloud Function的出现旨在为快速发展的Serverless市场提供一个Spring的接入路径&#xff0c;使用SpringCloud Function进行无服…...

删掉cache wordpress/网站流量分析报告

通常我们只需要编写HTML&#xff0c;CSS&#xff0c;JavaScript屏幕上就会显示出漂亮的页面&#xff0c;但浏览器是如何使用我们的代码在屏幕上渲染像素的呢&#xff1f;浏览器将HTML&#xff0c;CSS&#xff0c;JavaScript转换为屏幕上所呈现的实际像素&#xff0c;这期间所经…...