1 pair
1)pair的定义和结构
在C++中,pair是一个模板类,用于表示一对值的组合。
它位于<utility>头文件中。
pair类的定义如下:
template<class T1,class T2>
struct pair {
T1 first;//第一个值
T2 second;//第二个值
//构造函数
pair();
pair( const T1& x, const T2& y);
//比较运算符重载
bool operator==(const pair& rhs) const;
bool operator!=(const pair& rhs) const;
//其他成员函数和特性
...
};
pair类模板有两个模板参数, T1和T2,分别表示第一个值和第二个值的类型。
pair类有两个成员变量,first和lsecond,分别表示第一个值和第二个值。
pair类还有一些成员函数和特性例如默认构造函数、带参数的构造函数、比较运算符重载等。
使用pair类,你可以方便地将两个值组合在一起,并进行传递、存储和操作。
例如,可以将两个整数组合在一起作为函数的返回值,或者将一对值存储在容器中。
例1.1下面是一些使用pair的示例
#include <iostream>
#include <utility>
int main()
{
std::pair<int,double> p1(1,3.14);
std::pair<char,std::string> p2('a',"hello");
std::cout <<p1.first <<"," <<p1.second <<std::endl;
std::cout<<p2.first <<"," <<p2.second <<std::endl;
return 0;
}
以上代码创建了两个pair对象,分别包含不同类型的值。
然后,通过访问first和second成员变量,输出了这些值。
2)pair的嵌套
pair可以进行嵌套,也就是说可以将一个pair对象作为另一个pair对象的成员。通过嵌套pair,你可以方便地组合多个值,并形成更复杂的数据结构。
例如,你可以创建一个三维坐标系的点,其中第1个维度由一个整数表示,第2、3个维度由一个pair表示。
例1.2 下面是一个示例代码,演示了如何嵌套使用pair
#include <iostream>
#include <utility>
int main()
{
std::pair<int,int> p1(1,2);
std::pair<int,std::pair<int,int>> p2(3,std::make_pair(4,5));
std::pair<std::pair<int,int>,std::pair<int,int>> p3(std::make_pair(6,7),std::make_pair(8,9));
std::cout<<p1.first<<","<<p1.second<<std::endl;
std::cout<<p2.first<<","<<p2.second.first <<","<< p2.second.second <<std::endl;
std::cout<<p3.first.first<<","<<p3.first.second<<","<<p3.second.first <<","<<p3.second.second<<std::endl;
return 0;
}
在这个示例中,我们创建了三个pair对象: p1、p2和p3。
p1是一个简单的pair,包含两个整数值。
p2是一个嵌套的pair,其中第一个值是一个整数,第二个值是一个pair,其中包含两个整数值。
p3是一个嵌套的pair,其中每个值都是一个pair,每个pair包含两个整数值。
通过访问嵌套的pair对象的成员变量,我们可以获取到相应的值。
3)pair自带排序规则
pair自带的排序规则是按照first成员进行升序排序。
如果first成员相等,则按照second成员进行升序排序。
这意味着当你使用标准库中的排序算法(如std::sort)对包含pair对象的容器进行排序时,会根据pair对象的first成员进行排序。
例1.3 下面是一个示例代码,演示了如何使用pair进行排序
#include <iostream>
#include <utility>
#include <vector>
#include <algorithm>
int main()
{
std::vector<std::pair<int, int>> vec;
vec.push_back(std::make_pair(3,2));
vec.push_back(std::make_pair(1,4));
vec.push_back(std::make_pair(2,1));
std::sort(vec.begin(),vec.end());
for(const auto& p:vec)
{
std::cout<<p.first<< "," <<p.second<<std::endl;
}
return 0;
}
在这个示例中,我们创建了一个存储pair对象的向量vec,其中包含三个pair对象。
然后,我们使用stdsort函数对vec进行排序。由于pair对象的排序规则是按照first成员进行升序排序,
所以排序后的结果是:
1,4
2,1
3,2
最后,我们通过遍历vec并输出每个pair对象的成员,验证了排序结果。
需要注意的是,如果你想按照其他排序规则对pair进行排序,可以自定义比较函数或使用lambda表达式来传递给排序算法。这样,你可以根据自己的需求定义排序规则。
例1.4 代码示例
#include <iostream>
#include <utility>
#include <vector>
//定义一个结构体,表示一个人的信息
struct Person{
std::string name;
int age;
};
int main()
{
//创建一个存储Person对象的向量
std::vector<Person> people;
//添加一些Person对象到向量中
people.push_back({"Alice",25});
people.push_back({"Bob",30});
people.push_back({"Charlie",20});
//创建一个存储pain的向量,每个pair包含一个Person对象和一个评分
std::vector<std::pair<Person,int>> scores;
//添加一些pair到向量中
scores.push_back({people[0],9});
scores.push_back({people[1],85});
scores.push_back({people[2],95});
//遍历pair向量,并输出每个人的姓名、年龄和评分
for(const auto pair:scores)
{
std::cout<<"Name:"<< pair.first.name<<std::endl;
std::cout<<"Age:"<< pair.first.age<< std::endl;
std::cout<<"Score:"<<pair.second<<std::endl;
std::cout<<std::endl;
}
return 0;
}
2 vector
1)vector的定义和特性
在C++中, vector是一个动态数组容器,可以存储一系列相同类型的元素。
它是标准库<vector>中定义的模板类。
vector的定义和结构非常简单,它由以下几个重要的部分组成:
模板类声明: vector是一个模板类,因此在使用之前需要包含头文件<vector>。
声明一个vector对象的通用语法如下:
std::vector<T> vec;
这里的T是要存储在vector中的元素类型。
容器大小:vector是一个动态数组,可以根据需要自动调整大小。
它会根据元素的数量动态分配内存空间。
元素访问:可以通过索引来访问vector中的元素。索引从0开始,最后一个元素的索引是size()-1,可以使用[]运算符或at()函数来访问元素。
元素添加和删除:可以使用push_back()函数在vector的末尾添加元素,使用pop_back()函数删除末尾的元素。还可以使用insert()函数在指定位置插人元素,使用erase()函数删除指定位置的元素.
容器大小管理:可以使用size()函数获取vector中元素的数量,使用empty()函数检查vector是否为空。还可以使用resize()函数调整vector的大小。
迭代器:vector提供了迭代器,可以用于遍历容器中的元素。可以使用begin()函数获取指向第一个元素的迭代器,使用end()函数获取指向最后一个元素之后位置的迭代器。
2)vector的常用函数
push back():将元素添加到vector的末尾。
void push_back( const T& value);
pop_back():删除vector末尾的元素.
void pop_back(); //一定保证vector非空
begin()和end():返回指向vector第一个元素和最后一个元素之后位置的迭代器。
iterator begin();
const_iterator begin() const;
iterator end();
const_iterator end() const;
例2.1
#include <iostream>
#include <utility>
#include <vector>
int main()
{
std::vector<int> vec = {10,20,30};
for (auto it=vec.begin();it!=vec.end();++it){ //迭代器不能比较,只有相等或不等
std::cout<<*it<<" ";
}
return 0;
}
3)vector排序去重
排序:
要对vector进行排序,可以使用标准库中的std:sort函数。
该函数位于头文件<algorithm>中。
#include <algorithm>
std::vector<T> vec={...};
std::sort(vec.begin(),vec.end());
这里的T是vector中元素的类型。
std:sort函数接受两个迭代器参数,表示要排序的范围。
vec.begin()返回指向vector第一个元素的迭代器
vec.end()返回指向最后一个元素之后位置的迭代器。
例2.2
#include <iostream>
#include <vector>
#include <algorithm>
int main()
{
std::vector<int> vec = {5,2,8,1,9};
std::sort(vec.begin(),vec.end());
for(const auto& num:vec)
{
std::cout<<num<<" ";
}
return 0;
}
去重:
要去除vector中的重复元素,可以使用std:unique函数。
该函数位于头文件<algorithm>中。
#include <algorithm>
std::vector<T> vec={...};
std::sort(vec.begin(),vec.end());
auto last=std::unique(vec.begin(),vec.end());
vec.erase(last,vec.end());
首先,需要对vector进行排序,以便相同的元素相邻。
然后,std::unique函数将重复的元素移动到vector的末尾,并返回一个指向重复元素的迭代器。
最后,可以使用vec.erase函数将重复元素从vector中删除。
例2.3
#include <iostream>
#include <vector>
#include <algorithm>
int main()
{
std::vector<int> vec = {2,1,3,2,4,1,5,4};
std::sort(vec.begin(),vec.end());
auto last=std::unique(vec.begin(),vec.end());
vec.erase(last,vec.end());
for(const auto& num:vec)
{
std::cout<<num<<"";
}
return 0;
}
这样,vector中的重复元素被去除,只保留了不重复的元素。
例2.4
#include <iostream>
#include <vector>
#include <algorithm>
int main() {
//创建一个空的std::vector对象
std::vector<int> numbers;
//向向量中添加元素
numbers.push_back(5);
numbers.push_back(2);
numbers.push_back(8);
numbers.push_back(5);
numbers.push_back(1);
numbers.push_back(2);
numbers.push_back(9);
numbers.push_back(8);
//打印向量中的元素
std::cout<<"原始向量中的元素:";
for(const auto& number:numbers) {
std::cout<<number<<" ";
}
std::cout<<std::endl;
//对向量进行排序
std::sort(numbers.begin(), numbers.end());
//打印排序后的向量
std::cout<<"排序后的向量:";
for(const auto& number:numbers) {
std::cout<<number<<" ";
}
std::cout<<std::endl;
//去除重复元素
numbers.erase(std::unique(numbers.begin(),numbers.end()),numbers.end());
//打印去重后的向量
std::cout<<"去重后的向量:";
for(const auto& number:numbers) {
std::cout<<number<<" ";
}
std::cout<<std::endl;
//向向量中插入元素
numbers.insert(numbers.begin()+2,3);
//打印插入元素后的向量
std::cout<<"插入元素后的向量:";
for(const auto& number:numbers) {
std::cout<<number<< " ";
}
std::cout<<std::endl;
//删除向量中的某个元素
numbers.erase(numbers.begin() +4);
std::cout <<"删除元素后的向量:";
for (const auto& number:numbers) {
std::cout<<number<<"";
}
std::cout<<std::endl;
//检查向量是否为空
if(numbers.empty()){
std:: cout<<"向量为空"<<std::endl;}
else {
std::cout<<"向量不为空"<< std::endl;
}
//获取向量的大小
std::cout <<"向量的大小:"<<numbers.size()<<std::endl;
//清空向量
numbers.clear();
//检查向量是否为空
if(numbers.empty()) {
std::cout<<"向量为空"<<std::endl;}
else{
std::cout<<"向量不为空"<<std::endl;
}
return 0;
}
3 list
1)list的定义和结构
list的使用频率不高,在做题时极少遇到需要使用list的情景。
list是一种双向链表容器,它是标准模板库(STL)_提供的一种序列容器。
list容器以节点(node)的形式存储元素,并使用指针将这些节点链接在一起,形成一个链表结构。
list容器结构如下:
list容器的定义和结构如下:
template <class T,class Allocator = std::allocator<T>>
class list;
list容器模板接受两个参数:
1.T:指定容器中存储的元素类型。
2.Allocator(可选):指定用于分配内存的分配器类型,默认为std::allocator<T>。表示怎么分配内存,可以不管。
list容器的特点包括:
·双向性:每个节点都包含指向前一个节点和后一个节点的指针,因此可以在常数时间内在链表中的任意位置(要记录地址)进行插入、删除和访问操作。
·动态大小:链表的大小可以根据需要动态扩展或收缩,不需要预先指定容器的大小。
·不连续存储:链表中的节点可以在内存中的任意位置分布,不要求连续存储,因此插入和删除操作不会导致元素的移动。
list容器提供了一系列成员函数和迭代器来操作和访问链表中的元素,包括插入、删除、访问、反转等操作。可以使用迭代器来遍历链表中的元素。
例3.1 展示如何使用list容器:
#include <iostream>
#include <list>
int main(){
std::list<int> myList;
//在链表尾部插入元素
myList.push_back(1);
myList.push_back(2);
myList.push_back(3);
//在链表头部插入元素
myList.push_front(0);
//遍历链表并输出元素
for (int num:myList){ //可迭代容器中元素的遍历
std::cout<<num<<" ";
}
std::cout<<std::endl;
return 0;
}
在上述示例中,我们首先创建了一个list容器myList,然后使用push_back()和push_front()函数分别在链表尾部和头部插入元素。最后,使用范围基于范围的for循环遍历链表并输出元素。
需要注意的是,由于list是双向链表,因此插入和删除操作的时间复杂度是常量时间O(1),但访问和查找操作的时间复杂度是线性时间O(n),其中n是链表的大小。
因此,如果需要频繁进行随机访问操作,可能更适合使用支持随机访问的容器,如vector或deque(双端队列)。
2)list的常用函数
list容器提供了多个常用的成员函数来操作和访问链表中的元素。
以下是一些常用的list函数的解释:
push back():将元素插入到链表的末尾。
push front():将元素插人到链表的开头。//双向
pop_back():移除链表末尾的元素。
pop_front():移除链表开头的元素。
size():返回链表中元素的个数。
empty():检查链表是否为空。
clear():清空链表中的所有元素。
front():返回链表中第一个元素的引用。//引用可以直接修改元素
back():返回链表中最后一个元素的引用。
begin():返回指向链表第一个元素的迭代器。
end():返回指向链表末尾的下一个位置的迭代器。
insert():在指定位置之前插入一个或多个元素。
erase():从链表中移除指定位置的一个或多个元素。
例3.2
#include <iostream>
#include <list>
#include <algorithm>
using namespace std;
int main(){
//创建一个list<int>对象myList
list<int> mylist;
//向mylist尾部添加元素
for(int i=1;i<=5;++i){
mylist.push_back(i);
}
//从头到尾输出myList中的元亲
for(const auto &i:mylist)cout<<i<<' ';
cout<<'\n';
//将mylist中元素反转
reverse(mylist.begin(),mylist.end());
for(const auto &i:mylist)cout<<i<<' ';
cout<<'\n';
//在第一个元素的后一个位置加上元素0
mylist.insert(++mylist.begin(),0);
for(const auto &i:mylist)cout<<i<<' ';
cout<<'\n';
mylist.erase(++ ++mylist.begin(),--mylist.end());
//输出myList的大小
cout<<"链表大小为:" <<mylist.size()<<'\n';
//从头到尾输出myList中的元素
for(const auto &i:mylist)cout<<i<<' ';
cout<<'\n';
return 0;
}