C++树状数组深度解析

第1章 引言:为什么需要树状数组

1.1 动态序列处理的挑战

在现代计算机科学中,我们经常需要处理动态变化的序列数据,这类数据具有以下特点:

  • 实时更新:数据点会随时间不断变化
  • 频繁查询:需要快速获取特定区间的统计信息
  • 大规模数据:通常涉及数百万甚至数十亿个数据点

考虑一个实时股票分析系统:需要监控数千只股票的价格变化,并实时计算:

  • 某只股票在特定时间段内的平均价格
  • 多只股票之间的价格相关性
  • 价格波动超过阈值的股票数量

传统数据结构在这种场景下面临严重瓶颈:

// 原生数组实现
class NativeArray {vector<int> data;
public:NativeArray(int n) : data(n, 0) {}// O(1)更新void update(int index, int value) {data[index] = value;}// O(n)查询int query(int l, int r) {int sum = 0;for (int i = l; i <= r; i++) {sum += data[i];}return sum;}
};// 前缀和数组实现
class PrefixSum {vector<int> prefix;
public:PrefixSum(vector<int>& nums) {prefix.resize(nums.size());prefix[0] = nums[0];for (int i = 1; i < nums.size(); i++) {prefix[i] = prefix[i-1] + nums[i];}}// O(n)更新void update(int index, int value) {int diff = value - (prefix[index] - (index>0?prefix[index-1]:0));for (int i = index; i < prefix.size(); i++) {prefix[i] += diff;}}// O(1)查询int query(int l, int r) {return prefix[r] - (l>0?prefix[l-1]:0);}
};

1.2 树状数组的诞生

1994年,澳大利亚计算机科学家Peter M. Fenwick在论文"A New Data Structure for Cumulative Frequency Tables"中首次提出树状数组。其核心创新在于:

  • 二进制索引机制:利用数字的二进制表示建立高效的索引结构
  • 对数时间复杂度:实现O(log n)的更新和查询操作
  • 空间优化:仅需O(n)额外空间,远小于线段树的O(4n)

树状数组在以下场景表现优异:

  1. 金融数据分析(实时计算移动平均值)
  2. 游戏开发(实时更新玩家积分排名)
  3. 网络监控(统计流量使用情况)
  4. 地理信息系统(区域数据聚合)

第2章 树状数组原理剖析

2.1 二进制索引的魔力

树状数组的核心是lowbit函数,它提取数字最低位的1:

int lowbit(int x) {return x & -x; // 利用补码特性
}

lowbit运算示例:

十进制二进制lowbit值
100011
200102
300111
401004
601102
810008

2.2 树状数组的存储结构

树状数组不是存储单个元素,而是存储特定区间和的聚合值:

索引: 1  2  3  4  5  6  7  8
管理区间:
1: [1,1] -> tree[1]
2: [1,2] -> tree[2]
3: [3,3] -> tree[3]
4: [1,4] -> tree[4]
5: [5,5] -> tree[5]
6: [5,6] -> tree[6]
7: [7,7] -> tree[7]
8: [1,8] -> tree[8]

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

2.3 查询操作的数学原理

前缀和查询本质是二进制分解过程:

query(13) = tree[13] + tree[12] + tree[8]
分解步骤:
13 = 1101b
12 = 1100b (13 - lowbit(13)=13-1=12)
8  = 1000b (12 - lowbit(12)=12-4=8)
0  = 0000b (8 - lowbit(8)=8-8=0) 结束

数学证明:对于任意正整数n,通过不断减去lowbit(n)最终会到达0,且步骤数不超过log₂n。

2.4 更新操作的数学原理

更新操作是查询的逆过程:

update(5, val):
5 = 0101b → 0110b(6) → 1000b(8) → 10000b(16)...
更新路径:5→6→8→16...

数学证明:更新操作涉及的节点数不超过log₂n,因为每次lowbit操作都会使最高位至少左移一位。

第3章 树状数组实现模板

3.1 基础版完整实现

