Scanner和BufferReader的效率问题

时间:2023-12-30 10:48:14

先给出一道题,测试平台是Acwing, 这道题是腾讯2019年春招提前批笔试第二题。题目不难,但是如果不注意细节,很容易TLE(超时)

https://www.acwing.com/problem/content/570/

下面的做法是用JAVA scanner依次读入输入数据,但这样做的效率较低,会直接导致TLE:

 import java.util.Scanner;

 public class Main {
public static void main(String[] args) {
Scanner in = new Scanner(System.in);
int n = in.nextInt();
for(int i = 1; i <= n; i++){
int l = in.nextInt();
int r = in.nextInt(); int sum1 = 0;
int sum2 = 0;
if(r%2 == 0)
sum1 = r/2;
else
sum1 = r/2-r;
if((l-1)%2==0)
sum2 = l/2;
else
sum2 = l/2-l; System.out.println(sum1-sum2);
}
}
}

结果如下所示,在读入超过10万行的输入的时候直接超时

Scanner和BufferReader的效率问题

好的做法是使用BufferedReader来读输入,以下代码AC

 import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader; public class Main { public static void main(String[] args) throws IOException {
BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
int q = Integer.valueOf(br.readLine());
while (q-- > 0) {
String[] parts = br.readLine().split(" ");
int l = Integer.valueOf(parts[0]);
int r = Integer.valueOf(parts[1]); int k = (r-l+1)/2;
int res = 0;
if(l%2==0)
res = -k;
else
res = k;
if((r-l+1)%2==1){
if(r%2==0)
res += r;
else
res -=r;
}
System.out.println(res);
}
}
}

代码通过:

Scanner和BufferReader的效率问题

可能有人觉得Scanner我也可以使用整行读入的方式呀,可是这样仍然会TLE:

 import java.util.Scanner;

 public class Main {
public static void main(String[] args) {
Scanner in = new Scanner(System.in);
int n = in.nextInt();//Scanner读入一个int后, 读入指针仍然停留在该行
in.nextLine();//必须消耗掉上一行的所有数据,读到\n,才能去读下一行,因此这里用nextLine()消耗掉上一行的末尾
for(int i = 1; i <= n; i++){
String[] parts = in.nextLine().split(" ");
int l = Integer.valueOf(parts[0]);
int r = Integer.valueOf(parts[1]); int k = (r-l+1)/2;
int res = 0;
if(l%2==0)
res = -k;
else
res = k;
if((r-l+1)%2==1){
if(r%2==0)
res += r;
else
res -=r;
}
System.out.println(res);
}
}
}

说明Scanner在读入大量数据的时候确实不如BufferedReader的效率高!

有人作了测试:

从测试结果来看,Scanner的平均耗时是BufferedReader的10倍左右.

Scanner和BufferReader的效率问题

在这里贴上关于Scanner和BufferedReader的对比分析。

BufferedReader可以用来读取文件或者接收来自键盘(控制台)的信息。它比Scanner更加快捷,能够大幅度缩短程序运行时间。它下面的readline()方法可以一次性读取一行文字(String),非常方便。需要注意的是,使用BufferedReader对象的readLine()方法必须处理java.io.IOException异常(Exception)。以及,在使用完BufferredReader以后,需要用close()方法关闭流。

这篇博客也讨论了这个问题

可以从源码上看看这两者之间的区别

【Java8源码分析】IO包-Reader、BufferedReader和Scanner总结

这里面有点类似与,C++提供的cin输入流的效率远不如C的scanf函数效率高