算法日志1:编程第一步,搞清读参数

前言

笔者上了几个月的班,昨天参加了一场笔试,感觉算法甚至编程语言的语法都忘光了(定义c语言数组想了十几分钟),于是痛定思痛,决心要把代码随想录的题刷一遍,系统的学一下算法。

笔者已经坚定决心,从本篇开始,不断记录自己的学习和思考过程(其实是大模型的思考过程!😃)


ACM 模式和 核心代码模式

ACM模式要自己处理系统输入输出, 核心代码模式是写一个核心函数



编程第一步,搞清读参数

C++ 的 cin/cout、C 的 scanf/printf、Python 的 sys.stdin/stdout 和 Shell 的标准输入输出(如管道和重定向)都是处理标准输入/输出(stdin/stdout)的工具,但它们在使用方式、性能、抽象层次和设计哲学上有显著区别和联系。以下是详细对比:


核心联系

  1. 统一的抽象概念
    所有工具都基于操作系统的标准输入/输出(stdin/stdout)概念,对应文件描述符 0(输入)和 1(输出)。

  2. 数据流方向一致
    均遵循“数据从 stdin 读取,处理后再写入 stdout”的流程。

  3. 可互相组合
    不同工具可通过管道(|)或重定向(<, >)协同工作。例如:

    # C++ 程序输出到 Python 脚本
    ./cpp_program | python3 script.py
    

主要区别