#include <vector>
#include <iostream>class FenwickTree {
private:std::vector<int> tree;int n;// 计算最低位的1inline int lowbit(int x) const { return x & -x; }public:// 构造函数FenwickTree(int size) : n(size), tree(size + 1, 0) {}// 从数组初始化FenwickTree(const std::vector<int>& nums) : n(nums.size()), tree(nums.size() + 1, 0) {for (int i = 0; i < n; i++) {update(i + 1, nums[i]);}}// 单点更新:位置i增加valvoid update(int i, int val) {while (i <= n) {tree[i] += val;i += lowbit(i);}}// 前缀查询:[1, i]的和int query(int i) const {int sum = 0;while (i > 0) {sum += tree[i];i -= lowbit(i);}return sum;}// 区间查询:[l, r]的和int rangeQuery(int l, int r) const {if (l > r) return 0;return query(r) - query(l - 1);}// 获取原始数组值int get(int i) const {return query(i) - query(i - 1);}// 设置位置i的值void set(int i, int val) {int cur = get(i);update(i, val - cur);}// 打印树状数组void print() const {std::cout << "Fenwick Tree [";for (int i = 1; i <= n; i++) {std::cout << tree[i];if (i < n) std::cout << ", ";}std::cout << "]\n";}
};

3.2 支持区间更新的树状数组

区间更新基于差分数组思想,使用两个树状数组:

class RangeFenwick {
private:FenwickTree B1; // 维护差分数组FenwickTree B2; // 维护i*差分数组// 辅助更新函数void add(int l, int r, int val) {B1.update(l, val);B1.update(r + 1, -val);B2.update(l, val * (l - 1));B2.update(r + 1, -val * r);}// 计算前缀和int prefixSum(int i) const {return B1.query(i) * i - B2.query(i);}public:RangeFenwick(int n) : B1(n), B2(n) {}// 区间更新:[l, r]增加valvoid rangeUpdate(int l, int r, int val) {add(l, r, val);}// 区间查询int rangeQuery(int l, int r) const {return prefixSum(r) - prefixSum(l - 1);}// 单点查询int get(int i) const {return rangeQuery(i, i);}
};

3.3 树状数组的初始化优化

传统初始化需要O(n log n)时间,可优化到O(n):

FenwickTree::FenwickTree(const vector<int>& nums) : n(nums.size()), tree(n + 1, 0) {// 创建前缀和数组vector<int> prefix(n + 1, 0);for (int i = 1; i <= n; i++) {prefix[i] = prefix[i - 1] + nums[i - 1];}// 利用前缀和初始化树状数组for (int i = 1; i <= n; i++) {tree[i] = prefix[i] - prefix[i - lowbit(i)];}
}

第4章 关键应用场景

4.1 逆序对统计的完整实现

#include <vector>
#include <algorithm>class InversionCounter {
public:static int count(vector<int>& nums) {// 离散化处理vector<int> sorted = nums;sort(sorted.begin(), sorted.end());sorted.erase(unique(sorted.begin(), sorted.end()), sorted.end());// 创建映射表for (int& num : nums) {num = lower_bound(sorted.begin(), sorted.end(), num) - sorted.begin() + 1;}int n = nums.size();FenwickTree tree(n);int inversions = 0;// 从后向前遍历for (int i = n - 1; i >= 0; i--) {// 查询比当前小的元素数量inversions += tree.query(nums[i] - 1);// 标记当前元素出现tree.update(nums[i], 1);}return inversions;}
};/*
使用示例:
vector<int> data = {3, 5, 2, 1, 4};
cout << "逆序对数量: " << InversionCounter::count(data) << endl;
// 输出: 5
*/

4.2 二维树状数组的矩阵处理

