【PAT甲级复习】 专题复习五:常用的STL容器及其相关操作

专题复习五(9.6):常用的STL容器及其相关操作

1 vector的常见用法

只有在vector和string中,才允许使用v.begin()+3这种迭代器加上整数的写法。

// 1.定义
vector<int> v1;
vector<Node> v2;
vector<vector<int> > v3;
vector<int> Adj[MAXV];	//声明一个邻接表
vector<int> v4(50);		//声明一个初始大小为50的int向量
vector<int> v5(10, 1);	//声明一个初始大小为10且值都是1的向量
vector<int> v6(v1);		//声明v6并用v1向量初始化
vector<int> v7(v1.begin(), v1.begin() + 3);	//用向量v1的第0个到第2个值初始化v7
int arr[5] = {1, 2, 3, 4, 5};	
vector<int> v8(arr, arr + 5);				//将arr数组的元素用于初始化v8向量: 1 2 3 4 5
vector<int> v9(&arr[1], &arr[4]); //将[ arr[1]~arr[4] )范围内的元素作为v9的初始值: 2 3 4

// 2.元素访问
vector<int> v1(10);	
cout << v1[5] << v1[v1.size()-1];	//通过下标访问
vector<int>::iterator it = v1.begin();	//通过迭代器访问
for(int i=0; i<v1.size()-1; i++){
    cout << *(it + i);
}
for(vector<int>::iterator it = v1.begin(); it != v1.end(); it++){
    cout << *it;
}

// 3.常用函数
vector<int> v;
v.push_back(1);		//时间复杂度O(1)
V.pop_back();		//时间复杂度O(1)
int s = v.size();	//时间复杂度O(1)
v.clear();			//时间复杂度O(N)
v.insert(v.begin()+2, -1);	//时间复杂度O(N),插入后为1 2 -1 3 4 5
v.erase(v.begin()+2);		//时间复杂度O(N),删除后为1 2 3 4 5
v.erase(v.begin(), v.begin()+3);	//时间复杂度O(N),删除后为4 5
int max = *max_element(v.begin(), v.end());	//求最大元素
int max = *min_element(v.begin(), v.begin()+3); //求[0,3)之间的最小元素
reverse(v.begin(), v.end());	//将vector中的元素倒序
sort(v.begin(), v.end()); //采用的是从小到大的排序
//如果想从大到小排序,可以采用反转函数,也可以采用下面方法:
bool cmp(const int& a, const int& b) {
	return a > b;
}
sort(v.begin(), v.end(), cmp);

2 set的常见用法

STL中的set使用方法详细!!!!_知足常乐的博客-CSDN博客

c++ STL中标准关联容器set, multiset, map, multimap内部采用的就是一种非常高效的平衡检索二叉树:红黑树,也成为RB树(Red-Black Tree)。RB树的统计性能要好于一般平衡二叉树,所以被STL选择作为了关联容器的内部结构。set内的元素自动递增排序,且去除了重复元素

// 1.定义
set<int> s1;
set<Node> s2;
set<int> s3[MAXV];

// 2.元素访问
for(set<int>::iterator it = s3.begin(); it != s3.end(); it++){
    cout << *it;
}

// 3.常用函数
s1.insert(1);		//时间复杂度O(logN)
//时间复杂度O(logN),如果找到返回迭代器位置,否则返回s1.end()
set<int>::iterator it = s1.find(1);	
//删除单个元素的方式有两种,一种参数为迭代器,一种参数为要删除的值
s1.erase(it);	//时间复杂度O(1)
s1.erase(3);	//时间复杂度O(logN)
s1.erase(it, s1.end())	//删除一个区间的元素,时间复杂度O(last-first)
int num = s1.size();	//时间复杂度O(1)
s1.clear();				//时间复杂度O(N)

//set默认的是递增排序,如果想从大到小排序,可以采用下面方法:
set<int, greater<int> > st;
//如果没有排序要求,使用unordered_set速度会快很多,因为其底层是Hash实现的。
unordered_set<int> st;

3 string的常见用法

stl之string类用法详细总结_Hao_09的专栏-CSDN博客_stl string

// 1.定义
string s; //生成一个空字符串s
string s = "123";
string s(str) //拷贝构造函数生成str的复制品
string s(str,index) //将字符串str内“始于位置index”的部分当作字符串的初值
string s(str,index, n) //将字符串str内“始于index且长度顶多n”的部分作为字符串的初值
string s(cstr) //将C字符串作为s的初值
string s(chars,chars_len) //将C字符串前chars_len个字符作为字符串s的初值。
string s(n,c) //生成一个字符串,包含n个c字符
string s(str.begin(),str.end()) //以区间begin():end() (不包含end())内的字符作为字符串s的初值


