一、顺序查找(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)