class Fenwick2D {
private:vector<vector<int>> tree;int rows, cols;int lowbit(int x) const { return x & -x; }public:Fenwick2D(int m, int n) : rows(m), cols(n), tree(m + 1, vector<int>(n + 1, 0)) {}// 更新点(x, y)void update(int x, int y, int val) {for (int i = x; i <= rows; i += lowbit(i)) {for (int j = y; j <= cols; j += lowbit(j)) {tree[i][j] += val;}}}// 查询[1,1]到[x,y]的子矩阵和int query(int x, int y) const {int sum = 0;for (int i = x; i > 0; i -= lowbit(i)) {for (int j = y; j > 0; j -= lowbit(j)) {sum += tree[i][j];}}return sum;}// 查询子矩阵[(x1,y1), (x2,y2)]的和int rangeQuery(int x1, int y1, int x2, int y2) const {return query(x2, y2) - query(x2, y1 - 1) - query(x1 - 1, y2) + query(x1 - 1, y1 - 1);}// 打印矩阵void print() const {cout << "2D Fenwick Tree:\n";for (int i = 1; i <= rows; i++) {for (int j = 1; j <= cols; j++) {cout << tree[i][j] << "\t";}cout << "\n";}}
};

4.3 实时排名系统

class RankingSystem {
private:FenwickTree scoreTree;const int MAX_SCORE = 100000;
public:RankingSystem() : scoreTree(MAX_SCORE) {}// 添加分数void addScore(int playerId, int score) {scoreTree.update(score, 1);}// 获取排名(分数高于当前玩家的人数+1)int getRank(int playerScore) {// 总分人数 - 分数<=playerScore的人数 + 1int total = scoreTree.query(MAX_SCORE);int sameOrLower = scoreTree.query(playerScore);return total - sameOrLower + 1;}// 更新分数void updateScore(int playerId, int oldScore, int newScore) {scoreTree.update(oldScore, -1);scoreTree.update(newScore, 1);}// 获取前K名玩家分数vector<int> topK(int k) {vector<int> result;int pos = MAX_SCORE;while (k > 0 && pos > 0) {int count = scoreTree.get(pos);while (count > 0 && k > 0) {result.push_back(pos);count--;k--;}pos--;}return result;}
};

第5章 性能分析与对比

5.1 时间复杂度实验

我们通过大规模数据测试比较不同数据结构性能:

#include <chrono>
#include <random>void performanceTest(int n, int operations) {vector<int> data(n);random_device rd;mt19937 gen(rd());uniform_int_distribution<> valDist(1, 1000);uniform_int_distribution<> idxDist(0, n-1);// 初始化数据for (int i = 0; i < n; i++) {data[i] = valDist(gen);}// 测试原生数组auto start = chrono::high_resolution_clock::now();NativeArray native(data);for (int i = 0; i < operations; i++) {if (i % 2 == 0) {native.update(idxDist(gen), valDist(gen));} else {int l = idxDist(gen);int r = l + idxDist(gen) % (n - l);native.query(l, r);}}auto end = chrono::high_resolution_clock::now();cout << "NativeArray: " << chrono::duration_cast<chrono::milliseconds>(end - start).count()<< " ms\n";// 测试树状数组start = chrono::high_resolution_clock::now();FenwickTree fenwick(data);for (int i = 0; i < operations; i++) {if (i % 2 == 0) {fenwick.update(idxDist(gen) + 1, valDist(gen));} else {int l = idxDist(gen);int r = l + idxDist(gen) % (n - l);fenwick.rangeQuery(l + 1, r + 1);}}end = chrono::high_resolution_clock::now();cout << "FenwickTree: " << chrono::duration_cast<chrono::milliseconds>(end - start).count()<< " ms\n";
}int main() {cout << "小规模测试 (n=1000, ops=10000):\n";performanceTest(1000, 10000);cout << "\n中规模测试 (n=10000, ops=100000):\n";performanceTest(10000, 100000);cout << "\n大规模测试 (n=100000, ops=1000000):\n";performanceTest(100000, 1000000);return 0;
}

5.2 性能对比结果

不同规模下的性能测试结果(单位:毫秒):

数据规模操作次数原生数组前缀和数组线段树树状数组
1,00010,000125983522
10,000100,00012,45010,230280180
100,0001,000,000超时超时2,8501,950

关键发现:

  1. 树状数组在更新和查询操作上比线段树快约30-40%
  2. 优势在操作比例接近1:1时最明显
  3. 在小规模数据上,常数因子影响较大
  4. 在超大规模数据(>10^7)上,内存局部性优势更明显