// 2.元素访问
for(int i=0; i<str.length(); i++){
    printf("%c", str[i]);
}
cin >> str;
cout << str;
printf("%s",str.c_str()); //要用printf输出的话得使用c_str()将string类型转换为字符数组输出
string::iterator it;

// 3.常用函数
s1 = s2 + s3;
bool flag = s1 > s2;
s.length(); s.size();

//插入函数,时间复杂度为O(N)
string str = "abcxyz", str2 = "opq";
str.insert(3, str2);	//abcopqxyz
str.insert(str.begin() + 3, str2.begin(), str2.end());
s.insert(0, 4 - s.length(), '0'); //用来给不足4位的时候前面补0~

//删除函数,时间复杂度为O(N)
str.erase(it);
str.erase(str.begin()+1, str.end());
str.erase(pos, length);
string str = "abcdefg";
str.erase(3,2); //abcfg
str.clear()	//复杂度O(1)
str.substr(pos, length); //复杂度O(len);

//查找函数,时间复杂度为O(NM)
找到了返回下标,没找到返回string::npos
int main(void)
{
	string s("dog bird chicken bird cat");
	//字符串查找
	cout <<	s.find("bird") << endl;  //打印
	cout << (int)s.find("pig") << endl;   //打印-1
	//字符查找
	cout << s.find('i',7) << endl;   //打印
	//从字符串的末尾开始查找字符串
	cout << s.rfind("bird") << endl; //打印
	//从字符串的末尾开始查找字符
	cout << s.rfind('i') << endl;    //打印
	//查找第个属于某子串的字符
	cout << s.find_first_of("13r98") << endl;  //找到字符r,打印
	//查找第个不属于某字符串的字符
	cout << s.find_first_not_of("dog bird 2006") << endl;  //找到字符c,打印
	//查找最后一个属于某子串的字符
	cout << s.find_last_of("13r98") << endl;  //字符r,打印
	//查找最后一个不属于某字符串的字符
	cout << s.find_last_not_of("tea") << endl;  //字符c,打印
	return 0;
}

//替换函数,时间复杂度为O(N)
int main(void)
{
	string s("hello,boy!");
	s.replace(6,3,"gril");  //boy替换为girl
	cout << s << endl;      //打印hello gril!
	s.replace(10,1,3,'.');  //将"hello gril!"的'!'替换为'...'
	cout << s << endl;      //打印hello gril.
	s.replace(s.begin(),s.begin()+5, "good morning");
	cout << s << endl;     //打印good morning girl...
	return 0;
}

4 map的常见用法

cpp中的STL中map用法详解_Hello World-CSDN博客

map内部自建一颗红黑树(一种非严格意义上的平衡二叉树),这颗树具有对数据自动排序的功能,所以在map内部所有的数据都是有序的.map是一类关联式容器。它的特点是增加和删除节点对迭代器的影响很小,除了那个操作节点,对其他的节点都没有什么影响。对于迭代器来说,可以修改实值,而不能修改key

根据key值快速查找记录,查找的复杂度基本是Log(N)不需要排序时使用unordered_map节省时间

// 1.定义
map<int, int< mp;

// 2.元素访问
mp[10];
mp["c"];
for(map<char, int>::iterator it = mp.begin(); it != mp.end(); it++){
    printf("%c %d\n", it->first, it->second);
}

// 3.常用函数
map<char, int>::iterator it = mp.find('b');	//查找的是关键字是否出现,复杂的O(logN)
if(it != mp.end())  
	cout<<"Find, the value is "<<it->second<<endl;  
else  
	cout<<"Do not Find"<<endl;  
map["a"] == 0 如果a不存在于map
    
mp.erase(it);
mp.erase(key);
mp.erase(first, last);
mp.size();
mp.clear();

例如:map中已经插入了1234的话,如果lower_bound(2)的话,返回的2,而upper-bound(2)的话,返回的就是3
it = mp.lower_bound(1);  

5 queue的常见用法

STL详解(三) 队列容器queue_流年的博客-CSDN博客

STL deque用法_pigofzhou的博客-CSDN博客

主要用于BFS。

// 1.定义
queue<int> q;

// 2.元素访问
int a = q.front();
int b = q.back();

// 3.常用函数,复杂的都为O(1)
q.push(x);
q.pop();
q.empty();
q.size();

