8.12 STL 容器:vector、set、map等容器用法详解

一、序列容器 --vector

/*vector*/
#include<bits/stdc++.h>
using namespace std;
int main(){
	// 创建一个初始空间为3的vector,其元素的默认值是4; 线性复杂度
	vector<int>v1(3,4); 
	//vector列表初始化 
	vector<int>v2{1,2,3};
	//v.front() 返回首元素的引用; v.back() 返回末尾元素的引用
	cout<<v1.front()<<" "<<v2.front()<<endl; //4 1
	//v.at(pos) 返回容器中下标为 pos 的引用。如果数组越界抛出 std::out_of_range 类型的异常
	cout<<v2.at(1)<<endl;;//2
	//v[pos] 返回容器中下标为 pos 的引用。不执行越界检查。
	cout<<v2[0]<<endl;//1
	//v.data() 返回指向数组第一个元素的指针
	cout<<v2.data()<<endl; //0xbc1530
	
	//begin()返回指向首元素的迭代器,其中 *begin = front
	//end()返回指向数组尾端占位符的迭代器,注意是没有元素的
	//cout<<v1.begin()<<endl;//错误 
	
	//empty() 返回一个 bool 值,即 v.begin() == v.end(),true 为空,false 为非空
	if(v1.empty()) cout<<"v1为空"<<endl;
	else  cout<<"v1不为空"<<endl;
	//size() 返回容器长度(元素数量)
	cout<<v1.size()<<endl;
	
	//insert(const_iterator pos,int count,ele); 在迭代器指向的位置pos处插入count个元素ele
	//复杂度与 pos 距离末尾长度成线性而非常数的
	v1.insert(v1.begin(),2,5);
	cout<<v1[0]<<" "<<v1[1]<<" "<<v1[2]<<endl;//5 5 4
	//int count不写时默认为1 
	v1.insert(v1.begin(),6);
	cout<<v1[0]<<endl;//6
	
	//erase(const_iterator pos);删除迭代器指向的元素
	//复杂度与 pos 距离末尾长度成线性而非常数的
	v1.erase(v1.begin()+2);
	cout<<v1[2]<<endl;//4
	//erase(const_iterator begin,const_iterator end);删除迭代器从begin到end之间的元素
	v1.erase(v1.begin()+2,v1.end());
	cout<<v1.back()<<endl;//5
	
	//push_back() 在末尾插入一个元素,均摊复杂度为常数O(1),最坏为线性复杂度
	v1.push_back(8);
	cout<<v1.back()<<endl;//8
	//pop_back() 删除末尾元素,常数复杂度
	v1.pop_back();
	cout<<v1.back()<<endl;//5
	
	//clear() 清除所有元素
	v1.clear();
	if(v1.empty()) cout<<"v1为空"<<endl;//v1为空
	else  cout<<"v1不为空"<<endl;
} 
/*vector遍历*/
#include<bits/stdc++.h>
using namespace std;
int n;
vector<int>g[2000005];
int main(){
	cin>>n;
	for(int i=1;i<n;i++){
		int u,v;cin>>u>>v;
		g[u].push_back(v);
		g[v].push_back(u);
	}
	//for(int i=1;i<=n;i++){
		for(auto v:g[1]){
			cout<<v<<" ";//2 8
		}
		//cout<<endl;
	//}
	for(auto v:g[2]){
			cout<<v<<" ";//1 3 4
		}
		
/*
测试数据: 
10
1 2
2 3
2 4
3 5
4 6
4 7
1 8
8 9
8 10
	*/
} 

/*vector 数组遍历*/
#include<bits/stdc++.h>
using namespace std;
vector<int> v={2,4,1,5,7};
int main() {
	for(int i:v) cout<<i<<' '; //输出vector 数组元素 2 4 1 5 7 
	for(int i:v) cout<<i+1<<' ';//输出 3 5 2 6 8
}

二、关联式容器 

关联容器,含有键值类型对象的已排序集,搜索移除插入拥有对数复杂度

1.set

set 内部通常采用红黑树(平衡二叉树)实现。set 中不会出现值相同的元素,multiset有相同元素的两者基本相同

