C++常见的STL用法(机试向)

写在前面

作为计算机相关专业的学生,无论是就业、考研复试、保研,机试都是一个很常见且重要的考核。其中一般OJ平台上C++、java是最常见的两种主流使用语言,考虑到性能运行速度的问题,我是主要使用C++作为主语言,下面结合自己平时刷acwing、PTA、蓝桥、力扣等平台程序设计算法题的一些经验,对C++中常见的STL 用法做一个大致的总结。本人小白,如果有问题欢迎大佬们批评指正!

常见STL

Vector

vector, 变长数组,倍增的思想,这个很常见,比一般数组好用很多!
常见函数如下:

size()  返回元素个数
empty()  返回是否为空
clear()  清空
front()/back()  返回第一个元素/返回最后一个元素
push_back()/pop_back()  在后面插入一个元素/删除最后一个元素
begin()/end()  返回数组开头的迭代器/返回数组结尾的迭代器
[]    支持像数组那样通过[]取元素
支持比较运算,按字典序

示例:


#include<bits/stdc++.h> 
using namespace std;
int main()
{
    vector<int> res{1,2,3,4,5};
    vector<int> a{6,7,8,9,10};
    for(int i = 0;i < 5;i++)
    {
        cout<<res[i]<<" ";
    }
    cout<<endl;
    cout<<res.size()<<endl; //size()返回元素个数
    cout<<res.empty()<<endl; //empty()返回是否为空
    res.clear();            //clear()清空数组
    cout<<res.empty()<<endl;
    for(int i = 1;i <= 5;i++)
    {
        res.push_back(i); //push_back()中加入元素
    }
    
    for(int i = 0;i < 5;i++)
    {
        cout<<res[i]<<" ";
    }
    cout<<endl;

    int k = 5;
    while(k--)
    {
        res.pop_back(); //pop_bcak()中弹出元素
    }
    cout<<res.size();
    cout<<endl;
    
    vector<int>::iterator it;
    for(auto it = a.begin();it != a.end();it++)  //begin()得到数组的头指针
    {                                           //end()得到数组的尾指针+1
        cout<<*it<<" ";
    }
    cout<<endl;
    cout<<a.front()<<" "; //front()弹出首元素
    cout<<a.back();  //back()弹出元素
}

在这里插入图片描述

pair

    pair<int, int>
    first, 第一个元素
    second, 第二个元素
    支持比较运算,以first为第一关键字,以second为第二关键字(字典序)
pair<T1, T2> p1;            //创建一个空的pair对象(使用默认构造),它的两个元素分别是T1和T2类型,采用值初始化。
pair<T1, T2> p1(v1, v2);    //创建一个pair对象,它的两个元素分别是T1和T2类型,其中first成员初始化为v1,second成员初始化为v2。
make_pair(v1, v2);          // 以v1和v2的值创建一个新的pair对象,其元素类型分别是v1和v2的类型。
p1 < p2;                    // 两个pair对象间的小于运算,其定义遵循字典次序:如 p1.first < p2.first 或者 !(p2.first < p1.first) && (p1.second < p2.second) 则返回true。
p1 == p2;                  // 如果两个对象的first和second依次相等,则这两个对象相等;该运算使用元素的==操作符。
p1.first;                   // 返回对象p1中名为first的公有数据成员
p1.second;                 // 返回对象p1中名为second的公有数据成员

示例:

int a = 8;
string m = "James";
pair<int, string> newone;
newone = make_pair(a, m);
cout << newone.first << newone.second << endl;
//output: 8 James

string

size()/length()  返回字符串长度
empty()   判空
clear()  清空
substr(起始下标,(子串长度))     返回子串
c_str()      返回字符串所在字符数组的起始地址
reverse(s.begin(),s.end())将字符串的[begin, end)的元素进行反转
append(),用于向string的后面追加字符或字符串,在string后面添加多个相同字符,例str.append(3,'!');
字符数组char name[3]之间的赋值strcpy(a,b)

queue, 队列

先进先出
size() 返回队列长度
empty() 判空
push() 向队尾插入一个元素
front() 返回队头元素
back() 返回队尾元素
pop() 弹出队头元素

priority_queue, 优先队列,默认是大根堆

