【算法】二分查找与暴力查找(白名单过滤)

 二分查找与暴力查找。

如果可能,我们的测试用例都会通过模拟实际情况来展示当前算法的必要性。这里该过程被称为白名单过滤。具体来说,可以想象一家信用卡公司,它需要检查客户的交易账号是否有效。为此,它需要:

  • 将客户的账号保存在一个文件中,我们称它为白名单;
  • 从标准输入中得到每笔交易的账号;
  • 使用这个测试用例在标准输出中打印所有与任何客户无关的账号,公司很可能拒绝此类交易。

在一家有上百万客户的大公司中,需要处理数百万甚至更多的交易都是很正常的。为了模拟这种情况,我们提供了文件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

 

posted @ 2015-07-07 13:49  Richaaaard  阅读(2297)  评论(0编辑  收藏  举报