/*set*/
#include<bits/stdc++.h>
using namespace std;
int main(){
	set<int>s;
	if(s.empty()) cout<<"集合为空"<<endl;//集合为空
	else  cout<<"集合不为空"<<endl;
	
	//insert(x) 当容器中没有等价元素的时候,将元素 x 插入到 set 中
	s.insert(1);
	s.insert(2);
	s.insert(3);
	//insert 函数的返回值类型为 pair<iterator, bool> 
	//iterator 是一个指向所插入元素(或者是指向等于所插入值的原本就在容器中的元素)的迭代器,而 bool 则代表元素是否插入成功
	s.insert(1);//无报错信息
	
	//size() 返回容器内元素个数
	cout<<s.size()<<endl;//3 
	
	//count(x) 返回 set 内键为 x 的元素数量
	cout<<s.count(1)<<endl;//1
	
	//find(x) 在 set 内存在键为 x 的元素时会返回该元素的迭代器,否则返回 end()
	cout<<*s.find(2)<<endl;
	//begin()返回指向首元素的迭代器,其中 *begin = front
	//end()返回指向数组尾端占位符的迭代器,注意是没有元素的
	cout<<*s.begin()<<" "<<*s.end()<<endl;//1 3
	//s.front();不存在 
	
	//lower_bound(x) 返回指向首个不小于(>=)给定键的元素的迭代器。如果不存在这样的元素,返回 end()
	cout<<*s.lower_bound(1)<<endl; //1
	//upper_bound(x) 返回指向首个大于(>)给定键的元素的迭代器。
	cout<<*s.upper_bound(1)<<endl; //2
	//如果不存在这样的元素,返回 end()。lower_bound(x) upper_bound(x)
	cout<<*s.upper_bound(5)<<endl; //3
	//set 自带的 lower_bound 和 upper_bound 的时间复杂度为 O(log n)
	
	/*错误 
	//在贪心算法中经常会需要出现类似 找出并删除最小的大于等于某个值的元素。这种操作能轻松地通过 set 来完成。
	set<int>::iterator it=s.lower_bound(4);
	if(it==s.end()) cout<<"YES"<<endl;//YES
	else cout<<"NO"<<endl;
	*/
} 
/*遍历set容器*/
#include<bits/stdc++.h>
using namespace std;
int main(){
	vector<int>v;
	for(int i=2;i<=5;i++){
		v.push_back(i);
	}
	set<int>s(v.begin(),v.end());
	for(auto i:s) cout<<i<<" ";//2 3 4 5
} 
/*set与unordered_set对元素排序问题*/
#include<bits/stdc++.h>
using namespace std;
int main(){
	/*vector<int>v;
	for(int i=2;i<=5;i++){
		v.push_back(i);
	}
	set<int>s(v.begin(),v.end());*/
	set<int>s;
	s.insert(5); 
	s.insert(4);
	s.insert(3);
	for(auto i:s) cout<<i<<" ";//3 4 5
	cout<<endl;
	unordered_set<int>s1;
	s1.insert(6); 
	s1.insert(4);
	s1.insert(9);
	for(auto i:s1) cout<<i<<" ";//9 4 6(也许这个顺序,顺序不定,受哈希函数的影响)
} 

2.map

map 是有序键值对容器,它的元素的键是唯一的。搜索、移除和插入操作拥有对数复杂度map 通常实现为红黑树。multimap 中允许多个元素拥有同一键,两者使用方法基本相同。

map<Key, T> yourMap;//Key 是键的类型(下标,也就是索引),T 是值的类型

/*map:map<Key, T> yourMap;Key 是键的类型,T 是值的类型*/
#include<bits/stdc++.h>
using namespace std;
int main(){
	map<string,int>mp;//下标为 string
	//可以直接通过下标访问来进行查询或插入操作
	mp["Alan"]=100;
	mp["Alice"]=95;
	mp["Tom"]=90;
	cout<<mp["Alan"]<<endl;//100
	
	//通过向 map 中插入一个类型为 pair<Key, T> 的值可以达到插入元素的目的
	mp.insert(pair<string ,int>("Bob",90));//mp.insert("Bob",90);错误
	cout<<mp["Bob"]<<endl; //90
	
	/*当下标访问操作过于频繁时,容器中会出现大量无意义元素,影响 map 的效率。
	因此一般情况下推荐使用 find() 函数来寻找特定键的元素。*/
	
	//find(x): 若容器内存在键为 x 的元素,会返回该元素的迭代器;否则返回 end()
	cout<<mp.find("Alice") ->second<<endl;//95
	
	//erase(key) 函数会删除键为 key 的 所有 元素。返回值为删除元素的数量---使用关键字删除 
	cout<<mp.erase("Bob")<<endl;//1
	//cout<<mp.begin()<<endl;错误 
	//erase(pos): 删除迭代器为 pos 的元素,要求迭代器必须合法---使用迭代器删除 
	mp.erase(mp.find("Alice"));//mp.erase(mp.begin()+1);错误
	if(mp.find("Alice")!=mp.end())  cout<<mp.find("Alice") ->second<<endl;
	else cout<<"不能找到"<<endl;//不能找到
	
	//clear() 函数会清空整个容器、empty(): 返回容器是否为空、 size(): 返回容器内元素个数
	
	//count(x): 返回容器内键为 x 的元素数量。复杂度为O(log(size)+ans) (关于容器大小对数复杂度,加上匹配个数)
	cout<<mp.count("Alice")<<endl;//0
	cout<<mp.count("Alan")<<endl;//1
	
	//lower_bound(x):>=  upper_bound(x):>
	cout<<mp.upper_bound("Alan")->second<<endl;//90

} 
/*vector遍历*/
#include<bits/stdc++.h>
using namespace std;
int n;
vector<int>g[2000005];
int main(){
	cin>>n;
	for(int i=1;i<n;i++){
		int u,v;cin>>u>>v;
		g[u].push_back(v);
		g[v].push_back(u);
	}
	//for(int i=1;i<=n;i++){
		for(auto v:g[1]){
			cout<<v<<" ";//2 8
		}
		//cout<<endl;
	//}
	/*
10
1 2
2 3
2 4
3 5
4 6
4 7
1 8
8 9
8 10
	*/
} 

三、无序关联式容器

无序关联式容器unordered_setunordered_multisetunordered_mapunordered_multimap是基于哈希实现的,大多数操作(包括查找,插入,删除)都能在常数时间复杂度内完成,相较于关联式容器与容器大小成对数的时间复杂度更好。它们与相应的关联式容器在功能,函数等方面有很多共同点。

四、容器适配器(依赖于其他容器作为底层来实现)

栈 (std::stack)、队列 (std::queue)、优先队列(priority_queue)

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值