vector
C++ std::vector 总结
std::vector
是 C++ 标准库中的一个序列容器,它封装了动态大小的数组。以下是关于 std::vector
的一些关键点和使用注意事项:
-
存储方式:
std::vector
中的元素是连续存储的,这意味着不仅可以通过迭代器访问元素,还可以使用偏移量来访问元素的常规指针。 -
自动管理存储:
std::vector
会自动处理其存储,根据需要进行扩展。通常,向量占用的空间比静态数组多,因为更多的内存被分配用于处理未来的增长。这样,每次插入元素时,向量不需要重新分配,只有在额外的内存用尽时才需要。 -
性能注意事项:重新分配通常在性能方面是代价高昂的操作。如果事先知道元素的数量,可以使用
reserve()
函数来避免重新分配。 -
操作复杂度:
- 随机访问 - 常数时间 O(1)。
- 在末尾插入或删除元素 - 平摊常数时间 O(1)。
- 插入或删除元素 - 线性时间 O(n)。
-
迭代器失效:某些操作可能导致迭代器失效。例如,如果向量更改了容量,
push_back
或emplace_back
可能会使所有迭代器失效。erase
会使被删除的元素和它们之后的所有元素的迭代器失效。 -
特化:标准库为
bool
类型提供了std::vector
的特化,可能针对空间效率进行了优化。 -
示例:
#include <iostream> #include <vector> int main() { // 创建一个包含整数的向量 std::vector<int> v = {8, 4, 5, 9}; // 向向量添加两个整数 v.push_back(6); v.push_back(9); // 覆盖位置 2 的元素 v[2] = -1; // 打印向量 for (int n : v) std::cout << n << ' '; std::cout << '\n'; }
输出:8 4 -1 9 6 9
希望这个总结能帮助您更好地理解和使用 std::vector
。您还有其他关于 std::vector
或 C++ 的问题吗?
queue
#include <iostream>
#include <queue>
using namespace std;
int main() {
queue<int> q;
q.push(10); // Enqueue 10
q.push(20); // Enqueue 20
q.push(30); // Enqueue 30
cout << q.front() << endl; // Peek 10
q.pop(); // Dequeue 10
cout << q.front() << endl; // Peek 20
return 0;
}
deque
双向队列,相比queue:
- 可以被遍历
// 基本用法
std::deque<int> nums {1, 2, 3};
nums.push_back(4); // add at last
nums.push_front(0); // add at first
nums.pop_back(); // remove at last
nums.pop_front(); // remove at first
for (int num : nums) {
std::cout << num << "->";
}
// 1->2->3->
// 可以遍历
deque<int> myDeque = {1, 2, 3, 4, 5};
cout << "Traversing deque using iterators: ";
for (auto it = myDeque.begin(); it != myDeque.end(); ++it) {
cout << *it << " ";
}
cout << endl;
// Traversing deque using iterators: 1 2 3 4 5
unordered_map
std::unordered_map<std::string, size_t> people {{"Jan",44}, {"Jim", 33}, {"Joe", 99}}; // Name,age
// 模板类的默认构造函数,创建空的unordered_map
unordered_map<int, string> umap;
// 使用初始化列表初始化
unordered_map<int, string> umap = unordered_map<int, string>({{1,"a"},{2,"b"}}); // 显式调用C++的构造函数
unordered_map<int, string> umap2({{3,"c"},{4,"d"}}); // 隐式调用构造函数,更简洁
unordered_map<string, string> umap{
{"淘宝","https://www.taobao.com/"},
{"京东","https://www.jd.com/"},
{"天猫商城","https://jx.tmall.com/"} };
// 元素访问
first["GOOG"] = "Google"; // new element inserted
first["AAPL"] = "Apple"; // new element inserted
first["MSFT"] = "Microsoft"; // new element inserted
first["BOB"] = "Bob";
string brand1 = first["GOOG"]; // read
first["BOB"] = ""; // writen
for (auto it = first.begin(); it != first.end(); it++){
cout << " " << it->first << ":" << it->second;
}
cout<<endl;
/** 插入 **/
unordered_map<string,double> myrecipe, mypantry = {{"milk",2.0},{"flour",1.5}};;
pair<string,double> myshopping ("baking powder",0.3);
myrecipe.insert(myshopping); // copy insertion
myrecipe.insert(mypantry.begin(), mypantry.end()); // range inseration
myrecipe.insert({{"sugar",0.8},{"salt",0.1},{"sugar",0.9}}); // initializer list inseration
cout << "myrecipe contains:" << endl;
for(auto& x:myrecipe){
cout << x.first << ":" << x.second << " ";
}
/** 遍历 **/
for (auto it = first.begin(); it != first.end(); it++){
cout << " " << it->first << ":" << it->second;
}
cout<<endl;
std::set
set<int> q; //以int型为例 默认按键值升序
set<int,greater<int>> p; //降序排列
int x;
q.insert(x); //将x插入q中
q.erase(x); //删除q中的x元素,返回0或1,0表示set中不存在x
q.clear(); //清空q
q.empty(); //判断q是否为空,若是返回1,否则返回0
q.size(); //返回q中元素的个数
q.find(x); //在q中查找x,返回x的迭代器,若x不存在,则返回指向q尾部的迭代器即 q.end()
q.lower_bound(x); //返回一个迭代器,指向第一个键值不小于x的元素
q.upper_bound(x); //返回一个迭代器,指向第一个键值大于x的元素
q.rend(); //返回第一个元素的的前一个元素迭代器
q.begin(); //返回指向q中第一个元素的迭代器
q.end(); //返回指向q最后一个元素下一个位置的迭代器
q.rbegin(); //返回最后一个元素
std::tuple
std::tuple
is a container that allows grouping multiple values of different types together as a single object. It is a part of the C++11 standard library and is a generalization ofstd::pair
. A tuple can store any number of objects, and each object can have its own type.
C++中的元组,类似于泛化的std::pair
,可以当成一个结构体来用。
来自 https://en.cppreference.com/w/cpp/utility/tuple 的例子:
std::tuple<int, int> foo_tuple()
{
return {1, -1}; // Error until N4387
return std::tuple<int, int>{1, -1}; // Always works
return std::make_tuple(1, -1); // Always works
}
#include <iostream>
#include <stdexcept>
#include <string>
#include <tuple>
std::tuple<double, char, std::string> get_student(int id)
{
switch (id)
{
case 0: return {3.8, 'A', "Lisa Simpson"};
case 1: return {2.9, 'C', "Milhouse Van Houten"};
case 2: return {1.7, 'D', "Ralph Wiggum"};
case 3: return {0.6, 'F', "Bart Simpson"};
}
throw std::invalid_argument("id");
}
int main()
{
const auto student0 = get_student(0);
std::cout << "ID: 0, "
<< "GPA: " << std::get<0>(student0) << ", "
<< "grade: " << std::get<1>(student0) << ", "
<< "name: " << std::get<2>(student0) << '\n';
const auto student1 = get_student(1);
std::cout << "ID: 1, "
<< "GPA: " << std::get<double>(student1) << ", "
<< "grade: " << std::get<char>(student1) << ", "
<< "name: " << std::get<std::string>(student1) << '\n';
double gpa2;
char grade2;
std::string name2;
std::tie(gpa2, grade2, name2) = get_student(2);
std::cout << "ID: 2, "
<< "GPA: " << gpa2 << ", "
<< "grade: " << grade2 << ", "
<< "name: " << name2 << '\n';
// C++17 structured binding:
const auto [gpa3, grade3, name3] = get_student(3);
std::cout << "ID: 3, "
<< "GPA: " << gpa3 << ", "
<< "grade: " << grade3 << ", "
<< "name: " << name3 << '\n';
}
其他例子:
// 创建
tuple<int,float,int,float> tu = make_tuple(1,2.f,3,4.f); //创建方式一
tuple<int,float,int,float> tu(1,2.f,3,4.f); //创建方式二
//相当于结构体:
struct tu
{
int a;
float b;
int c;
float d;
}
// 以上创建方式只是实参的拷贝,如果我们修改这些参数是无法真正修改实际的参数的值
// 以下是直接修改参数的方式
int a = 0;
float b = .f;
int c = 0;
float d = .1;
auto tu = tie(a,b,c,d);
//本地进行修改
get<0> (tu) = 2;
get<1> (tu) = 4.5f;
get<2> (tu) = 234;
get<2> (tu) = 22.f;
//当然还可以这么用
auto tu1 = make_tuple(1,2.f,3,4.f);
std::string str_five_1("five_1");
// 输出原址值
std::cout << "str_five_1 = " << str_five_1.c_str() << "\n";
std::tuple<std::string&, int> five(str_five_1, 5);
// 通过元组 对第一个元素的修改,str_five_1的值也会跟着修改,因为元组的第一个元素类型为引用。
// 使用get访问元组的第一个元素
std::get<0>(five) = "five_2";
// 输出的将是: five_2
std::cout << "str_five_1 = " << str_five_1.c_str() << "\n";
std::tuple<char, int, long, std::string> fourth('A', 2, 3, "4");
// 元组,可以看作一个包,类比结构体。 需要访问元组的元素时,2 种方法: A、索引访问,B、std::tie 。
// 元组包含一个或者多个元素,使用std::tie解包: 首先需要定义对应元素的变量,再使用tie。 比如,元素第0个元素的类型时 char, 第1个元素类型时int, 那么, 需要定义 一个 char的变量和int的变量, 用来储存解包元素的结果。
// 定义变量,保存解包结果
char tuple_0 = '0';
int tuple_1 = 0;
long tuple_2 = 0;
std::string tuple_3("");
// 使用std::tie, 依次传入对应的解包变量
std::tie(tuple_0, tuple_1, tuple_2, tuple_3) = fourth;
// 输出解包结果
std::cout << "tuple_0 = " << tuple_0 << "\n";
std::cout << "tuple_1 = " << tuple_1 << "\n";
std::cout << "tuple_2 = " << tuple_2 << "\n";
std::cout << "tuple_3 = " << tuple_3.c_str() << "\n";
std::accumulate
#include <iostream>
#include <vector>
#include <numeric>
int main( int argc, char **argv )
{
std::vector<int> v{1, 2, 3, 4};
int v1 = std::accumulate( v.begin(), v.end(), 0 );
int v2 = std::accumulate( v.begin(), v.end(), 1, std::multiplies<int>() );
int v3 = std::accumulate( v.begin(), v.end(), 1, std::multiplies<int>{} );
std::cout << "v1: " << v1 << '\n';
std::cout << "v2: " << v2 << '\n';
std::cout << "v3: " << v3 << '\n';
return 0;
}
// 输出
// v1: 10
// v2: 24
// v3: 24
参考: