Scanner和BufferReader的效率问题

Posted greatlong

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Scanner和BufferReader的效率问题相关的知识,希望对你有一定的参考价值。

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

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

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

 1 import java.util.Scanner;
 2 
 3 public class Main {
 4 public static void main(String[] args) {
 5 Scanner in = new Scanner(System.in);
 6 int n = in.nextInt();
 7 for(int i = 1; i <= n; i++){
 8 int l = in.nextInt();
 9 int r = in.nextInt();
10 
11 int sum1 = 0;
12 int sum2 = 0;
13 if(r%2 == 0)
14 sum1 = r/2;
15 else
16 sum1 = r/2-r;
17 if((l-1)%2==0)
18 sum2 = l/2;
19 else
20 sum2 = l/2-l;
21 
22 System.out.println(sum1-sum2);
23 }
24 }
25 }

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

技术图片

 

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

 1 import java.io.BufferedReader;
 2 import java.io.IOException;
 3 import java.io.InputStreamReader;
 4 
 5 
 6 public class Main {
 7 
 8 
 9 public static void main(String[] args) throws IOException {
10 BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
11 int q = Integer.valueOf(br.readLine());
12 while (q-- > 0) {
13 String[] parts = br.readLine().split(" ");
14 int l = Integer.valueOf(parts[0]);
15 int r = Integer.valueOf(parts[1]);
16 
17 int k = (r-l+1)/2;
18 int res = 0;
19 if(l%2==0)
20 res = -k;
21 else
22 res = k;
23 if((r-l+1)%2==1){
24 if(r%2==0)
25 res += r;
26 else
27 res -=r;
28 }
29 System.out.println(res);
30 }
31 }
32 }

代码通过:

技术图片

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

 1 import java.util.Scanner;
 2 
 3 public class Main {
 4 public static void main(String[] args) {
 5 Scanner in = new Scanner(System.in);
 6 int n = in.nextInt();//Scanner读入一个int后, 读入指针仍然停留在该行
 7 in.nextLine();//必须消耗掉上一行的所有数据,读到
,才能去读下一行,因此这里用nextLine()消耗掉上一行的末尾
 8 for(int i = 1; i <= n; i++){
 9 String[] parts = in.nextLine().split(" ");
10 int l = Integer.valueOf(parts[0]);
11 int r = Integer.valueOf(parts[1]);
12 
13 
14 int k = (r-l+1)/2;
15 int res = 0;
16 if(l%2==0)
17 res = -k;
18 else
19 res = k;
20 if((r-l+1)%2==1){
21 if(r%2==0)
22 res += r;
23 else
24 res -=r;
25 }
26 System.out.println(res);
27 }
28 }
29 }

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

有人作了测试:

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

技术图片

 

 

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

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

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

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

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

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

以上是关于Scanner和BufferReader的效率问题的主要内容,如果未能解决你的问题,请参考以下文章

JDK源码:BufferedReader

java中bufferreader的使用方法有哪些?

从socket bufferreader永远读取android

BufferReader案例

IO创建Socket通信中慎用BufferReader中的readLine()

Buffer Stream- BufferReader & BufferWriter