我该如何仅使用数组来实现二分查找?
我该如何仅使用数组来实现二分查找?
请确保数组已排序,因为这是二分查找的关键。
任何索引/随机访问数据结构都可以进行二分查找。所以,当你说“只使用一个数组”时,我会说数组是二分查找最基本/常见的数据结构。
您可以使用递归(最简单)或迭代方法进行二分查找。二分搜索的时间复杂度为O(log N),比线性搜索每个元素检查的O(N)要快得多。以下是来自维基百科的一些示例:二分查找算法:
递归方法:
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 = low + ((high - low) / 2)
和 mid = (low + high) / 2
是相同的。虽然整数除法可能会产生疑问,但算法使用这两个公式仍然有效。 - Niklas Rlow+high
会导致整数溢出。 - jarno(如果有人需要)
自下而上:
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);
}
使用仅数组实现二分查找
二分查找是一种优化的解决方案,用于在数组中搜索元素,因为它通过以下三种方式减少了搜索时间:
如果上述任何情况不满足,则此类元素不存在于数组中。
二分查找的好处
算法步骤
步骤1:使用数组中最低索引和最高索引的floor计算mid index
。
步骤2:将要搜索的元素与位于middle index
的元素进行比较。
步骤3:如果步骤2不满足,则检查所有左侧元素。为此,请将high index = mid index - 1
步骤4:如果步骤3不满足,则检查所有右侧元素。为此,请将low index = mid index + 1
如果没有满足的情况,则返回-1,这意味着要搜索的元素不存在于整个数组中。
代码
# iterative approach of binary search
def binary_search(array, element_to_search):
n = len(array)
low = 0
high = n - 1
while low <= high:
mid = (low + high) // 2
if element_to_search == array[mid]:
return mid
elif element_to_search < array[mid]:
high = mid - 1
elif element_to_search > array[mid]:
low = mid + 1
return -1
array = [1, 3, 5, 7]
element_to_search = 8
print(binary_search(array=array,
element_to_search=element_to_search))
递归代码也可以用于二分查找。无论是迭代还是递归,时间复杂度都为O(logn)
,但是在考虑空间复杂度时,迭代方法将获胜,因为它只需要O(1)
的空间复杂度,而对于递归算法,函数调用栈中将使用三个函数调用,因此空间复杂度变为O(logn)
。下面是递归解决方案。
def recurs_binary_search(arr, element, low, high):
if low > high:
return -1
mid = (low + high) // 2
if arr[mid] == element:
return mid
elif arr[mid] > element:
return recurs_binary_search(arr,element, low, mid - 1)
else:
return recurs_binary_search(arr,element, mid + 1, high)
array = [1, 3, 5, 7]
element_to_search = 7
low = 0
high = len(array) - 1
print(recurs_binary_search(arr=array, element=element_to_search,
low=low, high=high))
二分查找算法的伪代码流程:
The Iterative Approach
public int binarySearch(int[] arr, int size, int key){
int startIndex = 0;
int endIndex = arr.length - 1;
int midIndex = startIndex + (endIndex-startIndex)/2 ;
while (startIndex <= endIndex){
if(key == arr[midIndex]) {
return midIndex;
}else if (key > arr[midIndex]){
startIndex = midIndex + 1;
}else {
endIndex = midIndex -1;
}
midIndex = startIndex + (endIndex-startIndex)/2 ;
}
return -1; // Target element not found
}
The Recursive Approach
public int binarySearchByRecursion(int[] arr, int key, int startIndex, int endIndex){
if(startIndex > endIndex){
return -1;
}
int midIndex = startIndex + (endIndex - startIndex) / 2;
if(key == arr[midIndex]) {
return midIndex;
}else if (key > arr[midIndex]){
return binarySearchByRecursion( arr, key, midIndex + 1, endIndex);
}else {
return binarySearchByRecursion(arr, key, startIndex, midIndex -1);
}
}
在这里发现全面的解决方案 https://github.com/Amir36036/ds/blob/array/src/main/java/org/ds/array/BinarySearch.java
在Java中实现了下面的代码,简单而快速 /** * 使用递归进行二分查找 * 作者:asharda * */ public class 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);
}
}
这要看你的数组中是否有一个元素重复以及你是否在意多个找到的情况。我在这个实现中有两种方法。其中一种只返回第一个找到的结果,而另一种则返回关键字的所有发现。
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。希望能对您有所帮助。
这里是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))
以下是流程:
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
二分查找的短循环:
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语法,我们需要使用q={'-1':0,1:nums.length-1},其中q[-1]表示左侧名称,q[0]表示中间,q[1]表示右侧,或者对于所有三个元素都是q[dir]。
或者对于从0开始的数组索引也可以这样:
我们可以使用p=[0,,nums.length-1],其中p[0]表示左侧昵称,p[1]表示中间,p[2]表示右侧,对于所有三个元素都是p[1+dir]。
. :)
单个比较版本快速且简洁
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
语句。 - Jedn
通常表示数组的长度(从0开始),因此a[n]
是无效的。与此同时,bsearch_double((double[]){0,1}, 2, 1)
是有效的,并返回1
。 - Jed