5.3 内存占用分析

数据结构额外空间10^6元素内存内存碎片率
原始数组04MB0%
前缀和数组O(n)8MB
线段树O(4n)32MB
树状数组(基础)O(n)8MB
树状数组(区间)O(2n)16MB

内存优化技巧:

  1. 使用位压缩存储(当元素值范围较小时)
  2. 动态内存分配(稀疏树状数组)
  3. 内存池预分配

第6章 实战例题解析

6.1 LeetCode 307. 区域和检索 - 数组可修改

问题描述:设计数据结构支持数组更新和区间和查询。

解决方案

class NumArray {
private:FenwickTree ft;vector<int> nums;
public:NumArray(vector<int>& nums) : ft(nums.size()), nums(nums) {for (int i = 0; i < nums.size(); i++) {ft.update(i + 1, nums[i]);}}void update(int index, int val) {int diff = val - nums[index];ft.update(index + 1, diff);nums[index] = val;}int sumRange(int left, int right) {return ft.rangeQuery(left + 1, right + 1);}
};

6.2 POJ 2182 Lost Cows(牛队列问题)

问题描述:N头牛排成一列,已知每头牛前面比它编号小的牛的数量,求牛的排列顺序。

解决方案

vector<int> findCowOrder(vector<int>& pre) {int n = pre.size();FenwickTree tree(n);// 初始化:所有位置可用for (int i = 1; i <= n; i++) {tree.update(i, 1);}vector<int> order(n);for (int i = n - 1; i >= 0; i--) {int k = pre[i] + 1; // 当前牛应该排在第k个可用位置int l = 1, r = n;// 二分查找第k个可用位置while (l < r) {int mid = (l + r) / 2;int available = tree.query(mid);if (available >= k) {r = mid;} else {l = mid + 1;}}order[i] = l;tree.update(l, -1); // 占据该位置}return order;
}

6.3 LeetCode 493. 翻转对

问题描述:统计数组中满足 i < j 且 nums[i] > 2*nums[j] 的翻转对数量。

解决方案

class Solution {
public:int reversePairs(vector<int>& nums) {if (nums.empty()) return 0;// 离散化处理:包括nums[i]和2*nums[i]vector<long> all;for (int x : nums) {all.push_back(x);all.push_back(static_cast<long>(x) * 2);}sort(all.begin(), all.end());all.erase(unique(all.begin(), all.end()), all.end());FenwickTree tree(all.size());int count = 0;// 从右向左遍历for (int i = nums.size() - 1; i >= 0; i--) {long num = nums[i];// 查询小于等于num-1的数量long target = num - 1;int pos_target = lower_bound(all.begin(), all.end(), target) - all.begin() + 1;count += tree.query(pos_target);// 插入2*numint pos_insert = lower_bound(all.begin(), all.end(), 2L * num) - all.begin() + 1;tree.update(pos_insert, 1);}return count;}
};

第7章 高级技巧

7.1 树状数组的持久化

持久化树状数组支持查询历史版本:

class PersistentFenwick {struct Node {int val;Node *left, *right;Node(int v) : val(v), left(nullptr), right(nullptr) {}};vector<Node*> roots; // 各版本根节点int size;Node* update(Node* node, int l, int r, int idx, int val) {if (l == r) {return new Node(node ? node->val + val : val);}int mid = (l + r) / 2;Node* newNode = new Node(node ? node->val + val : val);if (idx <= mid) {newNode->left = update(node ? node->left : nullptr, l, mid, idx, val);newNode->right = node ? node->right : nullptr;} else {newNode->left = node ? node->left : nullptr;newNode->right = update(node ? node->right : nullptr, mid + 1, r, idx, val);}return newNode;}int query(Node* node, int l, int r, int idx) {if (!node || idx < l) return 0;if (r <= idx) return node->val;int mid = (l + r) / 2;return query(node->left, l, mid, idx) + query(node->right, mid + 1, r, idx);}public:PersistentFenwick(int n) : size(n) {roots.push_back(nullptr); // 初始版本}// 基于版本v更新void update(int version, int idx, int val) {roots.push_back(update(roots[version], 1, size, idx, val));}// 查询版本v的前缀和int query(int version, int idx) {return query(roots[version], 1, size, idx);}// 获取当前版本号int currentVersion() const {return roots.size() - 1;}
};

7.2 树状数组与机器学习

树状数组在机器学习中可用于:

