查找(searching)
先上一道阿里的面试题吧
题意是这样描述的,给定一个m行n列的整数矩阵(如图),每行从左到右,每列从上到下都是有序的。判断一个整数k是否在矩阵中出现的最优算法,在最坏的情况下的时间复杂度
1 5 7 9
4 6 10 15
8 11 12 19
14 16 18 21
A–O(mXn)
B–O(m+n)
C–O(log(mXn))
D–O(log(m+n))
只有第一题有点思路,这学期才开始数据结构的学习。在局部有序中进行查找,同样是可以用二分查找法的。为了问题的简化,不妨先假设n=m,那么这个矩阵就是n阶方阵。从主对角线上的元素开始进行二分查找,考虑最坏情况耗时为:log(n)。然后对左下角和右上角的两个n/2阶方阵分别又从主对角线上的元素开始进行二分查找,重复步骤到最后。每一次把矩阵分为了1,2,4,8,2^i个,运用了递归的思想。故时间复杂度应为:T(n)=1*log(n/1)+2log(n/2)+4log(n/4)+2^(i)log(n/2^(i))+…+;观察前几项可以把C,D选项直接排除。对这个级数求和大致可以得到O(2n),从而选项B:O(n+m)是正确的。(其实大O表示法在这里不是严密的,我们也可以选A,因为由大O的定义O(m*n)包含了O(m+n),虽然这并不符合题意)
分类
- 静态查找
1:顺序查找
//数组data,0到length-1都存有数据
for(i=0;i<length;i++)
if(key==data[i]) return i;
return 0;
//数组data,1到length中存有数据
for(i=length;i>0&&key!=data[i];i--);
return i;
//设置哨兵,有唯一出口和单个判断条件
data[0]=key;
for(i=length;key!=data[i];i--);
return i;
2:二分查找
假设树的深度depth是从1开始的,则查找判定树的depth=
⌊logN⌋
or
⌈logN⌉
+1
ASL:成功查找每个元素所需要的平均判定次数
//注意data数组中的数据是从1开始存放的
left=1;
right=length;
Notfind=-1;
while(left<right+1)//left<=right,最好不要带有“=”号
{
mid=(left+right)/2;
if(data[mid]<key) left=mid+1;
else if(data[mid]>key) right=mid-1;
else return mid;
}
return Notfind;
//在这个代码段中如果每次更新left和right用的不是mid+1和mid+1,则当查找的元素不再有序的序列中,就会进入死循环。**注意!在其他程序中的判定条件和更新边界的方法是不同,但是二分的思想是相同的,自己可以写出正确的代码来**
3.黄金分割查找
#include <math.h>
//_CRTIMP double __cdecl ceil (double);向上取整(天花板)
//_CRTIMP double __cdecl floor (double);向下取整(地板)
#define cut 0.618
left=1;
right=length;
Notfind=-1;
while(left<right+1)
{
mid=(int)(left+cut*(right-left));//mid必须是整型
//mid=floor(left+cut*(right-left));
if(data[mid]<key) right=mid-1;
else if(data[mid]>key) left=mid+1;
else return mid;
}
return Notfind;
- 动态查找