【算法】二分查找与暴力查找(白名单过滤)
二分查找与暴力查找。
如果可能,我们的测试用例都会通过模拟实际情况来展示当前算法的必要性。这里该过程被称为白名单过滤。具体来说,可以想象一家信用卡公司,它需要检查客户的交易账号是否有效。为此,它需要:
- 将客户的账号保存在一个文件中,我们称它为白名单;
- 从标准输入中得到每笔交易的账号;
- 使用这个测试用例在标准输出中打印所有与任何客户无关的账号,公司很可能拒绝此类交易。
在一家有上百万客户的大公司中,需要处理数百万甚至更多的交易都是很正常的。为了模拟这种情况,我们提供了文件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