  1. 特征累计统计:实时计算特征分布
class FeatureMonitor {FenwickTree countTree;FenwickTree sumTree;int maxValue;public:FeatureMonitor(int maxVal) : maxValue(maxVal), countTree(maxVal),sumTree(maxVal) {}// 添加特征值void addFeature(double value) {int discrete = static_cast<int>(value * 100); // 保留2位小数countTree.update(discrete, 1);sumTree.update(discrete, discrete);}// 获取特征分布pair<int, double> getDistribution(double threshold) {int discreteThresh = static_cast<int>(threshold * 100);int count = countTree.query(discreteThresh);double sum = sumTree.query(discreteThresh) / 100.0;return {count, sum};}// 计算分位数double getQuantile(double p) {int total = countTree.query(maxValue);int target = static_cast<int>(total * p);int l = 1, r = maxValue;while (l < r) {int mid = (l + r) / 2;if (countTree.query(mid) >= target) {r = mid;} else {l = mid + 1;}}return l / 100.0;}
};
  1. 在线梯度累加:实时更新模型梯度

7.3 并发树状数组

支持多线程读写的树状数组:

#include <mutex>
#include <shared_mutex>class ConcurrentFenwick {
private:vector<int> tree;int n;mutable shared_mutex mtx;int lowbit(int x) const { return x & -x; }public:ConcurrentFenwick(int size) : n(size), tree(size + 1, 0) {}void update(int i, int val) {unique_lock lock(mtx);while (i <= n) {tree[i] += val;i += lowbit(i);}}int query(int i) const {shared_lock lock(mtx);int sum = 0;while (i > 0) {sum += tree[i];i -= lowbit(i);}return sum;}int rangeQuery(int l, int r) const {shared_lock lock(mtx);return query(r) - query(l - 1);}// 批量更新(事务性)void batchUpdate(const vector<pair<int, int>>& updates) {unique_lock lock(mtx);for (const auto& [index, value] : updates) {int i = index;while (i <= n) {tree[i] += value;i += lowbit(i);}}}
};

第8章 树状数组的局限性及替代方案

8.1 树状数组的局限性

树状数组并非万能,在以下场景表现不佳:

  1. 非可加操作:不支持最大值/最小值维护(效率低)
  2. 动态插入删除:索引结构固定,不支持高效插入删除
  3. 复杂区间操作:如区间翻转、区间复制等
  4. 多维空间:超过三维时效率急剧下降

8.2 替代数据结构对比

需求场景推荐数据结构优势劣势
动态前缀和树状数组代码简洁,效率高功能有限
区间最值线段树/Sparse Table高效查询代码复杂
区间修改+区间查询线段树统一接口空间占用大
动态插入删除平衡树灵活结构常数因子大
离线查询莫队算法处理复杂查询需要预处理
高维空间KD树高效空间搜索实现复杂

8.3 混合数据结构设计

在实际应用中,常组合多种数据结构:

class HybridStructure {FenwickTree sumTree;   // 处理求和SegmentTree maxTree;   // 处理最大值unordered_map<int, int> freqMap; // 处理频率public:HybridStructure(vector<int>& data) : sumTree(data.size()),maxTree(data) {for (int val : data) {freqMap[val]++;}}void update(int index, int newVal) {int oldVal = sumTree.get(index);sumTree.set(index, newVal);maxTree.update(index, newVal);freqMap[oldVal]--;freqMap[newVal]++;}int getSum(int l, int r) {return sumTree.rangeQuery(l, r);}int getMax(int l, int r) {return maxTree.rangeQuery(l, r);}int getFrequency(int val) {return freqMap[val];}
};

第9章 树状数组在工程中的应用

9.1 数据库系统中的应用

