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

二分查找与暴力查找。

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

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

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

2)largeW.txt 与 largeT.txt(BruteForceSearch in hours)

./largeW.txt./largeT.txtBinarySearch 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/1eQlhUt8

时间: 2024-11-09 10:20:47

【算法】二分查找与暴力查找(白名单过滤)的相关文章

Algs4-1.1.38二分查找与暴力查找

1.1.38二分查找与暴力查找.根据1.1.10.4节给出的暴力查找法编写一个程序BruteForceSearch,在你的计算机上比较它和BinarySearch处理largeW.txt和largeT.txt所需的时间.解:暴力查找约用时:2371秒二分查找约用时: 17秒//暴力查找代码import java.util.Date;public class BruteForceSearch{    public static int rank(int key,int[] a)    {     

[经典算法] 二分查找

题目说明: 二分查找法是对一组有序的数字中进行查找,传递相应的数据,进行比较查找到与原数据相同的数据,查找到了返回对应的数组下标,失败返回-1. 题目解析: 二分查找又称折半查找,优点是比较次数少,查找速度快,平均性能好:其缺点是要求待查表为有序表,且插入删除困难.因此,折半查找方法适用于不经常变动而查找频繁的有序列表. 二分查找可以解决(预排序数组的查找)问题:只要数组中包含T(即要查找的值),那么通过不断缩小包含T的范围,最终就可以找到它.其算法流程如下: 1.一开始,范围覆盖整个数组. 2

查找算法(I) 顺序查找 二分查找 索引查找

查找 本文为查找算法的第一部分内容,包括了基本概念,顺序查找.二分查找和索引查找.关于散列表和B树查找的内容,待有空更新吧. 基本概念 查找(search)又称检索,在计算机上对数据表进行查找,就是根据所给条件查找出满足条件的第一条记录(元素)或全部记录. 若没有找到满足条件的记录,则返回特定值,表明查找失败:若查找到满足条件的 第一条记录,则表明查找成功,通常要求返回该记录的存储位置或记录值本身,以便进行进一步处理:若需要查找到满足条件的所有记录,则可看做在多个区间内连 续查找到满足条件的第一

查找算法:二分查找、顺序查找

08年9月入学,12年7月毕业,结束了我在软件学院愉快丰富的大学生活.此系列是对四年专业课程学习的回顾,索引参见:http://blog.csdn.net/xiaowei_cqu/article/details/7747205 查找算法 查找算法是在存在的序列(list) 中查找特定的目标(target),要求序列中每个记录必须与一个关键词(key)关联才能进行查找. 查找算法通常需要两个输入: 1.被查找的序列 2.要查找的关键词 查找算法的输出参数和返回值: 1.返回类型为 Error_co

查找算法系列之简单查找:顺序查找、二分查找、分块查找

近期总结了各大排序算法的原理 ,并对其进行了实现,想着一并把查找算法总结了,今天就着手开始总结查找算法. 废话不多说,这篇文章从最简单的查找算法开始讲起,之后会补充复杂的二叉搜索树查找(BST)和B树,B+树查找以及哈希查找等. 顾名思义,查找就是寻找到关键字在队列中的位置,最笨的查找算法就是依次顺序比较,复杂度为O(n),但是有很多方法的复杂度可以达到O(logn)等等. 1.顺序查找 关键字与数组中的数顺序比较,时间复杂度O(n). template<class T> int OrderS

查找算法-二分查找

查找算法-二分查找 标题 二分查找也称折半查找(Binary Search),它是一种效率较高的查找方法.但是,折半查找要求线性表必须采用顺序存储结构,而且表中元素按关键字有序排列. 过程 首先,假设表中元素是按升序排列,将表中间位置记录的关键字与查找关键字比较,如果两者相等,则查找成功:否则利用中间位置记录将表分成前.后两个子表,如果中间位置记录的关键字大于查找关键字,则进一步查找前一子表,否则进一步查找后一子表.重复以上过程,直到找到满足条件的记录,使查找成功,或直到子表不存在为止,此时查找

算法之二分查找PK线性查找

列表查找(线性查找) 本质就是列表的index() 顺序查找 也叫线性查找,从列表第一个元素开始,顺序进行搜索,知道找到元素或搜索到列表最后一个元素为止. 以下是示例代码: def line_search(li, val): for key, value in enumerate(li): if value == val: return key else: return None 二分法查找(前提必须是一个有序的列表) 通过取中间值,选择候选区,如果中间值大于要查找的值,则证明候选区在左边,更改

算法 - 二分查找(折半查找)

1. 解决问题 从有序的数据中查找元素,存储结构一般为数组之类的.(假定下面讨论的都是数据都是从小到大排序的数据). 2 .思路 把待查找数据值与查找范围的中间元素值进行比较,会有如下情况出现: 1)     待查找数据值与中间元素值正好相等,则放回中间元素值的索引. 2)     待查找数据值比中间元素值小,则以查找范围的前半部分作为新的查找范围,执行1),直到找到相等的值. 3)     待查找数据值比中间元素值大,则以查找范围的后半部分作为新的查找范围,执行1),直到找到相等的值 4)  

一天一道算法题---6.26---二分查找

感谢微信平台---一天一道算法题----每天多一点进步-- 好累啊  现在在用win7自带的输入法 打起来真麻烦 快点把这2天的搞完就重装了 还是直接来源于----〉 待字闺中 分析 给定一个数组A,其中有一个位置被称为Magic Index,含义是:如果i是Magic Index,则A[i] = i.假设A中的元素递增有序.且不重复,请给出方法,找到这个Magic Index.更进一步,当A中允许有重复的元素,该怎么办呢? 没有重复元素的情况 一些同学在遇到这个题目的时候,往往会觉得比较简单.