6 priority_queue的常见用法

STL priority_queue 常见用法详解 - 哨音 - 博客园 (cnblogs.com)

priority_queue底层是用堆来实现的。 默认的是大顶堆

主要用于解决一些贪心问题,以及Dijkstra算法的优化,使用top函数前记得先判断队列是否为空。

// 1.定义
priority_queue<int> q;
priority_queue<Node> q;

// 2.元素访问
int a = q.top();

// 3.常用函数
q.push(x);
q.top();
q.pop();
q.empty();
q.size();

// 4.优先级设置
priority_queue<int, vector<int>, greater<int> > q;	//设置为小顶堆
struct fruit{	//设置价格低的为优先级高
    string name;
    int price;
    friend bool operator < (const fruit &f1, const fruit &f2){
        return f1.price > f2.price;
    }
};
priority_queue<fruit> q1;

struct fruit{	//设置价格低的为优先级高
    string name;
    int price;
};
struct cmp{
    bool operator () (const fruit &f1, const fruit &f2){
        return f1.price > f2.price;
    }
};
priority_queue<fruit, vector<fruit>, cmp> q2;

7 stack的常见用法

stack的常见用途是用来模拟一些递归,防止程序对栈内存的限制而导致程序运行出错(不过这种应用一般出现较少)。

// 1.定义
stack<int> st;
stack<Node> st;

// 2.元素访问
int a = st.top();

// 3.常用函数
st.push(x);
st.top();
st.pop();
st.empty();
st.size();

8 pair的常见用法

pair可以看作内部有两个元素的结构体。pair中只有两个元素,分别是first和second,按正常结构体的方式去访问即可。

// 1.定义
pair<int, int> st;
pair<string, int> p("haha",5);

// 2.元素访问
p = make_pair("xixi",6);
cout << p.first << p.second;

// 3.常用函数
== != < <= > >=比较大小,先以first的大小为标准
mp.insert(make_pair("heihei,7"));

9 algorithm头文件下的常用函数

  1. max(),min() 参数必须是两个,可以是浮点数
  2. abs() 参数必须是整数,浮点数需要使用math头文件下的fabs
  3. swap(a,b) 用来交换a,b的值
  4. reverse(it1, it2),将[it1,it2)内的元素翻转,适用于数组以及容器(vector, string)。
  5. next_permutation() 给出下一个序列
int a[10] = {1, 2, 3};
do{
    printf("%d%d%d\n", a[0], a[1], a[2]);
}while(next_permutation(a, a+3));
  1. fill(a, a+MAXN, INF) 对数组或容器赋值。
  2. sort(a, a+5, cmp) 排序函数,主要用于结构体排序以及容器的排序(vector,string, deque可以使用sort)。
  3. lower_bound(first, last, val) 用来寻找在数组或容器的[first, last)范围内第一个值大于等于val的元素的位置。
  4. upper_bound(first, last, val) 用来寻找在数组或容器的[first, last)范围内第一个值大于val的元素的位置。
  5. 如果没有找到则返回可以插入的位置,upper_bound返回的值减去lower_bound返回的值即为值为val的元素个数。

10 例题解析

10.1 A1039 Course List for Student (25 分)

可以考虑字符串hash,用scanf读取节省时间,scanf读取string类型的话,需要先用resize分配内存,然后读取:

scanf("%s", &str[0]);

#include<bits/stdc++.h>
using namespace std;
int n, k;
unordered_map<string, set<int> > mp;

int getid(char *name) {
    int id = 0;
    for(int i = 0; i < 3; i++)
        id = 26 * id + (name[i] - 'A');
    id = id * 10 + (name[3] - '0');
    return id;
}

int main(){
    int courseId, m;
    string name;
    name.resize(4);
    cin >> n >> k;
    for(int i=1; i<=k; i++){
        scanf("%d %d",&courseId, &m);
        for(int j=0; j<m; j++){
            scanf("%s",&name[0]);
            mp[name].insert(courseId);
        }
    }
    for(int i=0; i<n; i++){
        scanf("%s",&name[0]);
        printf("%s %d",name.c_str(), mp[name].size());
        for(auto it = mp[name].begin(); it != mp[name].end(); it++){
            printf(" %d",*it);
        }
        printf("\n");
    }
}
10.2 A1047 Student List for Course (25 分)

直接用多个set会超时,先用vector存储,最后用sort排序一次就不会超时。