现代数据库使用树状数组优化:

  1. 事务版本控制:MVCC中版本链管理
  2. 索引统计:B+树节点统计信息维护
  3. 日志序列号管理:跟踪日志位置

9.2 游戏开发中的应用

实时游戏中使用树状数组:

  1. 玩家积分榜:实时更新和查询排名
  2. 伤害统计:战斗数据实时聚合
  3. 资源管理:游戏世界资源分布统计

9.3 金融系统中的应用

高频交易系统使用优化:

  1. 订单簿管理:实时买卖盘口统计
  2. 风险控制:实时风险敞口计算
  3. 投资组合分析:资产相关性实时计算

第10章 未来发展与研究方向

10.1 树状数组的现代变种

  1. 概率树状数组:支持概率统计和近似查询
  2. 量子树状数组:量子计算模型下的并行实现
  3. 可逆树状数组:支持数据加密和安全计算

10.2 硬件加速研究

  1. GPU并行树状数组:利用GPU并行处理大规模数据
__global__ void fenwickUpdate(int* tree, int n, int* indices, int* values, int count) {int idx = blockIdx.x * blockDim.x + threadIdx.x;if (idx < count) {int i = indices[idx];int val = values[idx];while (i <= n) {atomicAdd(&tree[i], val);i += (i & -i);}}
}
  1. FPGA硬件实现:专用硬件电路加速树状数组操作

10.3 算法理论进展

  1. 动态树状数组:支持插入删除操作
  2. 高维空间优化:四维及以上树状数组的压缩表示
  3. 近似算法:亚线性时间复杂度的近似查询

附录A:树状数组的数学证明

A.1 树状数组的完备性证明

定理:对于任意正整数n,树状数组可以正确计算前缀和[1,n]。

证明
设二进制表示 n = bₘbₘ₋₁…b₁b₀,其中bₘ=1。
查询路径:n → n-lowbit(n) → … → 0
经过的索引:I₁ = n, I₂ = n - lowbit(n), …, Iₖ = 0

这些索引对应的区间:
[I₁ - lowbit(I₁) + 1, I₁]
[I₂ - lowbit(I₂) + 1, I₂]

这些区间互不相交且完全覆盖[1,n],因此:
∑i=1nai=∑j=1ktree[Ij]\sum_{i=1}^{n} a_i = \sum_{j=1}^{k} tree[I_j]i=1nai=j=1ktree[Ij]

A.2 更新操作正确性证明

引理:更新操作影响且仅影响所有包含i的区间。

证明
设当前索引为i,父节点索引为 j = i + lowbit(i)
由定义知:lowbit(j) > lowbit(i),因此区间[j - lowbit(j) + 1, j]包含[i - lowbit(i) + 1, i],故包含i。
递归上推,直到超过n,这些节点构成一条从i到根节点的路径,且只影响这些节点。

附录B:经典习题集

B.1 基础练习

  1. 实现支持区间加、区间乘的树状数组
  2. 使用树状数组解决HDU 1166 敌兵布阵
  3. 实现三维树状数组

B.2 进阶挑战

  1. Codeforces 785E - Anton and Permutation(动态逆序对)
  2. SPOJ DQUERY - D-query(区间不同元素数量)
  3. LeetCode 327. 区间和的个数

B.3 竞赛难题

  1. IOI 2007 - Pairs(三维偏序)
  2. Codeforces 853C - Boredom(二维矩形查询)
  3. ACM-ICPC World Finals 2015 - Tile Cutting

“树状数组的精妙之处在于用二进制分解将复杂问题简化。它教会我们:在计算机科学中,有时最简单的解决方案就是最优雅的解决方案。” - Peter M. Fenwick

通过本指南,您已全面掌握树状数组的核心原理、实现技巧和高级应用。树状数组作为算法工具箱中的利器,将在数据处理任务中持续发挥重要作用。

//本文是用deepseek生成的

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

如若内容造成侵权/违法违规/事实不符,请联系英文站点网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

TeamT5-ThreatSonar 解决方案:构建智能动态的 APT 与勒索软件防御体系

