二进制搜索的实现如何工作?

时间:2012-07-10 05:31:36

标签: java

% java BinarySearch 1.txt < 2.txt

如果我有两个文本文件(1.txt和2.txt),其中2.txt包含的值不在1.txt中,二进制搜索如何为我们提供这些值?如果BinarySearch的参数是一个键和一个排序数组,我不知道这是如何适用的。

以下是二进制搜索的代码:

import java.util.Arrays;

public class BinarySearch {

    // precondition: array a[] is sorted
    public static int rank(int key, int[] a) {
        int lo = 0;
        int hi = a.length - 1;
        while (lo <= hi) {
            // Key is in a[lo..hi] or not present.
            int mid = lo + (hi - lo) / 2;
            if      (key < a[mid]) hi = mid - 1;
            else if (key > a[mid]) lo = mid + 1;
            else return mid;
        }
        return -1;
    }

    public static void main(String[] args) {
        int[] whitelist = In.readInts(args[0]);

        Arrays.sort(whitelist);

        // read key; print if not in whitelist
        while (!StdIn.isEmpty()) {
            int key = StdIn.readInt();
            if (rank(key, whitelist) == -1)
                StdOut.println(key);
        }
    }
}

根据维基百科和我所理解的:二元搜索或半间隔搜索算法在排序数组中找到指定值(输入“键”)的位置。

那么如何在两个文本文件中找到不常见的值呢?

3 个答案:

答案 0 :(得分:0)

while (!StdIn.isEmpty()) { //WHILE THE INPUT FILE (OR STANDARD INPUT) ISN'T EMPTY
            int key = StdIn.readInt();  //GET THE NEXT INTEGER
            if (rank(key, whitelist) == -1) // USE BINARY SEARCH TO SEARCH FOR THAT INTEGER
                StdOut.println(key); //PRINT WHEN IT'S NOT FOUND
        }

它正在执行的代码N个二进制搜索,其中N是标准输入文件中的整数数。 复杂度为O(n * log n)+ O(m * log n)。 n和m不同文件的大小。 while列表中的n和另一个中的m。如果whilelist比其他文件小得多,这将很好用。如果没有,那么对两个文件进行排序可能是个更好的主意,并使用类似合并排序的合并步骤来比较它们。

答案 1 :(得分:0)

我认为创建哈希表将比修改的合并排序算法更好,用于比较仅包含整数的大文件。您所要做的就是读取第一个文件(它已经在做)并在阅读时将一些文件放入某些文件中哈希表。一次读取一个int的下一个文件,main中的循环正在执行,计算int的散列并比较该表是否包含与散列对应的散列表中的任何值。我假设完美的哈希表,因此您可能需要在发生冲突时进行修改。

答案 2 :(得分:0)

正如我理解这个问题,你想知道这个程序在(正确地)确定2.txt中的条目不在1.txt中时如何工作。这有一个非常简单的答案。

此算法对阵列白名单进行排序。它初始化lo指针指向元素0,hi指针指向元素whitelist.length-1,这是白名单中的最后一个元素。数组段是第一次迭代的整个数组。必须对数组进行排序或排序才能使其正常工作。

对于每次连续迭代,如果在当前数组段的中间没有找到该值,则逻辑确定该值是否必须位于中间上方的半段或中间下方的半段。除了旧的中间元素之外,该半段成为下一次迭代的新搜索段。该算法将hi和lo指针调整为一次接收数组的剩余段的一半,如果它在数组中,则搜索值必须在该处。

最终,对于不在数组中的搜索值,hi和lo(因此mid)将收敛到相同的单个元素,它将是搜索的数组的最后一段,只是一个元素的一段。如果该元素没有搜索值,那么,取决于搜索值和该元素的值,hi将变为mid-1或lo将变为mid + 1.无论哪种方式,while continuation条件将变为false,因为lo&lt ; =嗨不再是真的。新的剩余搜索细分现在具有负尺寸。这可以解释为如果在while终止之前没有发生返回,则搜索没有找到任何先前段中的值,并且没有剩余的段要搜索。因此,搜索值不能在数组中。

此问题中给出的实现有效。我用Princeton.edu stdlib测试了它,它包含了这里使用的In和StdIn类。我已经使用stdin管道在第二个文本文件中编译并运行它从命令行运行它。我不认为我会像这样实现这个应用程序,除了作为二进制搜索方法的演示,可能是为了一个类或检查一些技术。

以下是有关使用二进制搜索的原因的进一步背景知识。使用二进制搜索的原因是获得最差情况2 * logBase2(n)执行复杂度,平均1.5 * logBase2(n)复杂度。二进制搜索不在数组中的值将始终是2 * logBase2(n)比较的最坏情况。

二进制搜索远远优于线性搜索,线性搜索只从数组的一端开始并搜索每个元素,直到找到匹配或到达数组的末尾。平均搜索可以是大约n / 2,这取决于阵列中值的分布。线性搜索不在数组中的值将始终具有n比较的最坏情况。

在二元搜索中,每对比较消除了一半的可能性。可以在最多20个比较中搜索1024个条目的数组。将其与线性搜索的最大值1024进行比较。平方搜索到的数组的大小只会使二进制搜索的比较数加倍。二进制搜索可以搜索具有1,048,576个条目的数组,最多40个比较。将其与线性搜索最大值1,048,576进行比较。

问题中给出的基本二进制搜索算法对于从已排序或有序集合继承的对象非常有用,并且您必须实现自己的比较和搜索方法来重载继承的方法。只要您具有在对象之间确定更少,更大和相等的比较,并且根据该比较对集合进行排序或排序,您就可以使用此基本二进制搜索算法来搜索集合。