摘要
- C++11一些基本的数据结构
- C++常用函数调用
- 基本的使用方法(代码以及表格)
- 主要是为了方便索引查找,助力代码自动化(代码那么多,靠索引字典吧,我尽量的实现了位置索引)
一、基本的数据结构
1.1 栈stack
1.1.1 stack的基本特性
C++ stack(堆栈)是一种基于后进先出(LIFO)原则操作的容器。它具有以下基本特性:
- 后进先出(LIFO):只有位于堆栈顶部的元素可以被访问和删除,新添加的元素也会被放在堆栈的顶部。
- 动态性:stack的大小是动态的,可以根据需要自动增长或缩小。
- 随机访问:stack支持随机访问,可以通过索引直接访问任意位置的元素。但是注意,由于stack是后进先出(LIFO)的,所以最后一个添加到stack中的元素是第一个被访问的。
- 容器的通用性:stack可以容纳任何类型的元素,包括基本类型和自定义类型。
1.1.2 stack的代码使用例程
#include <stack> //头文件
std::stack<int> myStack; // 栈的声明创建
using namespace std; //忽略std::
stack<int> myStack;
myStack.push(10); //通过push添加元素
myStack.push(20);
int top = myStack.top(); // 获取栈顶元素
myStack.pop(); // 删除栈顶元素
bool isEmpty = myStack.empty(); // 判断栈是否为空
int size = myStack.size(); // 获取栈的大小
//一些高级使用方法,自定义栈(固定类型和固定长度)
std::stack<int, std::vector<int>> myStack;
1.1.3 stack的用法总结(表格)
函数名 | 功能描述 |
---|---|
push() |
向栈顶添加一个元素 |
pop() |
删除栈顶元素 |
top() |
返回栈顶元素的值 |
empty() |
判断栈是否为空,如果为空则返回true,否则返回false |
size() |
返回栈中元素的个数 |
clear() | 清空栈中的所有元素。 |
1.2 单端队列queue
1.2.1 queue的基本特性
C++ queue是一种基于先进先出(FIFO)原则操作的容器。它具有以下基本特性:
- 先进先出(FIFO):队列的头部是第一个被添加的元素,也是第一个可以被删除的元素。新添加的元素总是被放在队列的尾部。
- 动态性:queue的大小是动态的,可以根据需要自动增长或缩小。
- 随机访问:queue不支持随机访问,不能通过索引直接访问任意位置的元素。只能从队头开始依次访问。
- 容器的通用性:queue可以容纳任何类型的元素,包括基本类型和自定义类型。
1.2.2 queue的代码使用例程
#include <queue> //头文件声明
using namespace std;
queue<int> q; // 创建一个整数类型的队列
q.push(10); // 在队列尾部添加元素
bool em=q.empty(); //判断队列是否为空
int ans=q.front(); //获取队列的头部第一个元素
int ans=q.back(); //获取队列的尾部第一个元素
q.pop(); //删除队列头部第一个元素
int qsize=q.size(); //获取队列大小
1.2.3 queue的用法总结(表格)
函数名 | 功能描述 |
---|---|
push() |
在队列尾部添加一个元素 |
pop() |
删除队列的头部元素 |
front() |
返回队列的头部元素 |
back() |
返回队列的尾部元素 |
empty() |
判断队列是否为空(元素个数为0) |
size() |
返回队列中元素的个数 |
clear() | 清空栈中的所有元素。 |
1.3 双端队列deque
1.3.1 deque的基本特性
C++ deque(双端队列)是一种具有队列和栈的性质的数据结构。它支持在队列的前端和后端进行插入和删除操作。其基本特性包括:
- 双向队列:deque在队列的两端都可以进行插入和删除操作。
- 动态数组:deque底层通常使用动态数组实现,可以动态地增长和缩小。
- 顺序存储:deque中的元素是顺序存储的,相邻元素在内存中相邻存储。
- 支持随机访问:deque支持使用索引进行访问,可以随机访问队列中的元素。
- 高效的插入和删除操作:deque在队列的两端插入和删除元素的复杂度为O(1)。
1.3.2 deque的代码使用例程
#include <iostream>
#include <deque> //头文件声明
using namespace std;
deque<int> d; // 创建一个空的deque
d.push_front(1); // 在队列前端插入元素
d.push_back(3); // 在队列后端插入元素
int ans=d.size();//队列大小
d.pop_front(); //删除队列第一个元素
d.pop_back(); //删除队列最后一个元素
bool em=d.empty();//队列是否为空
1.3.3 deque的用法总结(表格)
函数名 | 功能描述 | 时间复杂度 |
---|---|---|
push_front() |
在队列前端插入一个元素 | O(1) |
push_back() |
在队列后端插入一个元素 | O(1) |
pop_front() |
删除队列前端的一个元素 | O(1) |
pop_back() |
删除队列后端的一个元素 | O(1) |
front() |
返回队列前端的元素 | O(1) |
back() |
返回队列后端的元素 | O(1) |
empty() |
判断空 |
1.4 数组容器vector
1.4.1 vector的基本特性
C++ vector是一种动态数组,它具有以下基本特性:
- 动态性:vector的大小是动态的,可以在运行时添加或删除元素。
- 随机访问:vector支持随机访问,可以通过索引直接访问任意位置的元素。
- 容器的通用性:vector可以容纳任何类型的元素,包括基本类型和自定义类型。
- 高效性:vector在内存中连续存储元素,因此访问元素的速度非常快。
1.4.2 vector的代码使用例程
#include <iostream>
#include <vector>
std::vector<int> v; // 创建一个空的vector
v.push_back(1); // 在vector末尾添加元素
int siz=v.size(); //返回vector数组大小
v.insert(v.begin(), 0); // 在vector前端插入元素
v.erase(v.begin() + 1); // 删除vector中的元素
v.clear(); // 清空vector中的元素
1.4.3 vector的用法总结(表格)
函数名 | 描述 |
---|---|
push_back() | 在vector末尾添加一个元素 |
emplace_back() | 在vector末尾添加一个元素(但不通过临时变量存储) |
insert() | 在vector前端或后端插入一个或多个元素 |
erase() | 删除vector中的一个或多个元素 |
clear() | 清空vector中的所有元素 |
resize() | 调整vector的大小(会进行变量的初始化) |
reserve() | 调整vector的内存大小(不进行变量的初始化) |
empty() | 判断vector是否为空 |
size() | 获取vector的大小 |
capacity() | 获取vector的容量 |
front() | 获取vector第一个元素的值 |
back() | 获取vector最后一个元素的值 |
operator[] | 通过索引访问vector中的元素 |
begin() | 获取vector的起始迭代器 |
end() | 获取vector的结束迭代器 |
rbegin() | 获取vector的逆向起始迭代器(从尾部开始) |
rend() | 获取vector的逆向结束迭代器(从尾部开始) |
1.4.4 vector的高级使用(优化)
1.4.4.1 元素插入(优化)
对于vector的元素插入存在两个函数push_back()以及emplace_back(),其都是向容器尾部插入元素,但存在一些小的差异点:
- push_back()的机理:1.构造一个临时对象——2.调用移动构造函数把临时对象的副本拷贝到容器末尾增加的元素中——3.调用析构释放临时对象。
- emplace_back()调用构造函数在容器末尾增加一个元素。
可以通过如下代码进行展示:
#include<iostream>
#include <vector>
using namespace std;
class MyTest
{
public:
//普通构造
MyTest(int id,int age):m_id(id),m_age(age)
{
cout << "创建" << this << endl;
}
//拷贝构造
MyTest(const MyTest &t):m_id(t.m_id),m_age(t.m_age)
{
cout << "拷贝" << this << endl;
}
//移动构造
MyTest(const MyTest &&t)
{
m_id = std::move(t.m_id);
m_age = std::move(t.m_age);
cout << "移动" << this << endl;
}
//析构
~MyTest()
{
cout << "析构" << this << endl;
}
private:
int m_id; //id成员
int m_age;//age成员
};
int main(int argc, char *argv[])
{
vector<MyTest> vec(10);
cout << "\n ------ push_back --------" << endl;
vec.push_back(MyTest(1,20));
cout << "\n ------ emplace_back --------" << endl;
vec.emplace_back(1,20);
cout << "\n -------- finish -------- " << endl;
}
通过编译可以得到如下结果:
------ push_back --------
创建
移动
析构
------ emplace_back --------
创建
-------- finish --------
析构
析构
因此emplace_back()的效率要比push_back()高得多,在处理大数据量的问题时效果更加明显。
1.4.4.2 容器大小声明(内存初始化)
在C++的std::vector
中,resize
和reserve
是两个用于处理动态数组的方法,它们的区别在于它们的目标和行为不同。
resize
:此方法用于改变vector
的大小。如果你将vector
的大小设为新的大小,那么vector
中超出新大小的部分会被删除,而小于新大小的部分会被添加空值(对于基本类型)或默认构造的对象(对于类类型)。reserve
:此方法用于改变vector
的容量。reserve
方法会预先分配足够的内存以容纳新的元素,但并不会构造这些元素。如果分配的容量大于当前的需求,那么多余的内存将被闲置,不会进行任何初始化。
std::vector<int> v;
v.resize(10); // v现在包含10个int类型的默认值(通常是0)
std::vector<int> v;
v.reserve(10); // v现在具有预先分配的内存,可以容纳10个int类型的元素,但v中仍然没有元素
1.5 双向链表list *
1.5.1 list的基本特性
C++的list是一种双链表,这意味着每个元素都有一个指向前一个和后一个元素的指针。相比于单链表,双链表在插入和删除操作中更为高效,因为它不需要遍历链表来找到插入或删除的位置。
list支持常见的序列操作,如添加元素(push_front, push_back),删除元素(erase),查找元素(find),访问元素(front, back)等。同时,list还支持一些更高级的操作,如合并(splice),排序(sort),反转(reverse)等。
1.5.2 list的代码使用例程
#include <iostream>
#include <list>
using namespace std;
list<int> my_list; // 创建一个整数类型的链表
my_list.push_back(1); // 添加元素
// 删除元素
my_list.pop_back(); // 删除末尾元素
my_list.pop_front(); // 删除头部元素
my_list.erase(2); // 删除指定元素
// 查找元素
auto it = my_list.find(1); // 在链表中查找元素1,返回指向它的迭代器
if (it != my_list.end()) { // 如果找到了元素1
std::cout << "Fo