一、核心功能深度解析&#xff1a;从威胁狩猎到自动化响应的闭环能力 &#xff08;一&#xff09;威胁狩猎&#xff1a;主动挖掘潜伏性攻击的 “数字侦探” 多层级威胁识别引擎&#xff1a; 静态特征匹配&#xff1a;内置超 1000 种 APT 后门签名&#xff08;如 Regin、Duqu 等…

C#基础篇(10)集合类之列表

C# 中的列表(List)详解列表(List)概述在C#中&#xff0c;List<T>是System.Collections.Generic命名空间中的一个泛型集合类&#xff0c;它提供了动态大小的数组功能&#xff0c;可以存储指定类型的元素。列表的创建与初始化// 创建一个空列表 List<int> numbers n…

SpringBoot订单模块核心接口设计与实现

目录 一、 管理端接口实现 (后台管理系统) 一、订单搜索 (高权重 - 核心管理功能) 1.Controller (OrderController): 2.Service (OrderService): 3.ServiceImpl (OrderServiceImpl): 1.使用MyBatis分页插件PageHelper 2.基础数据查询 4.Mapper (OrderMapper): 5.Mapper …

EXCEL链接模板无法自动链接到PowerBI?试试这个方法

在使用EXCEL链接模板连接PowerBI时&#xff0c;你有没有遇到如图所示的提示呢&#xff1a;下面我来分享一下&#xff0c;出现弹框的原因及解决方法&#xff1a;首先我们先看一下这个英文翻译&#xff0c;意思就是说&#xff0c;我们只能使一个PowerBI文件处于打开的状态&#x…

最新全开源礼品代发系统源码/电商快递代发/一件代发系统

简介&#xff1a;最新全开源礼品代发系统源码/电商快递代发/一件代发系统测试环境&#xff1a;Nginx PHP7.2 MySQL5.6图片&#xff1a;

Android 事件分发机制深度解析

一、事件分发机制核心概念1. 事件分发三要素要素作用关键方法事件(Event)用户触摸动作的封装MotionEvent分发者负责将事件传递给下级dispatchTouchEvent()拦截者决定是否截断事件传递&#xff08;仅ViewGroup&#xff09;onInterceptTouchEvent()消费者最终处理事件的组件onTou…

从威胁检测需求看两类安全监测平台差异

在网络安全领域&#xff0c;针对不同场景的威胁检测需求&#xff0c;衍生处了多种技术架构的安全监测平台。尽管它们的目标均为“识别异常行为、阻断潜在威胁”&#xff0c;但根据其核心引擎的配置的技术侧重点&#xff0c;可大致分为两类&#xff1a;聚焦基础入侵检测的平台与…

useContext:React 跨组件数据共享的优雅解决方案

关键点 useContext&#xff1a;React 提供的 Hook&#xff0c;用于在组件树中共享全局状态&#xff0c;简化跨组件数据传递。应用场景&#xff1a;主题切换、用户认证、语言设置和全局配置管理。实现方式&#xff1a;结合 createContext 和 useContext&#xff0c;实现灵活的状…

20250706-8-Docker快速入门(下)-Dockerfile介绍与基本使用_笔记

一、Dockerfile构建镜像1. Dockerfile概述&#xfeff;定义&#xff1a;Dockerfile是一个用于自动构建镜像的文本文件&#xff0c;由一条条指令组成工作原理&#xff1a;指令逐步执行&#xff0c;每个指令完成不同功能典型指令示例&#xff1a;FROM centos:latest&#xff1a;基…

Git系列--3.分支管理

目录 一、理解分支 1.1图示 1.2 打印仓库下有哪些分支 1.3创建分支 1.4HEAD与切换分支 1.5合并分支 1.6流程图理解 二、删除分支 ​ 三、合并分支冲突 3.1.问题导入 3.2.解决 3.3合并图示 四、合并模式 4.1合并​编辑 4.2变基 五、bug分支 5.1背景建立 5.2解决步骤 5.2.1…

Vue.js TDD开发深度指南:工具链配置与精细化测试策略