特性 C++ cin/cout C scanf/printf Python sys.stdin/stdout Shell 标准输入输出
语法风格 面向对象(运算符 >>/<< 函数式(格式字符串) 面向对象(文件对象方法) 命令式(管道 `
类型安全 是(自动类型推导) 否(需显式指定格式符,易出错) 是(动态类型) 无类型(纯文本流)
性能 较高(但默认同步 C 库,可能略慢) 最高(直接系统调用,无额外抽象) 较低(解释型语言,动态类型开销) 中等(依赖工具实现,如 grep/awk
缓冲机制 行缓冲(默认,可调整) 全缓冲(默认,可通过 fflush 控制) 全缓冲(可设置 flush=True 行缓冲(通常由工具自行管理)
错误处理 通过流状态(如 failbit)检查 通过返回值检查(如 scanf 返回成功数) 通过异常或返回值(如 read() 通过退出状态码($?
典型用途 类型安全的高性能 I/O 底层高效控制 快速开发和文本处理 文本流处理和工具组合
示例代码 cin >> x; cout << x; scanf("%d", &x); printf("%d", x); line = sys.stdin.readline() `cat file.txt

关键细节对比

1. 类型处理

  • C++cin >> x 根据 x 的类型自动解析输入(如 intstring),类型安全。
  • C:需显式指定格式符(如 %d%s),易因类型不匹配导致未定义行为。
  • Python:输入始终为字符串,需手动转换类型(如 int(input()))。
  • Shell:数据为纯文本流,需用工具(如 awk)解析类型。

2. 缓冲机制

  • C++cout 默认行缓冲(输出到终端时),但写入文件时为全缓冲;可通过 endlflush 强制刷新。
  • Cprintf 全缓冲,除非输出到终端(行缓冲);需手动调用 fflush(stdout)
  • Pythonprint 函数默认全缓冲,但可设置 flush=Truesys.stdout.write 需手动刷新。
  • Shell:管道中的工具通常行缓冲(如 grep),但某些工具(如 sed)可能全缓冲。

3. 性能考量

  • C/C++:适合处理大规模数据(如每秒百万级输入),但需避免频繁同步(如 sync_with_stdio(false))。
  • Python:处理大数据时性能较差,但可通过批量读取(如 sys.stdin.read())优化。
  • Shell:组合工具时性能取决于具体命令(如 awk 比纯 Shell 循环快)。

4. 错误处理

  • C++:通过 cin.fail() 检查输入错误,需手动清除状态(cin.clear())。
  • Cscanf 返回成功匹配的参数数量,需逐项检查。
  • Pythonsys.stdin.read() 可能抛出异常(如键盘中断),需 try/except 捕获。
  • Shell:通过 $? 获取上一个命令的退出状态(0 表示成功,非 0 表示失败)。

使用场景建议

  • 需要高性能和类型安全:优先选择 C++ cin/cout(关闭同步)或 C scanf/printf
  • 快速开发和文本处理:使用 Python sys.stdin 和字符串方法。
  • 组合现有工具处理文本流:Shell 管道和重定向(如 awk/sed)。
  • 混合语言协作:通过 stdin/stdout 跨语言传递数据(如 C++ 程序输出到 Python 脚本)。

示例:跨语言协作

# C 程序生成数据 → Python 处理 → Shell 过滤
./c_program | python3 script.py | grep "result"





c,c++, python输入输出函数的返回值详解:


C++ cincout

  1. cin >> var 的返回值

    • 类型istream&(输入流对象的引用)。

    • 行为:返回流对象本身,允许链式调用(如 cin >> a >> b;)。

    • 错误处理:可通过检查流状态判断是否成功:

      if (cin >> x) { /* 读取成功 */ }
      else { /* 失败(如类型不匹配或 EOF)*/ }
      
  2. cout << value 的返回值

    • 类型ostream&(输出流对象的引用)。
    • 行为:返回流对象本身,支持链式输出(如 cout << a << b;)。
    • 错误处理:通常不检查返回值,但可通过 cout.good() 检测流状态。

C 的 scanfprintf

  1. scanf 的返回值

    • 类型int

    • 行为:返回成功匹配并赋值的输入项数量。若遇到输入错误或 EOF,返回 EOF(通常是 -1)。

    • 示例

      int a, b;
      int result = scanf("%d %d", &a, &b);
      if (result == 2) { /* 成功读取两个整数 */ }
      else if (result == EOF) { /* 输入结束或错误 */ }
      
  2. printf 的返回值

    • 类型int

    • 行为:返回实际输出的字符数(不包括终止符 \0)。若出错(如格式化字符串无效),返回负数。

    • 示例

      int len = printf("Value: %d", 42); // len = 8("Value: 42" 共 8 字符)
      

Python 的 sys.stdinprint

  1. sys.stdin 的方法返回值

    • sys.stdin.read():返回整个输入内容(字符串),直到 EOF。

    • sys.stdin.readline():返回一行输入(包括换行符 \n),EOF 时返回空字符串 ''

    • 示例

      line = sys.stdin.readline()
      if line == '':  # 判断是否 EOF
          print("Input ended.")
      
  2. print 的返回值

    • 类型None

    • 行为print 是 Python 的函数,仅执行输出操作,没有返回值。

    • 示例

      result = print("Hello")  # result = None
      

关键对比表

函数/方法 返回值类型 返回值含义 错误处理
cin >> var istream& 返回流对象本身,用于链式操作 检查流状态(如 cin.fail()
cout << value ostream& 返回流对象本身,用于链式操作 通常忽略,可检查 cout.good()
scanf int 成功匹配的输入项数量 检查返回值是否等于预期参数数量
printf int 成功输出的字符数 检查是否为负数
sys.stdin.read() str 输入的全部内容(字符串) 空字符串表示 EOF
sys.stdin.readline() str 单行输入内容(含换行符) 空字符串表示 EOF
print() None 无返回值 异常可能由输出流引发(如 IOError)

常见场景示例

  1. C++ 读取直到 EOF

    int x;
    while (cin >> x) {  // 当读取失败(如 EOF)时退出循环
        // 处理 x
    }
    
  2. C 安全读取输入

    int a;
    if (scanf("%d", &a) != 1) {
        fprintf(stderr, "Invalid input!");
        exit(1);
    }
    
  3. Python 逐行读取输入

    import sys
    for line in sys.stdin:
        line = line.strip()
        if not line:
            break
        # 处理 line
    

总结

  • C/C++:通过返回值或流状态显式处理错误。
  • Python:输入方法返回字符串,需手动处理类型和 EOF;print 无返回值。
  • Shell:输入输出为纯文本流,依赖外部工具解析(如 awk 处理数值)。





不同语言stdin, stdout,stderr详解

在C++和Python中,标准输入(stdin)、标准输出(stdout)和标准错误(stderr)是三个独立的流。cincout 是C++中的标准输入输出流,而 scanfprintf 是C语言的标准输入输出函数。sys.stdinsys.stdoutsys.stderr 则是Python中的对应概念。

C++中的处理

标准输出 (cout) 和标准错误 (cerr)

  • std::cout:用于标准输出(通常是终端屏幕)。
  • std::cerr:用于标准错误输出(也是通常显示在终端屏幕上,但与标准输出分开)。

示例:

#include <iostream>

int main() {
    std::cout << "This is standard output." << std::endl;
    std::cerr << "This is standard error output." << std::endl;
    return 0;
}

使用 fprintf 处理 stderr

如果你使用的是C风格的I/O函数,可以使用 fprintf 来向 stderr 输出信息。

示例:

#include <cstdio>

int main() {
    printf("This is standard output.\n");
    fprintf(stderr, "This is standard error output.\n");
    return 0;
}

Python中的处理

标准输入 (sys.stdin)、标准输出 (sys.stdout) 和标准错误 (sys.stderr)

  • sys.stdin:用于标准输入。
  • sys.stdout:用于标准输出。
  • sys.stderr:用于标准错误输出。

示例:

import sys

sys.stdout.write("This is standard output.\n")
sys.stderr.write("This is standard error output.\n")

# 或者使用 print 函数指定文件参数
print("This is standard output.", file=sys.stdout)
print("This is standard error output.", file=sys.stderr)

总结

  • C++: 使用 std::coutstd::cerr 分别处理标准输出和标准错误输出。也可以使用 printffprintf(stderr, ...) 来分别处理标准输出和标准错误输出。
  • Python: 使用 sys.stdoutsys.stderr 分别处理标准输出和标准错误输出。可以通过 print 函数的 file 参数来指定输出流。

这些方法允许你将正常的程序输出和错误信息分离,这对于调试和日志记录非常有用。例如,你可以将正常的信息打印到控制台或日志文件,而将错误信息重定向到一个单独的日志文件中以便于分析。




代码实战


下面的所有代码均为自己手写,非官方参考答案,官方答案在这

第一题

1. A+B问题I
题目描述
你的任务是计算a+b。

输入描述
输入包含一系列的a和b对,通过空格隔开。一对a和b占一行。

输出描述
对于输入的每对a和b,你需要依次输出a、b的和。

如对于输入中的第二对a和b,在输出中它们的和应该也在第二行。

输入示例
3 4
11 40
输出示例
7
51

题解

C++:

#include<iostream>
using namespace std;
int main(){
    int a,b;
    while(cin>>a>>b){
        cout<<a+b<<'\n';
    }
}

C风格:

//代码1:

#include<cstdio>
using namespace std;
int main(){
    int a,b;
    while(scanf("%d%d",&a,&b) == 2){
        printf("%d\n",a+b);
    }

}

//代码2:
#include<cstdio>
using namespace std;
int main(){
    int a,b;
    while(scanf("%d%d",&a,&b) != EOF){
        printf("%d\n",a+b);
    }

}

python:

import sys


if __name__ =="__main__": 
    for line in sys.stdin:
        x,y = line.split(" ")
        #print(type(line))
        #print(line)
        print(int(x)+int(y))

第二题

2. A+B问题II
题目描述
计算a+b,但输入方式有所改变。

输入描述
第一行是一个整数N,表示后面会有N行a和b,通过空格隔开。

输出描述
对于输入的每对a和b,你需要在相应的行输出a、b的和。
如第二对a和b,对应的和也输出在第二行。
输入示例
2
2 4
9 21
输出示例
6
30
提示信息
注意,测试数据不仅仅一组。也就是说,会持续输入N以及后面的a和b

题解:

c&c++

#include<iostream>
#include<cstdio>
using namespace std;
/*int main(){
    int n,a,b;
    while(true){
        if(scanf("%d",&n) == 1){
            while(n--){
                scanf("%d%d",&a,&b);
                printf("%d\n",a+b);
            }   
        }
        else{
            break;
        }

    }

}*/

int main(){
    int n,a,b;
    while(cin>>n){
        while(n--){
            cin>>a>>b;
            cout<<a+b<<"\n";
        }
    }
}

python:

while 1:
    try:
        N = int(input())
        for i in range(N):
            l = list(map(int,input().split()))
            print(sum(l))
    except:
        break 

第三题

3. A+B问题III
题目描述
你的任务依然是计算a+b。

输入描述
输入中每行是一对a和b。其中会有一对是0和0标志着输入结束,且这一对不要计算。

输出描述
对于输入的每对a和b,你需要在相应的行输出a、b的和。
如第二对a和b,他们的和也输出在第二行。
输入示例
2 4
11 19
0 0
输出示例
6
30

题解:

python

while(1):
    mylist = list(map(int, input().split()))
    if mylist[0] == mylist[1] == 0:
        break;
    else:
        print(sum(mylist))

c++&c

#include<iostream>
using namespace std;
int main(){
    int a,b;
    while(true){
        cin>>a>>b;
        if(a==0&&b==0){
            break;
        }
        else{
            cout<<a+b<<endl;
        }
    }
}

第四题

4. A+B问题IV
题目描述
你的任务是计算若干整数的和。

输入描述
每行的第一个数N,表示本行后面有N个数。

如果N=0时,表示输入结束,且这一行不要计算。

输出描述
对于每一行数据需要在相应的行输出和。

输入示例
4 1 2 3 4
5 1 2 3 4 5
0 
输出示例
10
15

python

import sys
while(1):
    mylist = list(map(int, input().split()))
    if mylist[0] == 0:
        break
    print(sum(mylist[1:]))

c++

#include<iostream>
using namespace std;
int main(){
    int n;
    while(cin>>n && n!=0){
        int tmp;
        int sum = 0;
        while(n--){
            cin>>tmp;
            sum+=tmp;
        }
        cout<<sum<<endl;

    }
}

第五题

5. A+B问题VII
题目描述
你的任务是计算两个整数的和。
输入描述
输入包含若干行,每行输入两个整数a和b,由空格分隔。
输出描述
对于每组输入,输出a和b的和,每行输出后接一个空行。
输入示例
2 4
11 19
输出示例
6

30

题解

python

while 1:
    try:
        mylist = list(map(int, input().split()))
        print(sum(mylist),'\n')
    except:
        break

c++

#include<iostream>
using namespace std;
int main(){
    int a,b;
    while(cin>>a>>b){
        cout<<a+b<<"\n\n";
    }

}

第六题

6. A+B问题VIII
题目描述
你的任务是计算若干整数的和。
输入描述
输入的第一行为一个整数N,接下来N行每行先输入一个整数M,然后在同一行内输入M个整数。

输出描述
对于每组输入,输出M个数的和,每组输出之间输出一个空行。
输入示例
3
4 1 2 3 4
5 1 2 3 4 5
3 1 2 3
输出示例
10

15

6
提示信息
注意以上样例为一组测试数据,后端判题会有很多组测试数据,也就是会有多个N的输入
例如输入可以是:
3
4 1 2 3 4
5 1 2 3 4 5
3 1 2 3
3
4 1 2 3 4
5 1 2 3 4 5
3 1 2 3
输出则是
10

15

6
10

15

6
只保证每组数据间是有空行的。但两组数据并没有空行

题解

python

while 1:
    try:
        N = int(input())
        for i in range(N):
            fin = list(map(int,input().split()))
            print(sum(fin[1:]))
            if i != N-1:
                print()
    except:
        break

c++

#include<iostream>
using namespace std;
int main(){
    int n;
    while(cin>>n){
        int n_loop;
        int cnt_loop;
        int tmp_loop;
        while(n--){
            cin>>n_loop;
            cnt_loop = 0;
            while(n_loop--){
                cin>>tmp_loop;
                cnt_loop+=tmp_loop;
            }
            cout<<cnt_loop<<endl;
            if(n!=0){
                cout<<"\n";
            }
        }

    }
}

posted @ 2025-03-20 11:44  玉米面手雷王  阅读(121)  评论(0)    收藏  举报