std::priority_queue:在优先队列中,优先级高的元素先出队列,并非按照先进先出的要求,类似一个堆(heap)。其模板声明带有三个参数,priority_queue<Type, Container, Functional>, 其中Type为数据类型,Container为保存数据的容器,Functional为元素比较方式。Container必须是用数组实现的容器,比如 vector, deque. STL里面默认用的是vector. 比较方式默认用operator< , 所以如果把后面两个参数缺省的话,优先队列就是大顶堆,队头元素最大。

priority_queue(),默认按照从小到大排列。所以top()返回的是最大值而不是最小值!
使用greater<>后,数据从大到小排列,top()返回的就是最小值而不是最大值!
如果使用了第三个参数,那第二个参数不能省,用作保存数据的容器!!!!

priority_queue<int, greater<>> pq;//这是错误的
priority_queue<int,vector< int > , greater<>> pq;//这是对的

size()   返回大小
empty()  判空
push()  插入一个元素
top()  返回堆顶元素
pop()  弹出堆顶元素
定义成小根堆的方式:priority_queue<int, vector<int>, greater<int>> q;
优先队列的时间复杂度为O(logn),n为队列中元素的个数,其存取都需要时间。

产生原因:同样是为了提高数据处理的效率。试想,要实现优先队列对应的功能,若使用链表或者数组,那么要么先排序再插入,要么先插入再查找最大最小元素。这样一来,入队出队的时间复杂度至少为O(N)。

大根堆和小根堆的示例如下:

#include <bits/stdc++.h>
using namespace std;
 
int main()
{
	vector<int> aa = { 1,2,4,3,8,6,1,4 };
	priority_queue<int, vector<int>, greater<int>> pq;//小根堆, vector<int>
	priority_queue<int>pq2;    //大根堆 
	for (int i = 0; i < aa.size(); i++) {
		pq.push(aa[i]);
		pq2.push(aa[i]); 
	}
	for (int i = 0; i < aa.size(); i++){
		cout << pq.top();
		pq.pop();
	}
	cout<<endl;
	for(int i=0;i<aa.size();i++){
		cout<<pq2.top();
		pq2.pop();
	}
	//cout << pq << endl;
	system("pause");
	return 0;
}

stack, 栈

size()   返回栈的大小
empty()   返回栈是否为空
push()  向栈顶插入一个元素
top()  返回栈顶元素
pop()  弹出栈顶元素

deque, 双端队列

双端队列(deque)是一种随机访问的数据类型,提供了在序列两端快速插入和删除的功能,deque类似于vector。
size() 返回deque的大小
empty() 返回deque是否为空
clear() 返回是否为空
front()/back() 获取双端队列中第一个/最后一个元素
begin()/end() 双端队列中第一个元素/最后一个元素的引用
push_back()/pop_back() 在双端队列的后面增加/删除最后一个元素
push_front()/pop_front() 在双端队列的前面增加/删除第一个元素
[]

set, map, multiset, multimap,

基于平衡二叉树(红黑树),动态维护有序序列.
size()
empty()
clear()
begin()/end()
++, – 返回前驱和后继,时间复杂度 O(logn)

set/multiset

    insert()  插入一个数
    find()  查找一个数
    count()  返回某一个数的个数
    erase()
        (1) 输入是一个数x,删除所有x   O(k + logn)
        (2) 输入一个迭代器,删除这个迭代器
    lower_bound()/upper_bound()
        lower_bound(x)  返回大于等于x的最小的数的迭代器
        upper_bound(x)  返回大于x的最小的数的迭代器
set的定义方式
set<int> s1; //构造int类型的空容器
set<int> s2(s1); //拷贝构造int类型s1容器的复制品
string str("abcdef");
set<char> s3(str.begin(), str.end()); //构造string对象某段区间的复制品
set < int, greater<int>> s4; //构造int类型的空容器,比较方式指定为大于
//set中的元素默认按照小于来比较

set中的元素不可以重复(因此可以使用set进行去重)。

multiset容器与set容器的底层实现一样,都是平衡搜索树(红黑树),其次,multiset容器和set容器所提供的成员函数的接口都是基本一致的,multiset容器和set容器的唯一区别就是,multiset允许键值冗余,即multiset容器当中存储的元素是可以重复的。

