1. 程式人生 > >Java IO速度和佔用記憶體的極致優化方法,模板方法【從hdu 2602 說起】

Java IO速度和佔用記憶體的極致優化方法,模板方法【從hdu 2602 說起】

談起java,給人的第一映像是什麼?除了簡單方便易上手,跨平臺可移植,各種函式庫支援類應有盡有不用重複造輪子這些特性之外,恐怕就是速度慢,佔用記憶體高了吧。不可否認,java執行速度和記憶體佔用方便確實無法比肩C/C++。隨手舉一個很直觀的栗子,在ACM等其他演算法競賽中,普通給java的程式碼執行的時間往往都是C和C++  2~~3倍,由此可見一斑。不過我們今天要說的就是,演算法效率一樣的情況下,如何去優化java的速度,讓他在提供編碼方便的同時,速度和記憶體上比肩一般的C和C++。

(/**部落格記錄了小菜尋找優化解法的過程 === 嫌拖拉的同學可以直接拉到最末看總結出的模板 */)

        為了方便直觀對執行時間和佔用記憶體有直觀的感受,我們拿 hdu 2602這個題目舉栗子。因為在OJ上能直接給出程式的執行時間和佔用記憶體。 

        hdu 2602 是一個沒有任何變化的經典01揹包問題,對於01揹包問題,一維的dp做法在演算法上已經到極致不能再優化了(參考dd巨巨的揹包九講)。在大家演算法效率都是一樣的情況下,我們看看速度和記憶體佔用有多大差別。(提交語言都是java的情況下)


        最開始我連續提交了好幾次,雖然AC了,但是程式碼執行記憶體開銷始終在1萬3千多k,我繼續往後翻了一下java的提交記錄


        大都是在1萬多k 以上,雖然這數字看著有點大,但是既然那麼多人都是這麼大的記憶體佔用,那就應該是java本身的問題了。  ========我繼續往後翻=========可是當我繼續往後翻的時候,就感覺不對了,同樣是java,同樣的演算法,怎麼還能有這麼不可思議,整整少了一個數量級的記憶體佔用,整整快了一倍的速度


        快個幾十毫秒,記憶體多個幾十幾百k 還能理解,但是這不是一個幾十幾百k了,這是上萬的差別了,同樣是用java同樣的演算法(應該是),居然出現了上萬的差別。這就讓人不能忍受了。

        下面是我自己第一次提交的程式碼,用的是直觀二維的做法。耗時468ms,佔用記憶體24948k


        在發現自己記憶體佔用比人家高了那麼多之後,我又換成一維的解法。 耗時546ms,佔用記憶體 13908k。


        速度還是不盡人意,我試著直接寫在main 函式裡面,省去函式呼叫看會不會快一點。這次是546ms, 13940k,並沒有多大的變化。甚至還多了一點,我想應該是隨機的吧。


        後來喪心病狂的我又嘗試把 i,j 還有陣列的定義都放在迴圈外,然而時間還是微乎其微的變化,嘗試著像以前一樣固定陣列,然和時間也還是沒有變化。於是意識到這不是普通小優化能解決的了。

        ========================糾結糾結嘗試中====================

        由於在hdu 上不能發郵件問別人程式碼怎麼寫的也看不到別人程式碼,只能靠自己一步步的摸索了。百度了好久也沒找到可行的解決方案,最後還是上codeforces看的別人的模板才發現的。

來看一下效果吧,參看cf上排名第二的peter的java程式碼之後,        執行時間降到了234ms,記憶體降到了 9588k


        可是9k多k 還是比人家2k多有很大的差距,繼續在 cf上找程式碼嘗試 ======>

        這次看的是排名第一的tourist巨巨的程式碼,執行時間降到了 249ms,記憶體佔用降到了7504k,與之前相比整整降低了一倍,下面給出程式碼

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.PrintWriter;
import java.util.Arrays;
import java.util.Scanner;

public class Main {

    static InputReader in;
    static PrintWriter out;

    public static void main(String[] args) throws IOException {
        in = new InputReader(System.in);
        out = new PrintWriter(System.out);
            
        int Case;
        Case = in.nextInt();
        //int i,j;
//        int []v = new int[1010];
//        int []w = new int[1010];            
//        int []m = new int[1010];
        while(Case-- > 0){
            int n,c;
            n = in.nextInt();
            c = in.nextInt();    
            int []v = new int[n];
            int []w = new int[n];            
            int []m = new int[c+1];
            for(int i=0;i<n;i++){
                v[i] = in.nextInt();
            }
            for(int i=0;i<n;i++){
                w[i] = in.nextInt();
            }
            Arrays.fill(m,0);
            for(int i=0;i<=n-1;i++){
                for(int j=c;j>=w[i];j--)   
                        m[j]=Math.max(m[j], m[j-w[i]]+v[i]);   
            }
            System.out.println(m[c]);
        }    
        out.close();
    }

    static class InputReader {
        BufferedReader br;

