在这里先比较一下三种输入方式(这里从文件中读取):
第一种,Scanner类读取文件(in.txt,里面有从一到一百万的的整数)
public class Main {
public static void main(String[] args) throws IOException{
Scanner sc = new Scanner(new FileInputStream("in.txt"));
long start = System.currentTimeMillis();
for(int i=1;i<=1000000;i++)
sc.nextInt();
long end = System.currentTimeMillis();
System.out.println("time="+(end-start)+"ms");
}
}
运行结果:
time=2930ms
大概3秒,实际上如果ACM中真有一百万的数据,若用Scanner读取,还没开始计算,就已经超时了。
第二种,网上说的petr大佬的模板
public class Main {
public static class InputReader{
private BufferedReader in;
private StringTokenizer tokenizer;
public InputReader(InputStream stream){
in = new BufferedReader(new InputStreamReader(stream),32768);
tokenizer = null;
}
public String next() throws IOException{
while(tokenizer==null || !tokenizer.hasMoreTokens()){
tokenizer = new StringTokenizer(in.readLine());
}
return tokenizer.nextToken();
}
public int nextInt() throws IOException{
return Integer.valueOf(next());
}
}
public static void main(String[] args) throws IOException{
InputReader reader = new InputReader(new FileInputStream("in.txt"));
long start = System.currentTimeMillis();
for(int i=1;i<=1000000;i++)
reader.nextInt();
long end = System.currentTimeMillis();
System.out.println("time="+(end-start)+"ms");
}
}
运行结果:
time=844ms
显然读取速度提高了两秒,已经在ACM允许的时间内了。
第三种,用StreamTokenizer读取
public class Main {
public static StreamTokenizer in;
static {
try{
in = new StreamTokenizer(new BufferedReader(new InputStreamReader(new FileInputStream("in.txt"))));
}catch (Exception e){
e.printStackTrace();
}
}
public static int nextInt() throws IOException{ in.nextToken(); return (int)in.nval; }
public static void main(String[] args) throws IOException{
long start = System.currentTimeMillis();
for(int i=1;i<=1000000;i++)
nextInt(); //这里仅读取,不输出
long end = System.currentTimeMillis();
System.out.println("time="+(end-start)+"ms");
}
}
运行结果:
time=397ms
速度相比petr大佬的模板,速度又快了一倍左右。
不过要注意的是,用StreamTokenizer
读取字符串时,只能读取纯字母字符串,如果包含数字或者其他字符会返回null。这是用StreamTokenizer
读取的缺点。但是用它读取数字时没有问题的。
总结一下:
如果数据量比较小,用Scanner是比较方便的
如果数据量很大的话,那么用StreamTokenizer 是一个很好的选择
至于petr大佬的模板,从代码量和运行时间上都不如StreamTokenizer ,不推荐使用
输入讲完了,这里再比较一下两种输出方式
第一种使用传统的System.out.println()方式输出。
public class Main {
public static void main(String[] args) {
long start = System.currentTimeMillis();
for(int i=0;i<100000;i++)
System.out.println(i);
long end = System.currentTimeMillis();
System.out.println("time="+(end-start)+"ms");
}
}
运行结果:
...
......
time=3443ms
显然在ACM中会超时
第二种使用PrintWriter输出:
public class Main {
public static PrintWriter out = new PrintWriter(new OutputStreamWriter(System.out));
public static void main(String[] args) {
long start = System.currentTimeMillis();
for(int i=0;i<100000;i++)
out.println(i);
out.flush();
long end = System.currentTimeMillis();
System.out.println("time="+(end-start)+"ms");
out.close();
}
}
结果:
..
....
time=328ms
虽然每次输出的结果会有大致几十毫秒的偏差,但总体上来看,PrintWriter输出要比用System.out.println()输出快上10倍左右。这个结果就比较让人满意了。
最后在这里提供一个ACM模板:
import java.io.*;
public class Main {
public static StreamTokenizer in = new StreamTokenizer(new BufferedReader(new InputStreamReader(System.in),32768));
public static PrintWriter out = new PrintWriter(new OutputStreamWriter(System.out));
public static double nextDouble() throws IOException{ in.nextToken(); return in.nval; }
public static float nextFloat() throws IOException{ in.nextToken(); return (float)in.nval; }
public static int nextInt() throws IOException{ in.nextToken(); return (int)in.nval; }
public static String next() throws IOException{ in.nextToken(); return in.sval;}
public static void main(String[] args) throws IOException{
// 获取输入
while(in.nextToken()!=StreamTokenizer.TT_EOF){
break;
}
int x = (int)in.nextToken(); //第一个数据应当通过nextToken()获取
int y = nextInt();
float f = nextFloat();
double d = nextDouble();
String str = next();
// 输出
out.println("abc");
out.flush();
out.close();
}
}