关于set
set是按照一定次序存储元素的容器,在内部,set中的元素总是按照其内部比较对象(类型比较)所指示的特定严格弱排序准则进行排序。set容器通过key访问单个元素的速度通常比unordered_set容器慢,但它们允许根据顺序对子集进行直接迭代。与map/multimap不同,map/multimap中存储的是真正的键值对<key, value>,set中只放value,但 在底层实际存放的是由<value, value>构成的键值对。set中查找某个元素,时间复杂度为:log2 n。set中的元素不允许修改。

由于multiset容器允许键值冗余,因此两个容器中成员函数find和count的意义也有所不同:

  • 成员函数find
  • set对象 返回值为val的元素的迭代器
  • multiset对象 返回底层搜索树中序的第一个值为val的元素的迭代器
  • 成员函数count
  • set对象 值为val的元素存在则返回1,不存在则返回0(find成员函数可代替)
  • multiset对象 返回值为val的元素个数(find成员函数不可代替)

关于multiset
**使用迭代器对multiset中的元素进行遍历,可以得到有序的序列;**multiset中的元素不能修改;在multiset中找某个元素,时间复杂度为O(log2 n)。

map/multimap

        insert()  插入的数是一个pair
		{
			map<int ,string> mapstudent;
			Mapstudent.insert(make_pair(1,”student_one”);
		}
        erase()  输入的参数是pair或者迭代器
        find()
        []  注意multimap不支持此操作。 时间复杂度是 O(logn)
        lower_bound()/upper_bound()
        

unordered_set, unordered_map, unordered_multiset, unordered_multimap, 哈希表

用法基本同上面类似,但是底层实现不同,增删改查的时间复杂度是 O(1)
不支持 lower_bound()/upper_bound(), 迭代器的++,–

树形结构与哈希结构

据应用场景的不同,C++STL总共实现了两种不同结构的关联式容器:树型结构和哈希结构
在这里插入图片描述

高频易错问题

Scanf()输入string类型引发的问题

写在前面,一般不建议使用scanf()输入string类型,但是这个东西很容易出错,关键是使用scanf输入string类型时,且并没有开辟空间。所以简单介绍一下。
下面是一定正确的版本。

#include<bits/stdc++.h>
using namespace std;
int main(){
	string a;
	a.resize(6); //需要预先分配空间,超出空间会被截取
	scanf("%s",&a[0]);
	cout<<a;//用printf("%s",a.c_str())也可以输出
	return 0; 
}

下面是会出一些奇奇怪怪的问题的版本。

#include<bits/stdc++.h>
using namespace std;

int main(){
	string a;
	scanf("%s",a.c_str());
	printf("%s",a.c_str());
}

分析:上述如果没有预先开辟空间,我们从运行结果上看是正常的,但是如果我们将 printf(“%s”,a.c_str());改为cout<<a;则输出为空。
在一些情况下我们用scanf)利用刚才上述的方法输入string类型时(scanf(“%o”,a.c_str()),且并没有开辟空间,如果将输入的sting赋值给其他string类型时,则会出现赋值为空。但仅可以通过Printf(“%s”,A.C_str());进行输出(cout<a不行),仅此而已,a实际上仍为空)。因此在对字符串用scanf()进行输入时一定要进行开辟空间。具体底层原因请看下面的常见c_str()常见问题介绍。

printf输出string类型及c_str()函数部分要点

printf只能输出C语言内置的数据,而string不是内置的,只是一个扩展的类,直接输出肯定是错误的!

string test = "测试代码段";
printf("%s",test.c_str());

调用c_str()函数即可进行输出,同时使用cout也可以输出。
1.c_str()函数返回一个指向正规c字符串的指针,内容和string类的本身对象是一样的,通过string类的c_str()函数能够把string对象转换成c中的字符串的样式;

2.c_str()函数返回一个指向正规c字符串的指针, 内容与本string串相同.

这是为了与c语言兼容,在c语言中没有string类型,故必须通过string类对象的成员函数c_str()把string 对象转换成c中的字符串样式。
注意:一定要使用strcpy()函数 等来操作方法c_str()返回的指针

char p[20];
string test="test";
strcpy(p,test.c_str());
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值