C++学习:输入输出和标准模板库STL

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
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值