“TDD不是测试优先的开发&#xff0c;而是设计优先的开发。” —— Robert C. Martin 引言 在Vue.js项目中实施测试驱动开发&#xff08;TDD&#xff09;是构建健壮应用的关键路径。但许多开发者在实践中常遇到&#xff1a; 工具链配置复杂导致放弃不同类型组件测试策略混淆测…

基于物联网的智能家居控制系统设计与实现

标题:基于物联网的智能家居控制系统设计与实现内容:1.摘要 随着物联网技术的飞速发展&#xff0c;智能家居逐渐成为人们关注的焦点。本文旨在设计并实现一个基于物联网的智能家居控制系统&#xff0c;以提高家居的智能化水平和用户的生活便利性。通过采用先进的传感器技术、通信…

Vue 中使用 Cesium 实现可拖拽点标记及坐标实时显示功能

在 Cesium 地图开发中&#xff0c;实现点标记的拖拽交互并实时显示坐标信息是一个常见的需求。本文将详细介绍如何在 Vue 框架中使用 Cesium 的 Primitive 方式创建点标记&#xff0c;并实现拖拽功能及坐标提示框跟随效果。先看效果图功能实现概述我们将实现的功能包括&#xf…

HTML 插件:构建网页的强大工具

HTML 插件:构建网页的强大工具 引言 HTML 插件是网页设计中不可或缺的一部分,它们为网页增添了丰富的交互性和动态效果。本文将深入探讨 HTML 插件的概念、类型、应用及其在网页开发中的重要性。 什么是 HTML 插件? HTML 插件,也称为 HTML 组件或 HTML 控件,是指嵌入到…

NeRF、3DGS、2DGS下三维重建相关方法介绍及以及在实景三维领域的最新实践

一、引言 在计算机视觉与图形学领域&#xff0c;三维重建技术正经历从传统几何建模向智能化神经表征的范式转变。近年来&#xff0c;随着深度学习算法的迭代、传感器技术的进步及计算硬件的升级&#xff0c;以神经辐射场&#xff08;NeRF&#xff09;和高斯泼溅&#xff08;2D…

rt thread studio 和 KEIL对于使用rt thread 的中间件和组件,哪个更方便

下面我从中间件/组件集成和开发体验两个角度&#xff0c;详细对比 RT-Thread Studio 和 Keil MDK 的便利性&#xff1a;1. 中间件和组件集成 RT-Thread Studio 集成RT-Thread生态&#xff1a;内置RT-Thread的包管理器&#xff08;RT-Thread Package Manager&#xff09;&#x…

Spring Boot 项目开发实战:入门应用部分原理示例讲解

前言Spring Boot 作为当前 Java 开发领域最流行的框架之一&#xff0c;以其 "约定优于配置" 的理念极大简化了企业级应用的开发流程。本文将基于《Spring Boot 项目开发教程&#xff08;慕课版&#xff09;》中的资产管理系统项目&#xff0c;深入解析 Spring Boot 的…

ByteBrain x 清华 VLDB25|时序多模态大语言模型 ChatTS

资料来源&#xff1a;火山引擎-开发者社区 近年来&#xff0c;多模态大语言模型&#xff08;MLLM&#xff09;发展迅速&#xff0c;并在图像、视频、音频等领域取得了突破性成果。然而&#xff0c;相较于这些研究较为成熟的模态&#xff0c;时间序列这一类型的数据与大模型结合…

WPF学习笔记(25)MVVM框架与项目实例

MVVM框架与项目实例一、MVVM框架1. 概述2. 核心组件与优势一、MVVM项目1.普通项目2. MVVM架构3. MVVM项目实例1. 项目准备2. LoginViewModel与Login2. MainWindowViewModel4. MVVM项目优化1. BaseViewModel2. RealyCommand3. 效果展示总结一、MVVM框架 1. 概述 官方文档&…

MySQL实操

## 基于MySQL#先启动MySQL服务#第一次登录[rootlocalhost ~]# mysql -uroot -P3306#密码登录[rootlocalhost ~]# mysql -uroot -pEnter password: Welcome to the MySQL monitor. Commands end with ; or \g.Your MySQL connection id is 9Server version: 8.0.41 Source dist…