C++的输入输出(ACM模式)

原文

1.输入

首先,在C++语言中,要使用标准的输入,需要包含头文件<iostream>

1.1cin

cin是c++中标准的输入流对象,cin有两个用法,单独读入和批量读入
cin的原理:简单来讲,有一个缓冲区,键盘输入的数据会先存到缓冲区,用cin可以从缓冲区中读取数据。
注意:

  • cin可以连续从键盘读入数据
  • cin以空格,tab,换行符作为分隔符
  • cin从第一个非空格字符开始读取,直到遇到分隔符结束读取
    示例:
// 用法1,读入单数据
int num;
cin >> num;
cout << num << endl;  // 输出读入的整数num

// 用法2,批量读入多个数据
vector<int> nums(5);
for(int i = 0; i < nums.size(); i++) {
	cin >> nums[i];
}
// 输出读入的数组
for(int i = 0; i < nums.size(); i++) {
	cout << nums[i] << " ";
}

1.2getline()

当读取的字符串中间存在空格时,cin会读取不全整个字符串,这个时候,需要用getline()
注意:

  • 使用getline()函数的时候,需要包含头文件<string>
  • getline()函数会读取一行,读取的字符串包括空格,遇到换行符结束。
    示例:
string s;
getline(cin, s);
// 输出读入的字符串
cout << s << endl;

1.3getchar()

该函数会从缓冲区读出一个字符,异常被用于判断是否换行

char ch;
ch = getchar();
// 输出读入的字符
cout << ch << endl;

注意:
getline会读取一行字符串(包括空格)遇到回车结束,getline(cin, s)会获取前一个输入的换行符,需要在前面添加读取换行符的语句,如getchar()或cin.get()
在这里插入图片描述cin与getline()混用
cin输入完后,回车,cin遇到回车结束输入,但回车还在输入流中,cin不会清除,导致getline()读取回车,结束。需要在cin后面加cin.ignore();主动删除输入流中的换行符

2.输出

同样的,在C++语言中,要使用标准的输出,也需要包含头文件<iostream>
输出这边,主要介绍一个函数,就是用的最多的cout,需要注意的是,如果输出endl对象的时候,会输出一个换行符,类似\n
示例:

string s = "hello, Irray~";
// 看看二者有何不同
cout << "hello, Irray~";
cout << s << endl;

3.案例

3.1一维数组

此类输入,每个元素为一个int或char

3.1.1固定数目

输入格式1:

3
1 2 3

输入格式2:

3 1 2 3

解析:
对于第一组,第一行的3为整数的个数,第二行为三个用空格隔开的整数,因此可以采用cin来进行读取
对于第二组,第一行的3为整数的个数,空格后面的数据为三个用空格隔开的整数,因此可以采用cin来进行读取
此类问题,可以先创建一个vector,大小设置为给定值,然后通过for循环来循环输入

int n;
cin >> n; // 读入3,说明数组的大小是3
vector<int> nums(n); // 创建大小为3的vector<int>
for(int i = 0; i < n; i++) {
	cin >> nums[i];
}

// 验证是否读入成功
for(int i = 0; i < nums.size(); i++) {
	cout << nums[i] << " ";
}
cout << endl;

3.1.2不固定数目

输入格式:

1 2 3 4

解析:输入数据为四个用空格间隔的整数,没有指定整数个数,可以用while循环结合cin来处理

vector<int> nums;
int num;
while(cin >> num) {
	nums.push_back(num);
	// 读到换行符,终止循环
	if(getchar() == '\n') {
		break;
	}
}
// 验证是否读入成功
for(int i = 0; i < nums.size(); i++) {
	cout << nums[i] << " ";
}
cout << endl;

3.2二维数组

除了一维数组这种最基础的输入外,还会考察二维数组的输入,尤其是在dfs、dp类型的题目中。
二维数组主要有两种方式:常规模式和每一行数据是逗号隔开的整数

3.2.1常规模式

输入格式:

2 3
1 2 3
1 2 3

第一行的2,代表数据为2行,3代表数据为3列,因此根据第一行,可以得出,所输入数据为2行3列的二维数组。接下来的6个数字,就是按照空格和换行符分隔开的2x3二维数组,因此用for循环和cin即可处理

int m; // 接收行数
int n; // 接收列数

cin >> m >> n;

vector<vector<int>> matrix(m, vector<int>(n));