        public InputReader(InputStream stream) {
            br = new BufferedReader(new InputStreamReader(stream));
        }

        public int nextInt() throws IOException {
            int c = br.read();
            while (c <= 32) {
                c = br.read();
            }
            boolean negative = false;
            if (c == '-') {
                negative = true;
                c = br.read();
            }
            int x = 0;
            while (c > 32) {
                x = x * 10 + c - '0';
                c = br.read();
            }
            return negative ? -x : x;
        }

        public long nextLong() throws IOException {
            int c = br.read();
            while (c <= 32) {
                c = br.read();
            }
            boolean negative = false;
            if (c == '-') {
                negative = true;
                c = br.read();
            }
            long x = 0;
            while (c > 32) {
                x = x * 10 + c - '0';
                c = br.read();
            }
            return negative ? -x : x;
        }

        public String next() throws IOException {
            int c = br.read();
            while (c <= 32) {
                c = br.read();
            }
            StringBuilder sb = new StringBuilder();
            while (c > 32) {
                sb.append((char) c);
                c = br.read();
            }
            return sb.toString();
        }

        public double nextDouble() throws IOException {
            return Double.parseDouble(next());
        }
    }
}

        200多的速度和7000多的記憶體和極致的142ms度與2712的記憶體使用相比還有差距,不死心,還想繼續降低下去來著,可是無奈cf上前面兩頁巨巨的java程式碼幾乎都嘗試過了一遍,還是沒能降低下來,那就只好先暫時這樣吧。更加好奇142ms 的極致速度是怎麼出來的,真的堪比C/C++

要是哪位親有程式碼一定要貼出來學習一下啊.......

        下面給出IO讀取加速的普遍模板

import java.io.BufferedReader;  
import java.io.IOException;  
import java.io.InputStream;  
import java.io.InputStreamReader;  
import java.io.PrintWriter;  
import java.util.Scanner;  
  
public class Main {  
  
    static InputReader in;  
    static PrintWriter out;  
  
    public static void main(String[] args) throws IOException {  
        in = new InputReader(System.in);  
        out = new PrintWriter(System.out);  
        /*
         * 
         * 這裡補充你的實際程式碼   讀取輸入採用   in.nextInt();的形式
         * 
         * */
        out.close();  
    }  
  
    static class InputReader {  
        BufferedReader br;  
  
        public InputReader(InputStream stream) {  
            br = new BufferedReader(new InputStreamReader(stream));  
        }  
  
        public int nextInt() throws IOException {  
            int c = br.read();  
            while (c <= 32) {  
                c = br.read();  
            }  
            boolean negative = false;  
            if (c == '-') {  
                negative = true;  
                c = br.read();  
            }  
            int x = 0;  
            while (c > 32) {  
                x = x * 10 + c - '0';  
                c = br.read();  
            }  
            return negative ? -x : x;  
        }  
  
        public long nextLong() throws IOException {  
            int c = br.read();  
            while (c <= 32) {  
                c = br.read();  
            }  
            boolean negative = false;  
            if (c == '-') {  
                negative = true;  
                c = br.read();  
            }  
            long x = 0;  
            while (c > 32) {  
                x = x * 10 + c - '0';  
                c = br.read();  
            }  
            return negative ? -x : x;  
        }  
  
        public String next() throws IOException {  
            int c = br.read();  
            while (c <= 32) {  
                c = br.read();  
            }  
            StringBuilder sb = new StringBuilder();  
            while (c > 32) {  
                sb.append((char) c);  
                c = br.read();  
            }  
            return sb.toString();  
        }  
  
        public double nextDouble() throws IOException {  
            return Double.parseDouble(next());  
        }  
    }  
}  



相關推薦

Java IO速度佔用記憶體極致優化方法,模板方法hdu 2602

談起java,給人的第一映像是什麼?除了簡單方便易上手,跨平臺可移植,各種函式庫支援類應有盡有不用重複造輪子這些特性之外,恐怕就是速度慢,佔用記憶體高了吧。不可否認,java執行速度和記憶體佔用方便確實無法比肩C/C++。隨手舉一個很直觀的栗子,在ACM等其他演算法競賽中,

JAVA中基本資料型別佔用記憶體空間大小

byte:1個位元組,8位,-128~127 最大儲存資料量 255short:2個位元組,16位,-32768~32767 最大儲存資料量 65535char:2個位元組,16位,儲存Unicode編碼,用‘’int:4個位元組,32位,負的2的31次方~2的31次方-1 

Java IO: InputStreamReaderOutputStreamWriter

作者: Jakob Jenkov 譯者: 李璟([email protected]) 本章節將簡要介紹InputStreamReader和OutputStreamWriter。細心的讀者可能會發現,在之前的文章中,IO中的類要麼以Stream結尾,要麼以Reader或者Writer結

Java IO: BufferedData

作者:Jakob Jenkov  譯者: 李璟([email protected]) 本小節會簡要概括Java IO中Buffered和data的輸入輸出流,主要涉及以下4個型別的流:BufferedInputStream,BufferedOutputStream,DataInput