#include<bits/stdc++.h>
using namespace std;
int n, k;
vector<string> s[2505];
int main(){
    string name;
    int m, idx;
    name.resize(5);
    scanf("%d %d",&n,&k);
    for(int i=0; i<n; i++){
        scanf("%s %d",&name[0], &m);
        for(int j=0; j<m; j++){
            scanf("%d",&idx);
            s[idx].push_back(name);
        }
    }
    for(int i=1; i<=k; i++){
        printf("%d %d\n",i,s[i].size());
        sort(s[i].begin(), s[i].end());
        for(int j = 0; j < s[i].size(); j++){
            printf("%s\n",(s[i][j]).c_str());
        }
    }
}
10.3 A1063 Set Similarity (25 分)

得到交集之后,并集的元素数量用两个集合的元素数相加再减去交集元素数即可。

set_intersection, set_union真好用哈哈!

#include<bits/stdc++.h>
using namespace std;
set<int> st[55];
int n, m, k;
int main(){
    int temp, a, b;
    scanf("%d",&n);
    for(int i=1; i<=n; i++){
        scanf("%d",&m);
        for(int j=0; j<m; j++){
            scanf("%d",&temp);
            st[i].insert(temp);
        }
    }
    scanf("%d",&k);
    for(int i=0; i<k; i++){
        scanf("%d %d",&a,&b);
        set<int> interSt, unionSt;
        set_intersection(st[a].begin(), st[a].end(), st[b].begin(), st[b].end(), inserter(interSt, interSt.begin()));
        //set_union(st[a].begin(), st[a].end(), st[b].begin(), st[b].end(), inserter(unionSt, unionSt.begin()));
        printf("%.1f%%\n",interSt.size() * 100.0 / (st[a].size() + st[b].size() - interSt.size()));
    }
}
10.4 A1060 Are They Equal (25 分)

这题挺恶心的,陷阱很多,要考虑的细节也很多,自己代码逻辑太混乱了就不放上来了…

1060. Are They Equal (25)-PAT甲级真题(科学计数法)_柳婼 の blog-CSDN博客

也可以像算法笔记上把主题部分和指数部分分开考虑。

#include <iostream>
#include <cstring>
using namespace std;
int main() {
    int n, p = 0, q = 0;
    char a[10000], b[10000], A[10000], B[10000];
    scanf("%d%s%s", &n, a, b);
    int cnta = strlen(a), cntb = strlen(b);
    for(int i = 0; i < strlen(a); i++) {
        if(a[i] == '.') {
            cnta = i;
            break;
        }
    }
    for(int i = 0; i < strlen(b); i++) {
        if(b[i] == '.') {
            cntb = i;
            break;
        }
    }
    int indexa = 0, indexb = 0;
    while(a[p] == '0' || a[p] == '.') p++;
    while(b[q] == '0' || b[q] == '.') q++;
    if(cnta >= p)
        cnta = cnta - p;
    else
        cnta = cnta - p + 1;
    if(cntb >= q)
        cntb = cntb - q;
    else
        cntb = cntb - q + 1;
    if(p == strlen(a))
        cnta = 0;
    if(q == strlen(b))
        cntb = 0;
    while(indexa < n) {
        if(a[p] != '.' && p < strlen(a))
            A[indexa++] = a[p];
        else if(p >= strlen(a))
            A[indexa++] = '0';
        p++;
    }
    while(indexb < n) {
        if(b[q] != '.' && q < strlen(b))
            B[indexb++] = b[q];
        else if(q >= strlen(b))
            B[indexb++] = '0';
        q++;
    }
    if(strcmp(A, B) == 0 && cnta == cntb)
        printf("YES 0.%s*10^%d", A, cnta);
    else
        printf("NO 0.%s*10^%d 0.%s*10^%d" , A, cnta, B, cntb);
    return 0;
}
10.5 A1022 Digital Library (30 分)

主要考察了map的使用以及string类型的输入输出。

scanf中加上\n提前把换行符读取掉,防止其干扰后续的getline函数的读取。

拆分关键词可以在读取的过程中,使用while(cin >> tkey),读完一个单词后再读一个字符,判断这个字符如果是换行符就break。

还可以利用strtok函数,对输入进行分割。

scanf("%d\n", &id);

getline(cin, ttitle);
while(cin >> tkey) {
	key[tkey].insert(id);
	char c = getchar();
	if(c == '\n') break;
}


char* p;
const char* d = " ";
p = strtok(&keywords[0], d);
while(p)
{
	string keyword(p);
	keywordToid[keyword].insert(id);
	p=strtok(NULL,d);
} 
  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值