for(int i = 0; i < m; i++) {
	for(int j = 0; j < n; j++) {
		cin >> matrix[i][j];
	}
}

// 验证是否读入成功
for(int i = 0; i < m; i++) {
	for(int j = 0; j < n; j++) {
		cout << matrix[i][j] << " ";
	}
	cout << endl;
}

3.2.2每一行数据是逗号隔开的整数

输入格式:

2 3
1,2,3
1,2,3

解析:
第一行的2,代表数据为2行,3代表数据为3列,因此根据第一行,可以得出,所输入数据为2行3列的二维数组。接下来的2行,分别是一个字符串,字符串中用逗号隔开每个整数。这里采用读入字符串的方式,并将读入的字符串进行按逗号分开。

int m; // 接收行数
int n; // 接收列数

cin >> m >> n;

vector<vector<int>> matrix(m);

for(int i = 0; i < m; i++) {
    // 读入字符串
	string s;
	getline(cin, s);
	
	// 将读入的字符串按照逗号分隔为vector<int>
	vector<int> vec;
	int p = 0;
	for(int q = 0; q < s.size(); q++) {
		p = q;
		while(s[p] != ',' && p < s.size()) {
			p++;
		}
		string tmp = s.substr(q, p - q);
		vec.push_back(stoi(tmp));
		q = p;
	}
	
	//写入matrix
	matrix[i] = vec;
	vec.clear();
}

// 验证是否读入成功
for(int i = 0; i < matrix.size(); i++) {
	for(int j = 0; j < matrix[i].size(); j++) {
		cout << matrix[i][j] << " ";
	}
	cout << endl;
}

3.3字符串

3.3.1单字符串

输入格式:

abc

解析:
用cin读入即可

string s;
cin >> s;

// 验证是否读入成功
cout << s << endl;

3.3.2给定数目多字符串

输入格式:

3 abc ab a

第一行的3,代表有3个字符串,后续为用空格隔开的3个字符串,采用for循环和cin读入即可

int n;
cin >> n; // 读入3,说明字符串数组的大小是3
vector<string> strings(n); // 创建大小为3的vector<string>
for(int i = 0; i < n; i++) {
	cin >> strings[i];
}

// 验证是否读入成功
for(int i = 0; i < strings.size(); i++) {
	cout << strings[i] << " ";
}
cout << endl;

3.3.3不给定数目多字符串

输入格式:

abc ab a d

解析:
输入为用空格隔开的若干个字符串。

vector<string> strings;
string str;
while(cin >> str) {
	strings.push_back(str);
	// 读到换行符,终止循环
	if(getchar() == '\n') {
		break;
	}
}

// 验证是否读入成功
for(int i = 0; i < strings.size(); i++) {
	cout << strings[i] << " ";
}
cout << endl;

3.3.4字符串转整数数组

输入格式:

11,22,3,4

解析:
输入为一个完整字符串,字符串内容是按照逗号隔开的一个数组,可以先读入完成字符串,然后根据逗号进行分隔

vector<int> vec;

// 读入字符串
string s;
getline(cin, s);

// 将读入的字符串按照逗号分隔为vector<int>
	int p = 0;
	for(int q = 0; q < s.size(); q++) {
		p = q;
		while(s[p] != ',' && p < s.size()) {
			p++;
		}
		string tmp = s.substr(q, p - q);
		vec.push_back(stoi(tmp));
		q = p;
	}

// 验证是否读入成功
for(int i = 0; i < vec.size(); i++) {
	cout << vec[i] << " ";
}
cout << endl;

4.常见数据结构定义

4.1链表

#include <iostream>
using namespace std;

// 链表定义,并给出两个有参构造函数
struct ListNode
{
    int val;
    ListNode* next;
    ListNode(int _val):val(_val),next(nullptr){}
    ListNode(int _val,ListNode* _next):val(_val),next(_next){}
};

int main()
{

	// 根据控制台的输入,创建一条单链表
    ListNode* LHead = new ListNode(-1);
    ListNode* pre = LHead;
    ListNode* cur = nullptr;
    
    int num;
    while(cin >> num)
    {
    	// 为了简单起见,设置为-1退出,后续可优化,这里只是给出一个例子
        if(num == -1) break;
        cur = new ListNode(num);
        pre->next = cur;
        pre = cur;
    }
    
    cur = LHead->next;
    
    // 输出单链表的value
    while(cur)
    {
        cout << cur->val << " ";
        cur = cur->next;
    }
    
    cout << endl;
    
    return 0;
}

