二分查找
概念:
二分查找是一种高效的查找方式,不过要求线性表(注意与非线性表之间的区别,具有四个特征)必须采用顺序存储结构(注意不是链式存储结构),并且元素是有序排列的。
要求:
我们要从一个序列中查找一个元素的时候,二分查找是一种非常快速的查找算法,二分查找又叫折半查找。它对要查找的序列有两个要求,一是该序列必须是有序的(即该序列中的所有元素都是按照大小关系排好序的,升序和降序都可以,本文假设是升序排列的),二是该序列必须是顺序存储的。图1展示的就是一个能进行二分查找的序列。
原理:
-
如果待查序列为空,那么就返回-1,并退出算法;这表示查找不到目标元素。
-
如果待查序列不为空,则将它的中间元素与要查找的目标元素进行匹配,看它们是否相等。
-
如果相等,则返回该中间元素的索引,并退出算法;此时就查找成功了。
-
如果不相等,就再比较这两个元素的大小。
-
如果该中间元素大于目标元素,那么就将当前序列的前半部分作为新的待查序列;这是因为后半部分的所有元素都大于目标元素,它们全都被排除了。
-
如果该中间元素小于目标元素,那么就将当前序列的后半部分作为新的待查序列;这是因为前半部分的所有元素都小于目标元素,它们全都被排除了。
-
在新的待查序列上重新开始第1步的工作。
二分查找之所以快速,是因为它在匹配不成功的时候,每次都能排除剩余元素中一半的元素。因此可能包含目标元素的有效范围就收缩得很快,而不像顺序查找那样,每次仅能排除一个元素。
时间复杂度:log(n)
思路:
1.首先我们看到第一排为一个数组,下面的数字为其下标,数组元素是升序排列的,需要找到的元素是31
2.开始左指针在0下标的位置,右指针在9下标的位置,中间数mid为(0+9)/2=4,下标4位置的元素是27,31>27所以右指针移动到下标7位置(5+9/2=7)上,左指针变为下标5(4+1=5)位置
3.继续找mid坐标为下标(5+7)/2=6,判断33与31比较,33<31,左指针变为下标5,右指针也变为下标5,判断31=31
4.找到31位置为下标5
Go实现
package main
import "fmt"
func BinarySearch(arr []int, left int, right int, num int)(bool,int){
// 判断leftIndex是否大于rightIndex
if left > right {
return false,-1
}
mid := (left + right) / 2
if (arr)[mid] > num {
// 说明要找的数,在 left 至 mid-1
BinarySearch(arr, left, mid-1, num)
} else if (arr)[mid] < num {
// 说明要找的数,在 mid+1 至 right
BinarySearch(arr, mid+1, right, num)
} else {
return true,mid
}
return false,-1
}
func main() {
arr := []int{10,14,19,26,27,31,33,35,42,44}
fmt.Println(BinarySearch(arr, 0, len(arr), 31))
}
PHP实现
<?php
function BinarySearch($arr,$num){
$left = 0;
$right = count($arr)-1;
while($left<=$right){
$mid = ($left+$right)/2;
if($arr[$mid]<$num){
$left = $mid+1;
}elseif ($arr[$mid]>$num){
$right = $mid-1;
}else {
return true,$mid;
}
}
return false,-1;
}
$arr = array(10,14,19,26,27,31,33,35,42,44);
$a = BinarySearch($arr,31);
var_dump($a);