对字符串排序数组进行递归二进制搜索

时间:2018-10-01 01:32:07

标签: java binary-search

我制作了一个长度为10的数组。每个插槽都有一个名称。我的目标是随机选择一个名称并进行二进制搜索找到它。我不明白这有什么问题,但是如果您至少可以给我一个提示,那将非常有帮助,谢谢。 这是我的代码:

    private int iRecursiveCalls = 0;

    public void runRecursiveTest(){

        String[] iArraySize = new String[10];

        String[] aiNumbers = new String[iArraySize.length];

        SecureRandom oRand = new SecureRandom();

        iArraySize[0] = "John";
        iArraySize[1] = "Max";
        iArraySize[2] = "Kyle";
        iArraySize[3] = "Sam";
        iArraySize[4] = "Robert";
        iArraySize[5] = "Alex";
        iArraySize[6] = "Bob";
        iArraySize[7] = "Daniel";
        iArraySize[8] = "Felix";
        iArraySize[9] = "Michael";

        String iTarget = aiNumbers[oRand.nextInt(iArraySize.length)];

        Arrays.sort(aiNumbers);

        System.out.println("Target num: " + iTarget);

        System.out.println("--- Begin Binary Search ---");
        long lBegTime = System.nanoTime();
        findNumbersBinarySearch(aiNumbers, iTarget, 0, iArraySize.length -1);
        long lEndTime = System.nanoTime();
        System.out.println("Elapsed time: " + (lEndTime - lBegTime));
        System.out.println("Recursive calls: " + iRecursiveCalls);
        System.out.println("--- End Binary Search ---");
    }

    private int findNumbersBinarySearch(String[] aiNumbers, String iTarget,
                                        int iLow, int iHigh){

        iRecursiveCalls++;

        int iMiddle = (iHigh + iLow) / 2;

        if(iTarget.equals(aiNumbers[iMiddle])){
            return iMiddle;
        }
        else if(iTarget.compareTo(aiNumbers[iMiddle])>0){

            return findNumbersBinarySearch(aiNumbers, iTarget,
                    iMiddle + 1, iHigh);
        }
        else{
            return findNumbersBinarySearch(aiNumbers, iTarget,
                    iLow, iMiddle - 1);
        }
    }
}

我该如何解决?

1 个答案:

答案 0 :(得分:0)

您的算法不起作用,因为您正在索引,排序并将空数组传递给函数。您可能在iArraySizeaiNumbers之间感到困惑;这两个都是令人误解的变量名,因为您要向iArraySize添加字符串名,而aiNumbers不包含数字。您的二进制搜索函数名称和其他变量同样具有误导性;即使函数标头采用Numbers数组,它们也使用单词iprefix String[]

此外,如果在数组中未找到目标,您的代码将破坏调用堆栈。经典的二进制搜索一旦lo > hi就会返回失败;我认为没有任何理由不包括base case

另一个二进制搜索难题是使用公式mid = (hi - lo) / 2 + lo。这样可以避免在hi + lo > Integer.MAX_SIZE时可能发生的讨厌的整数溢出错误。

此代码通过在整个过程中坚持一个数组来解决这些问题,使用更准确的变量名并且不会溢出堆栈:

import java.util.*;
import java.security.SecureRandom;

class Main {
    private static int recursiveCalls = 0;

    public static void main(String[] args) {
        runRecursiveTest();
    }

    public static void runRecursiveTest() {
        SecureRandom rand = new SecureRandom();
        String[] names = {
            "John",
            "Max",
            "Kyle",
            "Sam",
            "Robert",
            "Alex",
            "Bob",
            "Daniel",
            "Felix",
            "Michael"
        };

        String target = names[rand.nextInt(names.length)];
        Arrays.sort(names);

        System.out.println("Target string: " + target);
        System.out.println("--- Begin Binary Search ---");

        long begin = System.nanoTime();
        System.out.println(bisect(names, target, 0, names.length - 1));
        long end = System.nanoTime();

        System.out.println("Elapsed time: " + (end - begin));
        System.out.println("Recursive calls: " + recursiveCalls);
        System.out.println("--- End Binary Search ---");
    }

    private static int bisect(String[] arr, String target, int lo, int hi) {
        recursiveCalls++;

        if (lo > hi) { return -1; }

        int mid = (hi - lo) / 2 + lo;

        if (target.equals(arr[mid])) {
            return mid;
        }
        else if (target.compareTo(arr[mid]) > 0) {
            return bisect(arr, target, mid + 1, hi);
        }

        return bisect(arr, target, lo, mid - 1);
    }
}

输出:

Target string: Sam
--- Begin Binary Search ---
9
Elapsed time: 81385
Recursive calls: 4
--- End Binary Search ---

Try it!