4.2二叉树

#include <iostream>
#include <vector>
#include <queue>

using namespace std;

//定义树节点
struct TreeNode
{
    int val;
    TreeNode* left;
    TreeNode* right;
    TreeNode():val(0),left(nullptr),right(nullptr){}
    TreeNode(int _val):val(_val),left(nullptr),right(nullptr){}
    TreeNode(int _val,TreeNode* _left,TreeNode* _right):val(0),left(_left),right(_right){}
};

//根据数组生成树
TreeNode* buildTree(const vector<int>& v)
{
    vector<TreeNode*> vTree(v.size(),nullptr);
    TreeNode* root = nullptr;
    for(int i = 0; i < v.size(); i++)
    {
        TreeNode* node = nullptr;
        if(v[i] != -1)
        {
            node = new TreeNode(v[i]);
        }
        vTree[i] = node;
    }
    root = vTree[0];
    for(int i = 0; 2 * i + 2 < v.size(); i++)
    {
        if(vTree[i] != nullptr)
        {
            vTree[i]->left = vTree[2 * i + 1];
            vTree[i]->right = vTree[2 * i + 2];
        }
    }
    return root;
}

//根据二叉树根节点层序遍历并打印
void printBinaryTree(TreeNode* root)
{
    if(root == nullptr) return;
    vector<vector<int>> ans;
    queue<TreeNode*> q;
    q.push(root);
    while(!q.empty())
    {
        int size = q.size();
        vector<int> path;
        for(int i = 0;i<size;i++)
        {
            TreeNode* node = q.front();
            q.pop();
            if(node == nullptr)
            {
                path.push_back(-1);
            }
            else
            {
                path.push_back(node->val);
                q.push(node->left);
                q.push(node->right);
            }
        }
        ans.push_back(path);
    }
    
    for(int i = 0;i<ans.size();i++)
    {
        for(int j = 0;j<ans[i].size();j++)
        {
            cout << ans[i][j] << " ";
        }
        cout << endl;
    }
    return;
}

int main()
{
	// 验证
    vector<int> v = {4,1,6,0,2,5,7,-1,-1,-1,3,-1,-1,-1,8};
    TreeNode* root = buildTree(v);
    printBinaryTree(root);
    
    return 0;
}

ACM模式练习

牛客

A+B(1)

#include <iostream>
using namespace std;

int main(void)
{
    int a, b;
    while (cin >> a >> b)
    {
        cout << a+b << endl;
    }
    return 0;
}

A+B(2)

#include <iostream>
using namespace std;

int main(void)
{
    int n;
    cin >> n;
    int a, b;
    while(cin >> a >> b)
    {
        cout << a + b << endl;   
    }
    return 0;
}

A+B(3)

#include <iostream>
using namespace std;

int main(void)
{
    int a, b;
    while(cin >> a >> b)
    {
        if (a == 0 && b == 0)
        {
            break;
        }
        cout << a + b << endl;
    }
    return 0;
}

A+B(4)

#include <iostream>
using namespace std;

int main(void)
{
    int n;
    while (cin >> n)
    {
        if (n == 0)
        {
            break;
        }
        int sum = 0;
        for(int i = 0; i < n; i++)
        {
            int num;
            cin >> num;
            sum += num;
        }
        cout << sum << endl;     
    }
        
    return 0;
}

A+B(5)

#include <iostream>
using namespace std;

int main(void)
{
    int groups;
    cin >> groups;
    while(groups--)
    {
        int n;
        while(cin >> n)
        {
            int sum = 0;
            while(n--)
            {
                int num;
                cin >> num;
                sum += num;
            }
            cout << sum << endl;
        }
    }
    return 0;
}

A+B(6)

#include <iostream>
using namespace std;

int main(void)
{
    int n;
    while (cin >> n)
    {
        int sum = 0;
        for(int i = 0; i < n; i++)
        {
            int num;
            cin >> num;
            sum += num;
        }
        cout << sum << endl;     
    }
        
    return 0;
}

A+B(7)(*)

#include <iostream>
using namespace std;

