如何使用二进制搜索Java

问题描述

嗨,我正在用searchMark方法创建一个包含两个并行数组(studentNum和成绩)的程序,我提示用户也输入他们要查找的成绩。然后该程序使用二进制搜索来找到该值,然后检查是否有其他学生拥有它。然后所有学生编号及其成绩会在输出屏幕中打印出来。在数组中找到目标的第一个实例后,程序/代码将立即结束。我提供了一张图片显示我的输出是什么以及输出应该是什么样子。

       // Binary Search
    int startIndex = 0,endindex = 0;
    int middleIndex;
    int shiftPlus = 0;
    int shiftMinus = grade.length-1;
    int midValue = 0;

    while (startIndex <= endindex) {
        
        middleIndex = (startIndex+endindex)/2;
        
        if (grade[middleIndex] == target) {
            midValue = grade[middleIndex];
            System.out.println("student #" + student[middleIndex] 
            + " has a correct count of " + target);
            break;
        }
        else if (grade[middleIndex] > target)
            endindex = middleIndex-1;
        
        else if (grade[middleIndex] < target)
            startIndex = middleIndex + 1;

    }  
    
    boolean aboveMid = true,belowMid = true; // for while loops to stop/start
    
    while (shiftPlus <= midValue && aboveMid == true) {
        shiftPlus += 1; // starts at 0 and moves 1 up each loop            
        if(grade[shiftPlus] == target && shiftPlus <= midValue) 
        {
            System.out.println("student #" + student[shiftPlus] 
            + " has a correct count of " + target);
        }
        else
            belowMid = false;          
    }
    
    while (shiftMinus >= midValue && belowMid == true) {
        shiftMinus -= 1; // subtract one from end
        if(grade[shiftMinus] == target && shiftMinus <= midValue) 
        {
            System.out.println("student #" + student[shiftMinus] 
            + " has a correct count of " + target);
        } 
        else
            aboveMid = false;            
    }
}

代码输出是我输入除3以外的任何数字的情况。

您要搜索什么标记? 6 建立成功(总时间:2秒)

但是,如果我输入数字“ 3” 您想搜索什么商标? 3 学生#2的正确计数为3 学生#3的正确计数为3

解决方法

二进制搜索内置于Java(Arrays.binarySearch)中,自己写是一个错误。当然,除非这是家庭作业,并且编写二进制搜索算法才是家庭作业。

请注意,二进制搜索需要对输入数组进行排序。在未排序的输入上运行binsearch会产生垃圾。如,没有错误,只是..错误答案的结果。这是二进制搜索的基本属性。

想一想您的算法:假设所有学生得分为6分。然后,很明显,您的意图是让您打印出所有学生。

您的代码只会在两个地方打印。这两个地方在for循环中,并且它对X循环for循环,其中X是“ target-shiftPlus”。您的代码不完整(shiftPlus并未在任何地方定义),但是很显然,如果“目标”发生变化,则打印数量也会发生变化。事实证明,这没有任何意义:如果您要寻找分数为7的学生,而他们的分数都为7,则与您寻找分数6的情况相比,您的打印要少一或少全部得分6?不,那是不对的。因此,“目标”一开始就不应成为循环计数的一部分,在设计此算法的过程中,您走错了路。

算法这一部分的目的是“寻找”您的二进制搜索找到的索引,因为可能有一个以上的学生具有预期的分数,如果超过1个,他们将立即靠近您的“热门”。

一个关键的线索是,直到到达那里,您都不知道会有多少次匹配,因此一个重要的for循环是正确的。也许while更合适? for也可以工作,但是某些索引查找需要成为终止条件的一部分(在for内的两个;之间)。

让我们说分数是:[4,6,7,8],您的binsearch偶然发现了3个6分数中的第一。换句话说,二进制搜索的结果是:在索引= 1处有一个匹配项。

您要首先“向下看” 4(因此,相对于找到的索引为-1:index = 0),在索引0处查找分数4,意识到4不是6,不要打印任何内容,此外,请停止向下看。

然后您要“查找”,从您自己的索引(index = 1)开始,获取该索引的分数(6,意识到实际上是目标索引,因此打印该学生然后继续:将1加到索引中(现在index = 2)并重复该算法。再次“命中”,打印另一个学生,增加索引,第三次命中,将索引增加到4,获取索引4的分数(7,现在失败了,因此不打印任何内容并且不会继续寻找。然后,您还需要在没有更多索引可看的情况下进行编程。假设输入是[4,6],您不希望程序因ArrayIndexOutOfBoundsException而崩溃,因为您的算法一直在列表中向下移动,直到找到不为6的数字为止。

我不会在这里转储一个功能齐全的程序,因为这显然是家庭作业,目的是让您学习和理解Java,而不是学习和理解CTRL / CMD + C的功能和CTRL / CMD + V键:)

,

假设您找到了所要查找的项目,并且该项目位于索引idx中,因此可以在其边界等于arr [idx]时进行迭代

leftidx = idx-1;
while(arr[leftidx]==arr[idx]{
   System.out.println(arr[leftidx]);
   lefidx--;
}
rightidx = idx+1;
while(arr[rightidx]==arr[idx]{
   System.out.println(arr[rightidx]);
   rightidx--;
}