《 C++ 修炼全景指南:六 》深入探索 C++ 标准库中的 stack 与 queue 容器适配器
1、引言
1.1、容器适配器的概念与应用
容器适配器(Container Adapters)是 C++ 标准库提供的一种特殊容器,它不是一种独立的容器,而是对其他标准容器的封装,用来实现特定的数据结构如栈(stack)和队列(queue)。通过容器适配器,开发者可以快速实现这些数据结构,而无需关心底层容器的具体实现。
适配器的核心功能是将已有的容器(如 vector、deque、list)通过封装,提供特定接口以实现新功能。例如,栈是后进先出(LIFO)的数据结构,而队列则是先进先出(FIFO)。适配器隐藏了底层容器的复杂性,提供了一套简化的接口,封装了底层容器的实现逻辑。因此,它们能够以更具语义化的方式对底层容器操作,使代码更加简洁和易于理解。
1.2、标准库中的 Stack 和 Queue 适配器概述
C++ 标准库中的 std::stack 和 std::queue 就是典型的容器适配器。stack 基于 deque、vector 或 list 实现,封装了其操作使之符合栈的语义,常用操作包括 push、pop、top。同样,queue 适配器也是对 deque、list 等容器的封装,提供了 enqueue、dequeue 和 front 等接口来实现队列的行为。
1.3、适配器设计的基本原则与目标
适配器的设计应遵循以下几个基本原则:
- 灵活性:支持多种底层容器,方便根据不同需求选择合适的数据结构。
- 效率:尽量减少不必要的拷贝和内存分配,提高整体性能。
- 安全性:保证异常情况下的数据一致性,避免出现内存泄漏等问题。
在设计自定义适配器时,我们的目标是实现与标准库类似的功能,同时可以根据实际需求进一步扩展。例如,在栈的实现中可以添加自定义的扩容机制或迭代器支持。
本文将深入探讨这两个容器适配器的工作原理,并展示如何使用这些适配器来高效管理数据。
2、适配器设计概述
2.1、适配器的模式
适配器模式是软件设计中的一种结构模式,它的主要作用是将某种类型的接口转化为客户端期望的接口,便于不同类型的对象之间进行协同工作。适配器模式的常见应用场景是在无法直接修改已有接口时,通过封装已有接口,提供新的、更合适的接口。
在 C++ 标准库中,stack 和 queue 容器就是经典的适配器模式的应用,它们将底层容器(如 deque 或 vector)的通用接口封装为栈或队列特定的数据处理接口。通过适配器的封装,只暴露出 push、pop、top 等操作,并隐藏底层的随机访问操作。
这种封装极大简化了代码的使用和维护,同时提高了代码的复用性。由于底层容器可以是多种不同的类型,我们可以根据不同的性能需求和使用场景选择最合适的容器。
2.2、常见底层容器的选择与对比
容器适配器不同于普通容器,如 vector 或 deque。它们不直接管理内存或元素,而是利用已有容器提供的接口来实现新的功能。例如,stack 依赖 deque 或 vector 的 push、pop、back 方法实现后进先出的操作逻辑。
在 C++ 标准库中,常见的底层容器包括 vector、deque 和 list。它们各自的特点如下:
vector:连续内存块,支持随机访问和动态扩展。对于栈来说,push和pop操作较快,但在某些情况下会因为动态扩展带来性能开销。deque:双端队列,支持在头尾两端插入和删除元素,适合实现栈和队列。它的扩展性更好,但相比vector稍微复杂。list:链表结构,适合频繁的插入和删除操作,但不支持随机访问,因此效率较低。
在实际设计中,选择合适的底层容器至关重要。对于频繁需要在两端进行插入和删除的队列,deque 通常是首选;而对于要求内存紧凑的场景,vector 则更加合适。
2.3、适配器设计的扩展性考虑
为了确保适配器具有良好的扩展性,我们需要考虑以下几点:
- 模板化设计:通过模板支持不同类型的数据,避免代码重复。
- 动态扩容:确保容器在超出初始容量时可以高效扩展,并保持较好的性能表现。
- 异常安全:确保在操作失败时,容器中的数据不会丢失或被破坏。
3、Stack 容器适配器的实现
3.1、Stack 容器的基本设计
Stack 容器适配器的基本设计思想是封装底层容器的插入和删除操作,使其符合栈的后进先出(LIFO)特性。常见操作包括 push 添加元素,pop 移除栈顶元素,top 获取栈顶元素。
我们可以通过以下代码实现一个支持模板的栈适配器:
#include <iostream>namespace Lenyiin
{template <class T, typename Container = std::deque<T>>class Stack{public:void push(const T& value){_container.push_back(value);}void pop(){_container.pop_back();}size_t size(){return _container.size();}bool empty(){return _container.empty();}T& top(){return _container.back();}private:Container _container;};
}
在这个实现中,Container 默认使用 deque,但可以通过模板参数指定其他容器,如 vector 或 list。栈的操作通过对底层容器的方法进行封装来实现。
3.2、模板支持与灵活底层容器
模板的使用使得 Stack 适配器可以存储任意类型的数据,并且底层容器类型也可以通过模板参数指定。这为不同场景下的优化提供了极大的灵活性。
例如,如果我们想要使用 vector 作为底层容器,可以在实例化时这样做:
Stack<int, std::vector<int>> myStack;
int main()
{// 用 vector 容器Stack<int, vector<int>> st1;st1.push(1);st1.push(2);st1.push(3);st1.push(4);st1.push(5);cout << "使用 vector \t容器: ";while (!st1.empty()){cout << st1.top() << " ";st1.pop();}cout << endl;// 用 list 容器Stack<int, list<int>> st2;st2.push(1);st2.push(2);st2.push(3);st2.push(4);st2.push(5);cout << "使用 list \t容器: ";while (!st2.empty()){cout << st2.top() << " ";st2.pop();}cout << endl;// 用 deque 容器cout << "使用 deque \t容器: ";Stack<int, deque<int>> st3;st3.push(1);st3.push(2);st3.push(3);st3.push(4);st3.push(5);while (!st3.empty()){cout << st3.top() << " ";st3.pop();}cout << endl;return 0;
}
3.3、栈的核心操作:push、pop、top
push:将新元素添加到栈顶。pop:移除栈顶元素。top:访问栈顶元素,但不修改栈的状态。
这些操作通过简单的接口与底层容器的相适配。让我们更深入地探讨这三种核心操作的实现细节,以及其与底层容器的关联。
3.3.1、push 操作
push 操作用于将元素压入栈顶。在适配器中,我们通过调用底层容器的 push_back 方法来实现该操作。栈的语义是后进先出(LIFO),因此每次添加新元素时,它应放在最后面。
代码示例:
void push(const T& value)
{_container.push_back(value);
}
在这里,_container.push_back(value) 将值 value 添加到底层容器的末尾。由于栈的语义与 deque 或 vector 的后端插入操作一致,因此这一操作的时间复杂度为 O(1)。
3.3.2、pop 操作
pop 操作用于从栈顶移除元素。在适配器中,它调用了底层容器的 pop_back 方法。
代码示例:
void pop()
{_container.pop_back();
}
该方法移除底层容器的最后一个元素。对于 deque 和 vector 而言,这一操作的时间复杂度为 O(1),非常高效。
3.3.3、top 操作
top 操作用于访问栈顶的元素,而不会修改栈的内容。为了获取栈顶元素,我们需要调用底层容器的 back() 方法。
代码示例:
T& top()
{return _container.back();
}
back() 方法返回底层容器的最后一个元素,时间复杂度为 O(1)。值得注意的是,这里返回的是元素的引用,因此可以直接修改栈顶的元素。
通过对 push、pop 和 top 的封装,我们完成了栈的核心功能,且这些操作都能高效运行在 O(1) 时间复杂度下。
3.4、栈的扩展性:动态扩容
对于栈的实现,底层容器常常需要动态扩容,尤其是当我们使用 vector 作为底层容器时。vector 的特性是其大小固定,但它会根据需求自动调整容量,通常是当前容量的两倍。
为了理解栈的扩容机制,我们可以对 vector 的容量变化进行追踪,并在 push 操作时观察容器的容量动态变化:
std::vector<int> vec;
vec.push_back(1);
std::cout << "Capacity: " << vec.capacity() << std::endl;
vec.push_back(2);
std::cout << "Capacity: " << vec.capacity() << std::endl;
这段代码将展示 vector 在每次插入新元素时如何自动扩容。栈容器的动态扩容是由底层 vector 控制的,开发者无需手动管理。
3.5、异常安全与异常处理
栈的设计中,异常安全是一个重要的考虑因素。对于可能抛出异常的操作,我们需要确保容器处于一致的状态。
假设我们在 push 时抛出异常,栈的状态应保持不变,底层容器的数据也不应被破坏。因此,我们需要遵循 C++ 的 RAII(资源获取即初始化)原则,确保在出现异常时正确释放资源。
void push(const T& value) {try {_container.push_back(value);} catch (const std::exception& e) {std::cerr << "Push failed: " << e.what() << std::endl;// 处理异常,确保栈状态不变}
}
这种处理方式能够确保在 push 操作失败时,栈依旧保持一致性,数据不丢失。
4、Queue 容器适配器的实现
4.1、Queue 容器的基本设计
队列(Queue)是一种先进先出(FIFO)的数据结构,意味着元素总是从队列的尾部插入,从队列的头部移出。标准库中的 queue 容器适配器就是对底层容器的封装,支持 enqueue 和 dequeue 等操作。
为了实现队列适配器,我们可以使用类似栈的方式,封装底层容器来实现 FIFO 的行为。核心操作包括 enqueue(入队)和 dequeue(出队)。
示例代码:
#include <iostream>
#include <deque>namespace Lenyiin
{template <class T, class Container = std::deque<T>>class Queue{public:void push(const T& value){_container.push_back(value);}void pop(){_container.pop_front();}size_t size(){return _container.size();}bool empty(){return _container.empty();}T& front(){return _container.front();}T& back(){return _container.back();}private:Container _container;};
}
4.2、支持多种底层容器
与 Stack 一样,我们可以为 Queue 适配器指定多种底层容器。deque 是默认的底层容器,因为它支持高效的两端插入和删除操作。如果需要,我们也可以选择 list 作为底层容器,它同样支持双端操作。
Queue<int, std::list<int>> myQueue;
使用 list 作为底层容器时,enqueue 和 dequeue 的操作将分别映射到 push_back 和 pop_front。虽然链表的性能在某些场景下不如 deque,但它在大量的插入和删除操作中表现良好。
int main()
{// 1. 不能使用 vector,因为 vector 没有提供 pop_front// Queue<int, vector<int>> q1;// q1.push(1);// q1.push(2);// q1.push(3);// q1.push(4);// q1.push(5);// while (!q1.empty())//{// cout << q1.front() << " ";// q1.pop();// }// cout << endl;// 2. 使用 list 容器Queue<int, list<int>> q2;q2.push(1);q2.push(2);q2.push(3);q2.push(4);q2.push(5);cout << "使用 list \t容器: ";while (!q2.empty()){cout << q2.front() << " ";q2.pop();}cout << endl;// 3. 使用 deque 容器Queue<int, deque<int>> q3;q3.push(1);q3.push(2);q3.push(3);q3.push(4);q3.push(5);cout << "使用 deque \t容器: ";while (!q3.empty()){cout << q3.front() << " ";q3.pop();}cout << endl;return 0;
}
4.3、队列的核心操作:push、pop、front
与栈类似,队列的核心操作也需要封装底层容器的具体方法:
push:将元素添加到队列尾部,调用push_back。pop:从队列头部移除元素,调用pop_front。front:访问队列头部元素,调用front。
这些操作都能保持 O(1) 的时间复杂度,确保队列在大量元素操作时的性能。
4.4、异常处理与扩展性分析
与栈适配器类似,队列适配器同样需要处理异常情况。在实现 push 和 pop 操作时,我们必须确保容器在出现异常时仍保持一致。
例如,以下代码展示了如何处理 push 操作的异常:
void push(const T& value) {try {_container.push_back(value);} catch (const std::exception& e) {std::cerr << "Enqueue failed: " << e.what() << std::endl;// 异常处理}
}
通过这种方式,我们可以确保队列在任何情况下都保持一致性,并避免数据丢失。
5、容器适配器的扩展与高级特性
5.1 模板元编程与适配器优化
为了提升适配器的灵活性,我们可以使用 C++ 中的模板元编程技术,进一步优化适配器的设计。模板元编程可以用于在编译时选择最合适的底层容器,甚至允许不同类型的数据结构共享相同的适配器框架。
例如,我们可以为 Stack 和 Queue 实现一个通用的适配器基类:
template <typename T, template <typename, typename> class Container>
class Adapter {
protected:Container<T, std::allocator<T>> _container;public:size_t size() const {return _container.size();}bool empty() const {return _container.empty();}
};
这样,Stack 和 Queue 可以继承自 Adapter 基类,并在其基础上扩展各自的特性。
5.2、迭代器支持的可能性探讨
虽然 stack 和 queue 的适配器在标准库中并不支持迭代器,但在某些特殊场景中,允许对栈或队列进行迭代访问可能是有用的。我们可以通过暴露底层容器的迭代器来实现这一功能。
代码示例:
auto begin() { return container.begin(); }
auto end() { return container.end(); }
通过这种方式,用户可以像遍历普通容器那样遍历栈或队列中的元素。然而,这种做法可能会破坏栈和队列的语义,因此在实际应用中需谨慎使用。
5.3、异常安全与性能优化的策略
为了确保适配器的高性能和异常安全,我们可以引入一些常见的优化策略,如减少动态内存分配次数、使用移动语义减少拷贝开销等。
例如,push 操作可以通过移动语义来提高效率:
void push(T&& value) {_container.push_back(std::move(value));
}
使用 std::move 可以避免不必要的拷贝,从而提升性能。
6、性能分析与优化建议
不同底层容器的选择会直接影响栈和队列的性能。例如,deque 在频繁的插入与删除操作中表现优异,而 vector 更适合需要连续内存布局的场景。通过分析不同容器的特点,我们可以为特定的使用场景选择最合适的容器。
下面是一段测试代码:
// deque 和 vector 排序效率比较
void test_sort_deque_vs_vector()
{deque<int> d;vector<int> v;const int n = 1000000;srand(time(0));for (size_t i = 0; i < n; i++){int x = rand();d.push_back(x);v.push_back(x);}size_t begin1 = clock();sort(d.begin(), d.end());size_t end1 = clock();cout << "deque 排序时间为:" << end1 - begin1 << endl;size_t begin2 = clock();sort(v.begin(), v.end());size_t end2 = clock();cout << "vector 排序时间为:" << end2 - begin2 << endl;
}int main()
{test_sort_deque_vs_vector();return 0;
}
栈和队列适用于许多实际开发场景。例如,栈常用于递归和回溯问题,而队列则在广度优先搜索和任务调度中广泛应用。通过使用适配器容器,程序员能够更高效地管理数据,并且代码更具可读性。
7、总结
在本文中,我们详细探讨了如何在 C++ 中实现 stack 和 queue 容器适配器,并逐步深入到每一个实现细节。本文不仅为读者提供了完整的实现代码,还通过理论分析和实际代码示例,帮助初学者理解底层机制、性能优化以及异常处理等方面的设计。总结如下:
7.1、栈和队列的基本概念和实现
我们首先介绍了栈和队列的基本概念:栈是一种后进先出(LIFO)的数据结构,队列是一种先进先出(FIFO)的数据结构。通过封装底层容器,如 deque 或 vector,我们能够很容易地为它们提供与标准库类似的接口。我们实现了 push、pop、top 等栈的常用操作,以及 push、pop 和 front 等队列操作,确保它们都具有 O(1) 时间复杂度。
7.2、模板和底层容器选择的灵活性
通过模板编程,我们能够为 stack 和 queue 容器适配器提供极大的灵活性。用户可以在适配器定义中选择底层容器,例如 deque 或 list,以便在不同的应用场景下达到最佳性能表现。我们讨论了如何使用 deque 作为默认底层容器,因为它支持双端插入和删除操作,适合于栈和队列的需求。同时,模板的引入使得容器适配器更具扩展性,能够适应不同类型的数据结构。
7.3、动态扩容与性能优化
栈和队列的扩容机制在使用 vector 时尤为显著。vector 在插入操作时能够自动进行容量调整,通常按倍数扩容,从而在保证性能的同时提供了良好的内存管理机制。我们通过代码示例展示了如何观察和控制容器的动态扩容,并分析了其对程序性能的影响。此外,文章也讨论了通过减少不必要的内存分配和使用移动语义来进一步优化栈和队列的性能。
7.4、异常处理与安全性
异常处理是设计容器适配器时必须考虑的一个重要方面。在本文的实现中,所有可能抛出异常的操作都包含了适当的错误处理机制。特别是对于涉及到动态内存管理的操作,如 push ,我们通过捕获异常确保栈和队列在发生错误时仍然保持一致性,避免数据损坏或程序崩溃。
7.5、迭代器支持与扩展
尽管标准库的 stack 和 queue 容器适配器不直接支持迭代器,本文探讨了为这些容器添加迭代器的可能性。通过暴露底层容器的迭代器,用户可以遍历栈或队列中的元素,虽然这种行为可能会违反其数据结构的语义,但在特定情况下,这种扩展仍然具有一定的应用价值。
7.6、面向未来的优化与扩展
除了基础功能之外,本文还讨论了如何利用模板元编程进一步优化容器适配器,甚至为不同类型的容器提供通用的框架。我们也提到了更多高阶的优化策略,例如减少动态内存分配、利用移动语义优化 push 和 enqueue 的性能等。这些技术和思想为进一步的扩展和优化提供了基础。
通过本文的学习,读者不仅能理解栈和队列的基础知识及其实现,还能深入了解如何设计一个高效、异常安全的容器适配器。文章涵盖了从设计思路到代码实现,再到性能优化的各个环节,力求提供一个全面的、实践性强的实现方案。未来的改进方向包括进一步优化内存管理、支持更丰富的功能扩展,以及探讨其他底层容器的实现等。相信通过对本文的学习,读者能够轻松掌握容器适配器的实现技术,并将其应用于实际的工程项目中。
希望这篇博客对您有所帮助,也欢迎您在此基础上进行更多的探索和改进。如果您有任何问题或建议,欢迎在评论区留言,我们可以共同探讨和学习。更多知识分享可以访问我的个人博客网站 : https://blog.lenyiin.com/ 。
相关文章:
《 C++ 修炼全景指南:六 》深入探索 C++ 标准库中的 stack 与 queue 容器适配器
1、引言 1.1、容器适配器的概念与应用 容器适配器(Container Adapters)是 C 标准库提供的一种特殊容器,它不是一种独立的容器,而是对其他标准容器的封装,用来实现特定的数据结构如栈(stack)和…...
高级java每日一道面试题-2024年9月07日-JVM篇-说一下类加载的执行过程?
如果有遗漏,评论区告诉我进行补充 面试官: 说一下类加载的执行过程? 我回答: 在Java中,类的加载是一个重要的过程,它是由Java虚拟机(JVM)的类加载器系统负责的。类加载的过程不仅仅包括加载类的字节码到内存中,还包…...
笔试强训day09
添加逗号 import sysa list(input())[::-1] s "" cnt 0 for v in a:cnt 1s vif cnt%30:s , print(s.rstrip(,)[::-1])跳台阶 import sys import functools functools.cache def dfs(u):if u1 or u2:# print(f"u {u}")return ureturn dfs(u-1)dfs(…...
软件测试中的黑盒测试方法,包括其定义、目的及主要步骤。
黑盒测试(Black Box Testing)是一种软件测试方法,它侧重于软件的功能性需求验证,而不考虑程序内部结构或代码实现细节。这种方法是从最终用户的角度出发,检查系统是否按照规格说明书的要求工作。黑盒测试的主要目的是验…...
Shell脚本计算π的近似值
计算π的公式很多,本文使用“π的莱布尼茨公式”来计算π的近似值,对应的公式如下: http://upload.wikimedia.org/math/9/e/8/9e804b8a1a11e442be93fed1d52205a9.png 由此我们可以得到求解π的公式为:π=4*(1-(1/3)+(1/5)-(1/7)+(1/9)...) 下面是在linux下使用shell脚本命令…...
进程间通信之消息队列
作用 进程间通信 特点 1 、消息队列中的消息是有类型的。 类型 : 自定义的结构体 , 第一个成员必须是 long 型的 . 表示为该消息的类型 如 : typedef struct 结构体名称 { long type; // 消息的正文 char name[50]; char sex[10]; int age; ... } 别名 ; 2 、消息队…...
人生苦短我用Python 5-xlwings自动调整表格
人生苦短我用Python 5-xlwings自动调整表格 前言依赖主要类App类Books类Sheet 类 示例代码 前言 使用pandas库openpyxl库实现了csv与excel文件的互相转换,csv转excel后若数据超出了单元格的宽度,部分数据无法完整显示。需要手动打开Excel文件࿰…...
移动跨平台框架Flutter详细介绍和学习线路分享
Flutter是一款移动应用程序SDK,一份代码可以同时生成iOS和Android两个高性能、高保真的应用程序。 Flutter目标是使开发人员能够交付在不同平台上都感觉自然流畅的高性能应用程序。我们兼容滚动行为、排版、图标等方面的差异。 在全世界,Flutter正在被越…...
线性代数基础:向量、矩阵、张量及其在机器学习中的应用详解
线性代数基础:向量、矩阵、张量及其在机器学习中的应用详解 线性代数基础:向量、矩阵、张量及其在机器学习中的应用详解一、向量 (Vectors)1. 向量的定义2. 向量在机器学习中的应用3. 向量空间 二、矩阵 (Matrices)1. 矩阵的定义2. 矩阵在机器学习中的应…...
Dockerfile中的RUN、CMD、ENTRYPOINT指令区别
RUN在构建过程中在镜像中执行命令。CMD容器创建时的默认命令。(可以被覆盖)ENTRYPOINT容器创建时的主要命令。(不可被覆盖) 指令介绍 1.RUN 在构建过程中在镜像中执行命令,是在 docker build中执行 2.CMD 作用&am…...
css grid布局属性详解
Grid布局 前言一、认识Grid1.1容器和项目1.2行和列1.3单元格和网格线 二、容器属性2.1.grid-template-columns与grid-template-rows属性2.1.1 直接使用长度单位比如px2.1.2 使用百分比 %2.1.3 使用repeat函数2.1.4 按比例划分 fr 关键字2.1.5 自动填充 auto 关键字2.1.6 最大值…...
Tranformer分布式特辑
随着大模型的发展,如何进行分布式训练也成了每位开发者必备的技能。 1. 单机训练 CPU OffloadingGradient Checkpointing 正向传播时,不存储当前节点的中间结果,在反向传播时重新计算,从而起到降低显存占用的作用 Low Precision…...
【Moveit2官方教程】使用 MoveIt Task Constructor (MTC) 框架来定义和执行一个机器人任务
#include <rclcpp/rclcpp.hpp> // ROS 2 的核心库 #include <moveit/planning_scene/planning_scene.h> // MoveIt 规划场景相关的头文件 #include <moveit/planning_scene_interface/planning_scene_interface.h> // MoveIt 规划场景接口 #include <m…...
使用docker配置wordpress
docker的安装 配置docker yum源 sudo yum install -y yum-utils sudo yum-config-manager \ --add-repo \ http://mirrors.aliyun.com/docker-ce/linux/centos/docker-ce.repo下载最新版本docker sudo yum install -y docker-ce docker-ce-cli containerd.io docker-buildx-…...
JVM字节码
JVM字节码详解 引言 JVM(Java Virtual Machine,Java虚拟机)字节码是一种中间代码,主要用于Java平台上的程序在不同硬件平台上的移植。Java程序通过编译器将源代码编译成字节码,然后通过JVM解释或即时编译(…...
python访问mysql
要在 Python 中访问 MySQL 数据库,通常会使用 mysql-connector-python 或 pymysql 这两个库之一。以下是使用这两个库的基本示例: 使用 mysql-connector-python 安装库: pip install mysql-connector-python示例代码: import mysql.connector# 连接到 M…...
Java工具插件
一、springboot集成mqtt订阅 阿里云MQTT使用教程_复杂的世界311的博客-CSDN博客_阿里云mqtt 阿里云创建MQTT服务 先找到产品与服务,然后选择物联网平台,找到公共实例,创建一个产品。 创建产品 然后在左侧下拉栏找到设备管理,在设备管理下拉栏找到设备,然后添加设备。添加…...
Class3——Esp32|Thonny——网络连接主机-wifi连接(源代码带教程)
废话不多说——直接上配置源码和图片 一.电脑连接到wifi上(不能是5G) 二.网络调试助手信息设置绑定 1.获取电脑wifi信息 2.设置网络调试助手为一致,然后打开,主机地址是上面的192.168.2.149端口自己设置,UDP然后打开…...
特效【生日视频制作】小车汽车黄金色版悍马车身AE模板修改文字软件生成器教程特效素材【AE模板】
生日视频制作教程小车汽车黄金色版悍马车身AE模板修改文字特效广告生成神器素材祝福玩法AE模板工程 怎么如何做的【生日视频制作】小车汽车黄金色版悍马车身AE模板修改文字软件生成器教程特效素材【AE模板】 生日视频制作步骤: 下载AE模板 安装AE软件 把AE模板导入…...
如何利用Java进行快速的足球大小球及亚盘数据处理与分析
在当今信息爆炸的时代,大量的数据产生和积累,对于企业和个人来说,如何高效地处理和分析这些数据成为了一项重要的任务。Java作为一门强大的编程语言,提供了丰富的工具和库,可以帮助我们快速进行数据处理与分析。下面将…...
Day131 | 灵神 | 回溯算法 | 子集型 子集
Day131 | 灵神 | 回溯算法 | 子集型 子集 78.子集 78. 子集 - 力扣(LeetCode) 思路: 笔者写过很多次这道题了,不想写题解了,大家看灵神讲解吧 回溯算法套路①子集型回溯【基础算法精讲 14】_哔哩哔哩_bilibili 完…...
系统设计 --- MongoDB亿级数据查询优化策略
系统设计 --- MongoDB亿级数据查询分表策略 背景Solution --- 分表 背景 使用audit log实现Audi Trail功能 Audit Trail范围: 六个月数据量: 每秒5-7条audi log,共计7千万 – 1亿条数据需要实现全文检索按照时间倒序因为license问题,不能使用ELK只能使用…...
1.3 VSCode安装与环境配置
进入网址Visual Studio Code - Code Editing. Redefined下载.deb文件,然后打开终端,进入下载文件夹,键入命令 sudo dpkg -i code_1.100.3-1748872405_amd64.deb 在终端键入命令code即启动vscode 需要安装插件列表 1.Chinese简化 2.ros …...
【SQL学习笔记1】增删改查+多表连接全解析(内附SQL免费在线练习工具)
可以使用Sqliteviz这个网站免费编写sql语句,它能够让用户直接在浏览器内练习SQL的语法,不需要安装任何软件。 链接如下: sqliteviz 注意: 在转写SQL语法时,关键字之间有一个特定的顺序,这个顺序会影响到…...
华为OD机试-食堂供餐-二分法
import java.util.Arrays; import java.util.Scanner;public class DemoTest3 {public static void main(String[] args) {Scanner in new Scanner(System.in);// 注意 hasNext 和 hasNextLine 的区别while (in.hasNextLine()) { // 注意 while 处理多个 caseint a in.nextIn…...
Qt Http Server模块功能及架构
Qt Http Server 是 Qt 6.0 中引入的一个新模块,它提供了一个轻量级的 HTTP 服务器实现,主要用于构建基于 HTTP 的应用程序和服务。 功能介绍: 主要功能 HTTP服务器功能: 支持 HTTP/1.1 协议 简单的请求/响应处理模型 支持 GET…...
C++八股 —— 单例模式
文章目录 1. 基本概念2. 设计要点3. 实现方式4. 详解懒汉模式 1. 基本概念 线程安全(Thread Safety) 线程安全是指在多线程环境下,某个函数、类或代码片段能够被多个线程同时调用时,仍能保证数据的一致性和逻辑的正确性…...
Python ROS2【机器人中间件框架】 简介
销量过万TEEIS德国护膝夏天用薄款 优惠券冠生园 百花蜂蜜428g 挤压瓶纯蜂蜜巨奇严选 鞋子除臭剂360ml 多芬身体磨砂膏280g健70%-75%酒精消毒棉片湿巾1418cm 80片/袋3袋大包清洁食品用消毒 优惠券AIMORNY52朵红玫瑰永生香皂花同城配送非鲜花七夕情人节生日礼物送女友 热卖妙洁棉…...
Aspose.PDF 限制绕过方案:Java 字节码技术实战分享(仅供学习)
Aspose.PDF 限制绕过方案:Java 字节码技术实战分享(仅供学习) 一、Aspose.PDF 简介二、说明(⚠️仅供学习与研究使用)三、技术流程总览四、准备工作1. 下载 Jar 包2. Maven 项目依赖配置 五、字节码修改实现代码&#…...
Java + Spring Boot + Mybatis 实现批量插入
在 Java 中使用 Spring Boot 和 MyBatis 实现批量插入可以通过以下步骤完成。这里提供两种常用方法:使用 MyBatis 的 <foreach> 标签和批处理模式(ExecutorType.BATCH)。 方法一:使用 XML 的 <foreach> 标签ÿ…...
