二分查找(Binary Search)

一、顺序查找(linear search)
问题描述:在一个给定的序列A[]中查找指定元素v,若查找成功则返回元素在数组中的下标,否则返回-1。

C++实现:

//简单线性查找 
int linearSearch(int *a, int n, int key)
{
    for(int i=0; i<n; i++)
    {
        if(a[i] == key)
        {
            return i;
        }
    }
    return -1;
}

(1)最好情况下,比较一次就查找成功

(2)最坏情况下,比较n次查找成功或查找失败

(3)假设数组中的n个元素以等可能的概率被查找,且待查找的数在数组中,则平均查找长度为: (n+1)/2

(4)综上,线性查找的时间复杂度为:Ο(n)

二、二分查找(binary search)

思想:当待查找序列是有序序列时, 不用像线性查找那样一个接一个的比较,我们可以把序列中点和检索值v进行比较,快速缩小比较范围,从而节省时间。

1.迭代实现

//binary search iterative implementation 
int binarySearch(int *a, int n, int key)
{
    int low = 0;
    int high = n-1;
    int mid ;
    
    while(low <= high)
    {
        mid = (low + high)/2;
        if(a[mid] == key)
            return mid;
        else if(a[mid] < key)
            low = mid + 1;
        else high = mid - 1;
    }
    return -1;
}

2.递归实现

//binary search recursive implementation
int binarySearch(int *a, int low, int high, int key)
{
    if(low <= high)
    {
        int mid = (low + high)/2;
        if(a[mid] == key)
            return mid;
        else if(a[mid] < key)
            return binarySearch(a,mid+1,high,key);
        else
            return binarySearch(a,low,mid-1,key);
    }
    return -1;
}

算法时间复杂度分析:

(1)根据迭代算法我们可以画出查找过程的判定树,判定树的高度为lgn,也就是最多比较lgn次,因而算法的时间复杂度为Ο(lgn)

(2)由于问题的输入规模不断减半,所以递归最多lgn层,每次递归代价为常数,算法复杂度为Ο(lgn )

==================================================================================

补充问题:

集合S由n个整数构成,给定一个整数x,判断集合中是否存在两个数,其和为x,存在返回true,否则返回false。要求算法的时间复杂度为O(nlgn)

分析:

(1)把n个元素按非递减排序 复杂度可以达到O(nlgn),如归并排序,堆排序

(2)从第一个元素开始运用二分查找,对于元素 a[i] 检索是否存在元素x-a[i]

核心代码:

bool exist(int* a, int n)
{
    mergeSort(a,n);
    for(int i=0; i<n-1; i++)
    { 
        if(binarySearch(a,0,n-1,x-a[i]) != -1) 
        { 
            return true;  
        }
    } 
    return false;
}

由于外层循环n次,循环体内的二分查找复杂度为O(lgn),该核心代码的复杂度为O(nlgn)

综上,算法总的复杂度为O(nlgn)

点赞