Java IO: FileReaderFileWriter

作者: Jakob Jenkov 譯者: 李璟([email protected]) 本章節將簡要介紹FileReader和FileWriter。與FileInputStream和FileOutputStream類似,FileReader與FileWriter用於處理檔案內容。 F

Java IO: 位元組字元陣列

原文連結 作者: Jakob Jenkov 譯者: 李璟([email protected]) Java中的位元組和字元陣列,經常被用於臨時儲存應用程式內部的資料,所以陣列也是常見的資料來源以及資料流目的地。如果你在程式執行過程中需要頻繁訪問檔案的內容,你可能會願意將檔案載入到陣列中

Java IO: ReaderWriter

作者: Jakob Jenkov 譯者: 李璟([email protected]) Reader 原文連結 Reader是Java IO中所有Reader的基類。Reader與InputStream類似,不同點在於,Reader基於字元而非基於位元組。換句話說,Reader用於讀取

Java IO: ByteArrayFilter

作者: Jakob Jenkov 譯者: 李璟([email protected]) 本小節會簡要概括Java IO中位元組陣列與過濾器的輸入輸出流,主要涉及以下4個型別的流:ByteArrayInputStream,ByteArrayOutputStream,FilterInput

javax.xml + java.io xmljava物件互轉工具類

import javax.xml.bind.JAXBContext; import javax.xml.bind.JAXBException; import javax.xml.bind.Marshaller; import javax.xml.bind.Unmarshall

java.io.Reader java.io.InputStream的區別

java.io.Reader 和 java.io.InputStream 組成了 Java 輸入類。Reader 用於讀入16位字元,也就是 Unicode 編碼的字元;而 InputStream 用於讀 入 ASCII 字元和二進位制資料。 在 Java 中,有不同型別的

黑馬程式設計師—JAVA IO(BufferStream)

---------------------- <a href="http://edu.csdn.net"target="blank">ASP.Net+Android+IOS開發</a>、<a href="http://edu.csdn.net"

協助科學家建立機器學習模型 讓進行速度精準度優化

IBM是一個數據科學應用程式開發工具Watson Studio,添加了一系列人工智慧自動化功能AutoAI,幫助資料科學家解決構建

Java中 OverloadOverride的區別。Overloaded的方法是否可以改變返回值的型別?

Overload是過載的意思,Override是覆蓋的意思,也就是重寫。 過載Overload表示同一個類中可以有多個名稱相同的方法,但這些方法的引數列表各不相同(即引數個數或型別不同)。 重寫Override表示子類中的方法可以與父類中的某個方法的名稱和引數完全相同,通

android java層直接kernel互動的最快的方法

http://blog.csdn.net/zengkexu/article/details/8805339  android java 和kernel 的互動方式  按照常規的要通過JNI實現, 然後jni 呼叫HAL的IOCTL ,或者類似Vold 中建立netli

java 中三種常見記憶體溢位錯誤的處理方法

相信有一定Java開發經驗的人或多或少都會遇到OutOfMemoryError的問題,這個問題曾困擾了我很長時間,隨著解決各類問題經驗的積累以及對問題根源的探索,終於有了一個比較深入的認識。 在解決java記憶體溢位問題之前,需要對jvm(java虛擬機器)的

eclipse中java,javascriphtml程式碼自動提示功能設定方法檔案

使用eclipse自帶的外掛,無需另外安裝外掛,具體步驟如下 1.開啟eclipse→Windows→Preferences→Java→Editor→Content Assist 修改Auto Activation triggers for java的值為:zjava 點選apply按鈕

java中MapList初始化的兩種方法

第一種方法(常用方法): //初始化List List<string> list = new ArrayList</string><string>

java中三種常見記憶體溢位錯誤的處理方法

相信有一定java開發經驗的人或多或少都會遇到OutOfMemoryError的問題,這個問題曾困擾了我很長時間,隨著解決各類問題經驗的積累以及對問題根源的探索,終於有了一個比較深入的認識。 在解決java記憶體溢位問題之前,需要對jvm(java虛擬機器

解密:智慧美妝動效自拍背後的技術楚才國科

在如今一個看臉的時代,顏值對大家來說都挺重要。對於女生來說,除了化妝以外還有拍照軟體的美顏技術,相信每個女生的手機上都有至少一個美拍軟體,那麼當中的智慧美妝跟動效自拍的背後運用了怎樣的技術呢? 一般而言,一個完整的人臉識別系統包含三大主要組成部分,即人臉檢測、人臉配准以及人臉識別。三者流水

《瘋狂Java講義(第4版)》-----第3章資料型別與運算子

Java的官方API下載 Java語言是一門強型別語言。強型別含義: 所有變數必須先宣告,後使用; 指定型別的變數只能接受型別與之匹配的值 註釋 //單行註釋 /* 多行註釋 */ /** *文件註釋 */ 識別符號 字母、下劃線、美元符號、數字組成。字