数组中的二分查找
Posted
技术标签:
【中文标题】数组中的二分查找【英文标题】:Binary Search in Array 【发布时间】:2010-09-19 22:45:07 【问题描述】:我将如何仅使用数组来实现二进制搜索?
【问题讨论】:
查看link 对我来说非常有意义。除了数组,你还可以使用二叉树。 【参考方案1】:确保您的数组已排序,因为这是二进制搜索的关键。
任何索引/随机访问的数据结构都可以进行二分搜索。所以当你说使用“只是一个数组”时,我会说数组是使用二进制搜索的最基本/常见的数据结构。
您可以递归(最简单)或迭代地执行此操作。二进制搜索的时间复杂度是 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
【讨论】:
在计算 mid 时记得注意溢出。 (见googleresearch.blogspot.com/2006/06/…) @Firas Assad,谢谢,更新了代码以显示与防止溢出相关的修复mid = low + ((high - low) / 2)
与 mid = (low + high) / 2
相同。不确定是否使用整数除法,但该算法仍然适用于两个公式。
@NiklasR 除非low+high
产生整数溢出。
中值 =(高 - 低)/2 可以吗?【参考方案2】:
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);
【讨论】:
【参考方案3】:这取决于您是否在数组中重复了一个元素,以及您是否关心多个发现。我在这个实现中有两种方法。其中一个只返回第一个发现,但另一个返回键的所有发现。
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。希望对你有帮助。
【讨论】:
【参考方案4】:单对比版快速简洁
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;
【讨论】:
这是一个if
声明,如果这是一个要求的话。
最后你也应该检查 a[n]。否则找不到例如1 个来自 0,1。
@jarno 与 C 的惯例一样,n
是(从 0 开始的)数组的长度,因此 a[n]
无效。同时bsearch_double((double[])0,1, 2, 1)
有效,返回1
。【参考方案5】:
用Java实现了下面的代码,简单快速 /** * 使用递归的二分搜索 * @作者阿沙达 * */ 公共类 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);
【讨论】:
s/int mid=low+high/2;/int mid=(low+high)/2;/s/return binSearch(arr,low,high-1, num);/return binSearch(arr,low,mid-1, num);/s/return binSearch(arr,low+1,high, num);/return binSearch(arr,mid+1,high, num);/【参考方案6】:这是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))
流程如下:
获取中点 如果中点 == 搜索返回中点 否则,如果高点和低点相同,则返回 -1 如果搜索值大于中点,则将中点+1设为较低值 如果搜索值小于中点,则将中点 1 设为较高值【讨论】:
【参考方案7】:二分查找的短循环:
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;
所以如果左、中、右变量按顺序排列,我们可以在 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],mid 为 q[0],右为 q[1]或者对于所有 3 的 q 是 q[dir]
对于从 0 开始的数组索引或相同:
我们可以使用 p=[0,,nums.length-1] 其中左边是 p[0] 的昵称,中间是 p[1],右边是 p[2],这三个都是 p [1+目录]
。 :)
【讨论】:
感谢您提供答案。您能否编辑您的答案以包括对您的代码的解释?这将有助于未来的读者更好地了解正在发生的事情,尤其是那些刚接触该语言并难以理解概念的社区成员。【参考方案8】:假设数组已排序,这是一个具有 O(log n) 运行时复杂度的 Pythonic 答案:
def binary_search(nums: List[int], target: int) -> int:
n = len(nums) - 1
left = 0
right = n
while left <= right:
mid = left + (right - left) // 2
if target == nums[mid]:
return mid
elif target < nums[mid]:
right = mid - 1
else:
left = mid + 1
return -1
【讨论】:
以上是关于数组中的二分查找的主要内容,如果未能解决你的问题,请参考以下文章