C++学习:输入输出和标准模板库STL
1 输入输出
ACM模式,找工作笔试常用,牛客输入输出练习
需要加入头文件:
#include <iostream>
连续输入的方法(可以用空格或者回车隔开):
//方法1
cin>>a>>b...;
//方法2
while(cin>>a){
//读取a
}
注意:第二种方式是退出不了循环的,但是ACM模式是允许这种方式输入的。
问题1:输入多行怎么按行操作呢?
形如:牛客输入输出练习的第7题
输入描述:
输入数据有多组, 每行表示一组输入数据。
每行不定有n个整数,空格隔开。(1 <= n <= 100)。
输出描述:
每组数据输出求和的结果
示例:
输入
1 2 3
4 5
0 0 0 0 0
输出
6
9
0
回答1:使用cin.get()
cin.get()
的详细用法看这个博客
while(cin>>a)//接收输入数据
{
while(cin.get()!='\n')//判读输入的数据是否有换行符
{
//这里按行处理输入a
}
}
问题2:怎么处理以其他符号(如:','等)分隔的输入?
形如:牛客输入输出练习字符串排序(3)
输入描述:
多个测试用例,每个测试用例一行。
每行通过,隔开,有n个字符,n<100
输出描述:
对于每组用例输出一行排序后的字符串,用’,'隔开,无结尾空格
示例:
输入
a,c,bb
f,dddd
nowcoder
输出
a,bb,c
dddd,f
nowcoder
回答2:使用sstream处理
直接上代码:
#include<iostream>
#include<string>
#include<vector>
#include<algorithm>
#include<sstream> //要加入sstream头文件
using namespace std;
int main()
{
vector<string> st;
string s,a;
while(getline(cin,s)) //输入时按行输入,即:一行输入转化成一条字符串数据
{
stringstream ss(s); //转化成stringstream数据格式
while(getline(ss,a,',')) //将数据按照','分隔开
{
st.push_back(a); //获取分隔后的每个数据
}
sort(st.begin(),st.end());
for(int i=0;i<st.size();++i)
{
if(i==st.size()-1)
{
cout<<st[i]<<endl;
}else{
cout<<st[i]<<',';
}
}
st.clear();
}
return 0;
}
可以将以上数据推广到处理任何有特殊分隔符的字符串数据
#include<sstream> //要加入sstream头文件
stringstream ss(s); //转化成stringstream数据格式
while(getline(ss,a,',')) //将数据按照','分隔开
{
//获取分隔后的每个数据
}
2 标准模板库
C++ 标准模板库(Standard Template Library,STL)是一套功能强大的 C++ 模板类和函数的集合,它提供了一系列通用的、可复用的算法和数据结构。
这里主要记录:包括容器(Containers)和算法(Algorithms)
容器是 STL 中最基本的组件之一,提供了各种数据结构,包括向量(vector)、链表(list)、队列(queue)、栈(stack)、集合(set)、映射(map)等。
STL 提供了大量的算法,用于对容器中的元素进行各种操作,包括排序、搜索、复制、移动、变换等。
2.1 向量(vector)
这篇博客讲得不错
2.1.1 向量的声明和初始化
/* 初始化vector对象的方法,其中T是type数据类型 */
vector<T> v1 ; //v1是一个空的vector,它潜在的元素是T类型的,执行默认初始化
vector<T> v2(n) ; //v2包含了n个重复地执行了值初始化的对象
vector<T> v3(n, val) ; //声明一个初始大小为n且初始值都为val的向量
vector<T> v4 = {a,b,c,...} //每个元素给赋予对应的初值
vector<T> v5(v4.begin(), v4.begin()+3) ; //将v4向量中从第0个到第2个(共3个)作为向量v5的初始值
2.1.2 向量的基本操作
//---- 基本操作 ----
* v.size() //返回向量v中的元素个数
* v.empty() //若v中不包含任何元素,返回真;否则返回假
* v.push_back(t) //向v的尾端添加一个值为t的元素
v.front() //访问v的第一个元素
v.back() //访问v的最后一个元素
v[n] //返回v中第n个位置上元素的应用
v.pop_back() //删除vector尾最后一个元素
v.erase(v.begin()+n) //删除第n个元素,如果是两个数n1~n2,则删除该范围的数
* v.clear() //清除所有元素
v.insert() //插入一个或多个对象
2.1.3 向量的遍历访问
vector<int> vec = {1, 2, 3, 4, 5};
//第一种方式
for (int num : vec) {
cout << num << endl;
}
for (const auto &num: vec) cout << num << endl;
//第二种方式
for (size_t i = 0; i < vec.size(); ++i) {
cout << vec[i] << endl;
}
//第三种方式
for (auto it = vec.begin(); it != vec.end(); ++it) {
cout << *it << endl;
}
//倒序遍历
for (auto it = vec.rbegin(); it != vec.rend(); ++it) {
cout << *it << endl;
}
2.1.4 二维向量
声明方式
vector< vector<int> > b(10, vector<int>(5)); //创建一个10*5的int型二维向量
注意:二维向量第一个维度是vector类型,所以添加元素(push_back(t))时t的数据类型要为vector类型
2.2 链表(list&forward_list)
2.2.1 list
list是双链表,可以向前和向后遍历元素。
基本操作:
list<T> mylist; //声明列表,其中 `T` 是存储在列表中的元素类型。
mylist.push_back(value); //尾端添加一个值为value的元素
mylist.pop_back(); | mylist.erase(iterator); //删除元素
mylist.front(); | mylist.back(); //访问元素
for (auto it = mylist.begin(); it != mylist.end(); ++it)//遍历列表:使用迭代器
注意:list最先入表的是表头(和数据结构中的链表相反)
2.2.2 forward_list
forward_list是单链表,只能从前往后遍历,不能反向遍历。
基本操作
forward_list<T> flist; //声明
flist.push_front(const T& value) //在列表的前端插入一个元素。
flist.pop_front() //移除列表前端的元素。
for (auto it = flist.begin(); it != flist.end(); ++flist) //遍历
注意:forward_list最后入表的是表头(和数据结构中的链表相同)
2.3 队列(queue)
C++ 标准库中的 <queue>
头文件提供了队列(Queue)数据结构的实现。队列是一种先进先出(FIFO, First In First Out)的数据结构,它允许在一端添加元素(称为队尾),并在另一端移除元素(称为队首)。
队列是一种线性数据结构,它遵循以下规则:
- 元素只能从队尾添加。
- 元素只能从队首移除。
基本操作:
queue<Type> q; // 声明队列
empty() //检查队列是否为空。
size() //返回队列中的元素数量。
front() //返回队首元素的引用。
back() //返回队尾元素的引用。
push() //在队尾添加一个元素。
pop() //移除队首元素。
while(!q.empty()) //队列遍历
{
cout<<q.front()<<" ";
q.pop();
}
2.4 栈(stack)
<stack>
是 C++ 标准模板库(STL)的一部分,它实现了一个后进先出(LIFO,Last In First Out)的数据结构。
基本操作
push() //在栈顶添加一个元素。
pop() //移除栈顶元素。
top() //返回栈顶元素的引用,但不移除它。
empty() //检查栈是否为空。
size() //返回栈中元素的数量。
if (!s.empty()) { //栈的遍历
cout << s.top() << endl;
s.pop();
}
2.5 集合(set)
C++ 标准库中的 <set>
是一个关联容器,它存储了一组唯一的元素,并按照一定的顺序进行排序。
常用操作
set<元素类型> 容器名; //声明
insert(元素) //插入一个元素。
erase(元素) //删除一个元素。
find(元素) //查找一个元素。
size() //返回容器中元素的数量。
empty() //检查容器是否为空。
// 查找元素
if (mySet.find(20) != mySet.end()) {
cout << "20 is in the set." << endl;
} else {
cout << "20 is not in the set." << endl;
}
// 遍历元素
for (int num : mySet) {
cout << num << " ";
}
set常用于去重的场景
例如给字符串去重
// 给字符串s去重,缺点是顺序会乱
set<char> uniqueViruses(s.begin(),s.end());
2.6 映射(map)
<map>
是标准模板库(STL)的一部分,它提供了一种关联容器,用于存储键值对(key-value pairs)。
定义和特性
- 键值对:
map
存储的是键值对,其中每个键都是唯一的。 - 排序:
map
中的元素按照键的顺序自动排序,通常是升序。 - 唯一性:每个键在
map
中只能出现一次。 - 双向迭代器:
map
提供了双向迭代器,可以向前和向后遍历元素。
基本操作
map<key_type, value_type> myMap; //声明
myMap[key] = value; //插入元素
value = myMap[key]; //访问元素
myMap.erase(key); //删除元素
myMap.clear(); //清空 map
myMap.size(); //获取 map 的大小
// 检查键是否存在
if (myMap.find(key) != myMap.end()) {
// 键存在
}
// 遍历
for (auto it = myMap.begin(); it != myMap.end(); ++it) {
cout << it->first << " => " << it->second << endl; //注意不能用'.'代替'->'
}
for (auto& e : myMap){ //注意要'&'
cout << e.first << " => " << e.second << endl;
}
map常用于统计的场景
2.7 其他比较重要的库
2.7.1 cmath
<cmath>
是一个包含数学函数的头文件,它提供了许多基本的数学运算和常数。
常用数学函数:
abs(x) //计算x的绝对值。
pow(x, y) //计算x的y次幂。
sqrt(x) //计算x的平方根。
sin(x) //计算x的正弦值(x以弧度为单位)。
cos(x) //计算x的余弦值(x以弧度为单位)。
tan(x) //计算x的正切值(x以弧度为单位)。
log(x) //计算x的自然对数。
exp(x) //计算e的x次幂。
2.7.2 new
<new>
是一个非常重要的头文件,它包含了用于动态内存分配的函数和异常类型。
<new>
头文件定义了以下几个关键组件:
new //运算符:用于动态分配内存。
delete //运算符:用于释放动态分配的内存。
nothrow //运算符:用于在内存分配失败时不抛出异常。
bad_alloc //异常:当内存分配失败时抛出。
2.7.3 climits
<climits>
是 C++ 标准库中的一个头文件,提供了与整数类型相关的限制和特性。
常用的常量:
短整型
SHRT_MIN //short 类型的最小值。
SHRT_MAX //short 类型的最大值。
USHRT_MAX //无符号 short 类型的最大值。
整型
INT_MIN //int 类型的最小值。
INT_MAX //int 类型的最大值。
UINT_MAX //无符号 int 类型的最大值。
长整型
LONG_MIN //long 类型的最小值。
LONG_MAX //long 类型的最大值。
ULONG_MAX //无符号 long 类型的最大值。
2.7.4 cstdlib
<cstdlib>
是 C++ 标准库中的一个头文件,提供了各种通用工具函数,包括内存分配、进程控制、环境查询、排序和搜索、数学转换、伪随机数生成等。
常用函数:
exit(int status) //终止程序执行,并返回一个状态码。
system(const char* command) //执行一个命令行字符串。
malloc(size_t size) //分配指定大小的内存。
free(void* ptr) // 释放之前分配的内存。
atoi(const char* str) //将字符串转换为整数。
atof(const char* str) //将字符串转换为浮点数。
rand() //生成一个随机数。
srand(unsigned int seed) //设置随机数生成器的种子。
3 算法库 algorithm
C++ 标准库中的 <algorithm>
头文件提供了一组用于操作容器(如数组、向量、字符串、列表等)的算法。这些算法包括排序、搜索、复制、比较等,它们是编写高效、可重用代码的重要工具。
3.1 排序算法
sort():对容器中的元素进行排序。
stable_sort():对容器中的元素进行稳定排序。
sort(v.begin(), v.end()); // 默认升序排序,stable_sort与这个相同
3.2 查找算法
find():查找容器中指定值的元素。
find_if():根据指定的条件查找容器中的元素。
count():计算容器中指定值的出现次数。
count_if():根据指定的条件查找容器中指定值的出现次数。
binary_search():在有序序列中进行二分查找。
lower_bound(): 查找有序序列中第一个不小于给定值的元素。
upper_bound(): 查找有序序列中第一个大于给定值的元素。
vector<int> v = {1, 2, 3, 4, 5};
auto it = find_if(v.begin(), v.end(), [](int n) {
return n > 3;
});
if (it != v.end()) cout << "Found value greater than 3: " << *it; // 输出: 4,即:返回满足条件的第一个元素
int count = count_if(v.begin(), v.end(), [](int n) {
return n % 2 == 0;
});
cout << "Number of even elements: " << count; // 输出: 2,即:有两个元素(2,4)满足函数条件
//binary_search只能对已排好序(只能是升序)的数组进行搜索,返回true或false
bool flag = binary_search(v.begin(), v.end(), 20);
//upper_bound函数只能对已排好序(必须是升序)的数组进行查找,返回目标数的地址,若没找到,返回最后一个元素的地址+该数组类型的字节(v.end())
auto p = upper_bound(v.begin(), v.end(), 20);
3.3 去重、删除和合并算法
merge():将两个有序序列合并成一个有序序列。
remove():删除容器中指定值的元素。
remove_if():根据指定的条件删除容器中的元素。
unique():去除容器中相邻的重复元素。
unique() 并不实际删除元素,而是重新排列容器中的元素,将重复元素移到容器的尾部,并返回一个迭代器,指向最后一个不重复的元素的下一个位置。为了完全删除重复元素,还需要结合容器的 erase
方法。
//remove_if和上面的带if的函数类似
vector<int> v = {1, 1, 2, 3, 3, 3, 4, 4, 5, 5};
auto new_end = unique(v.begin(), v.end());
v.erase(new_end, v.end());
for (const auto &i: v) cout << i << ' '; // 输出:1 2 3 4 5
3.4 复制、代替
copy():将一个容器的元素复制到另一个容器。
replace():将容器中指定值的元素替换为新值。
replace_if():根据指定的条件将容器中的元素替换为新值。
copy(src.begin(), src.end(), dest.begin());
//其他的和前面的类似
3.5 数值算法
accumulate():计算容器中元素的累加值。
min_element()、max_element():找到容器中最小和最大的元素。
min、max:找到容器中最小和最大的元素。
// 计算向量v的和
accumulate(v.begin(), v.end(), 0);
3.6 其他算法
reverse():反转容器中的元素顺序。
random_shuffle():随机打乱容器中的元素顺序。
for_each(): 对范围内的每个元素应用一个函数。
reverse(s.begin(), s.end()); //翻转整个字符串
random_shuffle(v.begin(), v.end()); //随机打乱向量
vector<int> v = {1, 2, 3, 4, 5};
for_each(v.begin(), v.end(), [](int &n) {
n *= 2;
});
for (const auto &i: v) cout << i << ' '; // 输出:2 4 6 8 10