数组中的二进制搜索

时间:2008-10-30 06:01:44

标签: algorithm arrays language-agnostic search binary-search

如何仅使用数组实现二进制搜索?

7 个答案:

答案 0 :(得分:40)

确保您的数组已排序,因为这是二进制搜索的关键。

任何索引/随机访问数据结构都可以进行二进制搜索。所以当你说“只是一个数组”时,我会说数组是采用二进制搜索的最基本/最常见的数据结构。

您可以递归(最简单)或迭代地执行此操作。二进制搜索的时间复杂度是O(log N),这比在O(N)处检查每个元素的线性搜索快得多。以下是Wikipedia: Binary Search Algorithm的一些示例:

递归:

BinarySearch(A[0..N-1], value, low, high) {  
    if (high < low)  
        return -1 // not found  
    mid = low + ((high - low) / 2) 
    if (A[mid] > value)  
        return BinarySearch(A, value, low, mid-1)  
    else if (A[mid] < value)  
        return BinarySearch(A, value, mid+1, high)  
    else
       return mid // found
    }

迭代:

  BinarySearch(A[0..N-1], value) {
   low = 0
   high = N - 1
   while (low <= high) {
       mid = low + ((high - low) / 2)
       if (A[mid] > value)
           high = mid - 1
       else if (A[mid] < value)
           low = mid + 1
       else
           return mid // found
   }
   return -1 // not found
}

答案 1 :(得分:0)

单一比较版本快速而简洁

int bsearch_double(const double a[], int n, double v) {
  int low = 0, mid;
  while (n - low > 1) {
    mid = low + (n - low) / 2;
    if (v < a[mid]) n   = mid;
    else            low = mid;
  }
  return (low < n && a[low] == v) ? low : -1;
}

答案 2 :(得分:0)

这取决于你是否在你的数组中重复了一个元素,或者你是否关心多个发现。我在这个实现中有两种方法。其中一个只返回第一个发现,但另一个返回密钥的所有发现。

import java.util.Arrays;

public class BinarySearchExample {

    //Find one occurrence
    public static int indexOf(int[] a, int key) {
        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;
    }

    //Find all occurrence
    public static void PrintIndicesForValue(int[] numbers, int target) {
        if (numbers == null)
            return;

        int low = 0, high = numbers.length - 1;
        // get the start index of target number
        int startIndex = -1;
        while (low <= high) {
            int mid = (high - low) / 2 + low;
            if (numbers[mid] > target) {
                high = mid - 1;
            } else if (numbers[mid] == target) {
                startIndex = mid;
                high = mid - 1;
            } else
                low = mid + 1;
        }

        // get the end index of target number
        int endIndex = -1;
        low = 0;
        high = numbers.length - 1;
        while (low <= high) {
            int mid = (high - low) / 2 + low;
            if (numbers[mid] > target) {
                high = mid - 1;
            } else if (numbers[mid] == target) {
                endIndex = mid;
                low = mid + 1;
            } else
                low = mid + 1;
        }

        if (startIndex != -1 && endIndex != -1){
            System.out.print("All: ");
            for(int i=0; i+startIndex<=endIndex;i++){
                if(i>0)
                    System.out.print(',');
                System.out.print(i+startIndex);
            }
        }
    }

    public static void main(String[] args) {

        // read the integers from a file
        int[] arr = {23,34,12,24,266,1,3,66,78,93,22,24,25,27};
        Boolean[] arrFlag = new Boolean[arr.length];
        Arrays.fill(arrFlag,false);

        // sort the array
        Arrays.sort(arr);

        //Search
        System.out.print("Array: ");
        for(int i=0; i<arr.length; i++)
            if(i != arr.length-1){
                System.out.print(arr[i]+",");
            }else{
                System.out.print(arr[i]);
            }

        System.out.println("\nOnly one: "+indexOf(arr,24));
        PrintIndicesForValue(arr,24);

    }

}

有关详细信息,请访问https://github.com/m-vahidalizadeh/foundations/blob/master/src/algorithms/BinarySearchExample.java。我希望它有所帮助。

答案 3 :(得分:0)

