二分查詢與暴力查詢。
如果可能,我們的測試用例都會通過模擬實際情況來展示當前演算法的必要性。這裡該過程被稱為白名單過濾。具體來說,可以想象一家信用卡公司,它需要檢查客戶的交易賬號是否有效。為此,它需要:
- 將客戶的賬號儲存在一個檔案中,我們稱它為白名單;
- 從標準輸入中得到每筆交易的賬號;
- 使用這個測試用例在標準輸出中列印所有與任何客戶無關的賬號,公司很可能拒絕此類交易。
在一家有上百萬客戶的大公司中,需要處理數百萬甚至更多的交易都是很正常的。為了模擬這種情況,我們提供了檔案largeW.txt(100萬條:約6.7M)和largeT.txt(1000萬條:約86M)。其中largeW.txt表示白名單,largeT.txt表示目標檔案
給出暴力查詢法(順序查詢)編寫一個程式BruteForceSearch,在你的計算機上比較它和BinarySearch處理largeW.txt(100萬條:約6.7M)和largeT.txt(1000萬條:約86M)所需的時間。
說明:
演算法第四版中提及的暴力查詢法實為順序查詢法,詳見程式碼:
1 public static int rank(int key, int[] a) { 2 for (int i = 0; i < a.length; i++) { 3 if (a[i] == key) return i; 4 } 5 return -1; 6 }
效能:
一個程式只是可用往往是不夠的。例如,上面rank()的實現也可以很簡單,它會檢查陣列的每個元素,甚至都不需要陣列是有序的。
有了這個簡單易懂的解決方案,我們為什麼還需要歸併排序和二分查詢呢?計算機用rank()方法的暴力實現處理大量輸入(比如含有100萬個條目的白名單和1000萬條交易)非常慢。沒有如二分查詢或者歸併排序這樣的高效演算法,解決大規模的白名單問題是不可能得。良好的效能常常是極為重要的。
二分查詢演算法程式碼:
1 public static int rank(int key, int[] a) { 2 int lo = 0; 3 int hi = a.length - 1; 4 while (lo <= hi) { 5 // Key is in a[lo..hi] or not present. 6 int mid = lo + (hi - lo) / 2; 7 if (key < a[mid]) hi = mid - 1; 8 else if (key > a[mid]) lo = mid + 1; 9 else return mid; 10 } 11 return -1; 12 }
實驗程式碼:
1 package com.beyond.algs4.experiment;
2
3 import java.io.File;
4 import java.util.Arrays;
5
6 import com.beyond.algs4.lib.BinarySearch;
7 import com.beyond.algs4.lib.StdIn;
8 import com.beyond.algs4.lib.StdOut;
9 import com.beyond.algs4.std.In;
10
11 public class PerfBruteForceSearch {
12
13 /**
14 * @param args
15 */
16 public static void main(String[] args) {
17 String whitelist = StdIn.readString();
18 int[] whitelistArray = readlist(whitelist);
19 String targetlist = StdIn.readString();
20 int[] targetlistArray = readlist(targetlist);
21
22 long t1 = System.currentTimeMillis();
23 // for (int i = 0; i < targetlistArray.length; i++) {
24 // BruteForceSearch.rank(targetlistArray[i], whitelistArray);
25 // }
26 // StdOut.println(String.format("BruteForceSearch in %d milliseconds", (long) (System.currentTimeMillis() - t1)));
27 //
28 // t1 = System.currentTimeMillis();
29 Arrays.sort(whitelistArray);
30 for (int i = 0; i < targetlistArray.length; i++) {
31 BinarySearch.rank(targetlistArray[i], whitelistArray);
32 }
33 StdOut.println(String.format("BinarySearch in %d milliseconds", (long) (System.currentTimeMillis() - t1)));
34 }
35
36 private static int[] readlist(String whitelist) {
37 File fWhitelist = new File(whitelist);
38 In in = new In(fWhitelist);
39 int[] whitelistArray = in.readAllInts();
40 return whitelistArray;
41 }
42
43 }
實驗結果:
1)tinyW.txt 與 tinyT.txt
./TinyW.txt
./TinyT.txt
BruteForceSearch in 0 milliseconds
BinarySearch in 1 milliseconds
2)largeW.txt 與 largeT.txt(BruteForceSearch in hours)
./largeW.txt
./largeT.txt
BinarySearch in 2399 milliseconds
補充說明:
實驗方法忽略讀取測試資料檔案對演算法的影響
實驗方法忽略BruteForceSearch與BinarySearch執行的影響
注意
在記憶體不夠時,可能出現錯誤:Java heap space
1 ./largeW.txt 2 ./largeT.txt 3 Exception in thread "main" java.lang.OutOfMemoryError: Java heap space 4 at java.nio.HeapCharBuffer.<init>(Unknown Source) 5 at java.nio.CharBuffer.allocate(Unknown Source) 6 at java.util.Scanner.makeSpace(Unknown Source) 7 at java.util.Scanner.readInput(Unknown Source) 8 at java.util.Scanner.next(Unknown Source) 9 at com.beyond.algs4.std.In.readAll(In.java:247) 10 at com.beyond.algs4.std.In.readAllStrings(In.java:322) 11 at com.beyond.algs4.std.In.readAllInts(In.java:348) 12 at com.beyond.algs4.experiment.PerfBruteForceSearch.readlist(PerfBruteForceSearch.java:39) 13 at com.beyond.algs4.experiment.PerfBruteForceSearch.main(PerfBruteForceSearch.java:20)
在更改win32_x86版本eclipse 並把eclipse.ini更新為-Xmx2048m超過1024時,eclipse會出錯“Failed to create the Java Virtual Machine”。建議更換64位版本。
計算機基本配置
處理器: Inter(R) Pentium(R) CPU G3220 @3.00GHz
記憶體:8.00GB
系統型別:64位作業系統
軟體環境
IDE: Version: Mars Release (4.5.0)
JVM:
1 -startup 2 plugins/org.eclipse.equinox.launcher_1.3.100.v20150511-1540.jar 3 --launcher.library 4 plugins/org.eclipse.equinox.launcher.win32.win32.x86_64_1.1.300.v20150602-1417 5 -product 6 org.eclipse.epp.package.jee.product 7 --launcher.defaultAction 8 openFile 9 --launcher.XXMaxPermSize 10 256M 11 -showsplash 12 org.eclipse.platform 13 --launcher.XXMaxPermSize 14 256m 15 --launcher.defaultAction 16 openFile 17 --launcher.appendVmargs 18 -vmargs 19 -Dosgi.requiredJavaVersion=1.7 20 -Xms512m 21 -Xmx2048m
參考資料:
演算法 第四版 謝路雲 譯 Algorithms Fourth Edition [美] Robert Sedgewick, Kevin Wayne著
http://algs4.cs.princeton.edu/home/
原始碼下載連結:
http://pan.baidu.com/s/1eQjMd0Y