int main(void)
{
        int sum = 0;
        int num;
        while(cin >> num)
        {
            sum += num;
            if (getchar() == '\n')
            {
                cout << sum << endl;
                sum = 0;            
            }
        }
    return 0;
}

字符串排序(1)

#include <iostream>
#include <string>
#include <vector>
#include <algorithm>
using namespace std;

int main(void)
{
    int n;
    cin >> n;
    vector<string> str(n);
    
    for(int i = 0; i < n; i++)
    {
        cin >> str[i];
    }
    sort(str.begin(), str.end());
    
    for(int i = 0; i < n; i++)
    {
        cout << str[i] << " ";
    }

    return 0;
}

注意:vector<string> str(n);在初始化时给vector分配n个元素的空间,老是忘记,导致索引访问时越界。

字符串排序(2)(*)

#include <iostream>
#include <vector>
#include <string>
#include <algorithm>
using namespace std;

int main(void)
{
    string str;
    vector<string> strs;
    while(cin >> str)
    {
        strs.push_back(str);
        if (getchar() == '\n')
        {
            sort(strs.begin(), strs.end());
            for (int i = 0; i < strs.size() - 1; i++)
            {
                cout << strs[i] << ' ';
            }
            cout << strs[strs.size() - 1] << endl;
            strs.clear();
        }      
    }
    return 0;
}

一开始,输出不符合题目要求

for(auto s: strs)
{
	 cout << s << ' ';
}
cout << endl

这样输出会导致最后一个字符串后面有空格后换行,不符号要求
应该先将最后一个字符串之间的字符先输出,最后将最后一个字符串输出,然后换行,即换行符和最后一个字符串之间无空格。

字符串排序(3)(*)

#include <iostream>
#include <string>
#include <vector>
#include <algorithm>
using namespace std;

int main(void)
{
    string str;
    while(getline(cin, str))
    {
        vector<string> s;
        int j = 0;
        for(int i = 0; i < str.size(); i = j + 1)
        {
            j = i;
            while (j < str.size() && str[j] != ',')
            {
                j++;
            }
            string temp = str.substr(i, j - i);
            s.push_back(temp);
            //i = j + 1;
        }
        sort(s.begin(), s.end());
        for (int i = 0; i < s.size() - 1; i++)
        {
            cout << s[i] << ',';
        }
        cout << s[s.size() - 1] << endl;                
    }
    return 0;
}

在分割字符串的时候,出了问题,一开始在更新i的时候,写的是i=j+1,但是i在进入for循环的时候,会执行i++,导致错误,应该改成i=j或者直接在for循环中将i的更新改为i=j+1

### C++ACM竞赛中的输入输出方法 在ACM竞赛中,高效的输入输出方法对于程序性能至关重要。以下是几种常见的C++输入输出方式及其优缺点: #### 1. 使用标准库 `cin` 和 `cout` 这是最基础的输入输出方法,适合初学者使用。然而,在处理大量数据时,其效率较低。 ```cpp #include <iostream> using namespace std; int main() { ios::sync_with_stdio(false); // 关闭同步以提高速度 cin.tie(NULL); // 解绑 cin 和 cout 的关联 int n; while(cin >> n) { // 输入直到文件结束符 cout << n * 2 << endl; // 输出结果 } return 0; } ``` 关闭同步和解绑可以显著提升运行时间[^1]。 #### 2. 使用缓冲区读取与解析 当需要快速读取大规模数据时,推荐使用自定义缓冲区配合字符串流或其他解析技术。这种方法能够大幅减少I/O操作的时间开销。 ```cpp #include <cstdio> #include <cstdlib> char buffer[100]; double value; int main(){ while(fscanf(stdin,"%s",buffer)!=EOF){ value = atof(buffer); printf("%f\n",value*2); } return 0; } ``` 上述代码展示了如何利用 `fscanf` 函数直接从标准输入读取字符串并转换成数值类型。相比其他高级封装函数如 `cin>>`, 这种原始接口提供了更高的执行效率。 #### 3. 文件流操作 虽然大多数情况下ACM题目会指定通过标准输入输出完成交互,但在某些特殊场景下可能允许选手自行设定临时文件作为媒介传递中间计算成果或者调试信息记录用途,则此时可考虑采用fstream类实现更灵活的数据交换机制。 需要注意的是,尽管这些技巧有助于优化算法表现,但实际比赛中更重要的是理解问题本质以及设计合理解决方案的能力。
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值