用Java实现下面的代码,简单快捷     / **      *使用递归进行二进制搜索      * @author asharda      *      * /     公共类BinSearch {

  /**
   * Simplistic BInary Search using Recursion
   * @param arr
   * @param low
   * @param high
   * @param num
   * @return int
   */
  public int binSearch(int []arr,int low,int high,int num)
  {
    int mid=low+high/2;
    if(num >arr[high] || num <arr[low])
    {
      return -1;
    }

    while(low<high)
    {
      if(num==arr[mid])
      {
        return mid;

      }
      else  if(num<arr[mid])
      {
       return  binSearch(arr,low,high-1, num);
      }

      else  if(num>arr[mid])
      {
        return binSearch(arr,low+1,high, num);
      }

    }//end of while

    return -1;
  }

  public static void main(String args[])
  {
    int arr[]= {2,4,6,8,10};
    BinSearch s=new BinSearch();
    int n=s.binSearch(arr, 0, arr.length-1, 10);
    String result= n>1?"Number found at "+n:"Number not found";
    System.out.println(result);
  }
}

答案 4 :(得分:0)

Javascript(ES6)中的二进制搜索

(如果有人需要)

<强>自下而上:

function binarySearch (arr, val) {
    let start = 0;
    let end = arr.length - 1;
    let mid;

    while (start <= end) {
        mid = Math.floor((start + end) / 2);

        if (arr[mid] === val) {
            return mid;
        }
        if (val < arr[mid]) {
            end = mid - 1;
        } else {
            start = mid + 1;
        }
    }
    return -1;
}

<强>递归

function binarySearch(arr, val, start = 0, end = arr.length - 1) {
    const mid = Math.floor((start + end) / 2);

    if (val === arr[mid]) {
        return mid;
    }
    if (start >= end) {
        return -1;
    }
    return val < arr[mid]
        ? binarySearch(arr, val, start, mid - 1)
        : binarySearch(arr, val, mid + 1, end);
}

答案 5 :(得分:0)

这是python编程语言的简单解决方案:

def bin(search, h, l):
    mid = (h+l)//2
    if m[mid] == search:
        return mid
    else:
        if l == h:
            return -1
        elif search > m[mid]:
            l = mid+1
            return bin(search, h, l)
        elif search < m[mid]:
            h = mid-1
            return bin(search, h, l)
    
m = [1,2,3,4,5,6,7,8]
tot = len(m)
print(bin(10, len(m)-1, 0))

流程如下:

  • 获得中点
  • 如果中点==搜索返回中点
  • else 如果高低点相同则返回-1
  • 如果搜索值大于中点,则将中点+1设为较低值
  • 如果搜索值小于中点,则将中点 1 设为较高值

答案 6 :(得分:0)

二分查找的短循环:

function search( nums, target){    
    for(let mid,look,p=[0,,nums.length-1]; p[0]<=p[2]; p[look+1]=mid-look){
        mid = (p[0] + p[2])>>>1
        look = Math.sign(nums[mid]-target)
        if(!look) 
            return mid
    }
    return -1
}

想法正在取代:

if(nums[mid]==target)
    return mid
else if(nums[mid]>target)
    right = mid - 1
else //here must nums[mid]<target
    left  = mid + 1

如果观察,则具有更多的默契(并且可能需要更少的计算) 前者等于:

switch(dir=Math.sign(nums[mid]-target)){
    case -1: left  = mid - dir;break;
    case  0: return  mid
    case  1: right = mid - dir;break;
}

所以如果 left,mid,right 变量按顺序排列,我们可以在 C 指针意义上向它们全部抛出 &mid[-1,0,1] :

dir=Math.sign(nums[mid]-target)
&mid[dir] = mid - dir

现在我们得到了循环体,所以我们可以构造二分查找:

while(dir && left <= right){
    mid = (left + right)>>>2
    dir=Math.sign(nums[mid]-target)
    &mid[dir] = mid - dir
}

之后我们只是:

return [dir,mid]

有语义的

for dir == -1 then nums[mid]<target<nums[mid+1] // if nums[mid+1 ] in start seaching domain
for dir ==  0 then mid is place of target in array 
for dir ==  1 then nums[mid-1]<target<nums[mid] // if nums[mid-1 ] in start seaching domain        

所以在一些更人性化的伪代码javascript函数中等效:

    function search( nums, target){
        let dir=!0,[left, mid, right]=[0, , nums.length-1]
        while(dir && left <=right){
            mid = (left + right)>>>1
            dir = Math.sign(nums[mid]-target)
            &mid[dir]=mid - dir
         }
         return [dir, mid]
    }

对于 js sintax,我们需要使用 q={'-1':0,1:nums.length-1} 其中 q[-1] 的左名称,q[0] 的 mid 和 q[1] 的右名称或者对于所有 3 的 q 是 q[dir]

或从 0 开始的数组索引相同:

我们可以使用 p=[0,,nums.length-1] 其中左边是 p[0] 的 nikname,p[1] 的中间和 p[2] 的右边,这对于所有 3 个都是 p [1+目录]

。 :)