上次面试栽到了二分查找,最简单的问题上,以至于一直不想面对,但是不论怎样,还是要不断成长,不断提升,不会的东西就要不断提升,才能得到真正想要的东西。
好啦,回归正题,二分查找又叫二分查找,它的前提是线性表中的记录必须是有序的,通常常见的就是由小到大排序,查找的基本思想是:在有序表中,取中间记录作为比较对象,若给定值与中间记录的关键字相等,则查找成功;若给定值小于中间记录的关键字,则在中间记录的左半区继续查找;若给定值大于中间记录的关键字,则在中间记录的右半区查找。不断重复上述过程,直到查找成功,或者所有查找区域无记录,查找失败为止。
(1)先来看最基础时候的情况:
int binary_search(int *a, int n, int key)
{
int low, high, mid;
low = 0; high = n;
while (low <= high)
{
mid = (low + high) / 2;
if (key < a[mid])
{
high = mid - 1;
}
else if (key > a[mid])
{
low = mid + 1;
}
else
return mid;
}
return 0;
}
(2)当然有很多变形的情况啦,咱们先来看第一种,还是有序数组,但是数字有重复,具体有几个重复不知道,现在要求是要找到第一个出现的位置。
这个题第一次并没有多少想法,甚至记得刷过剑指offer上的内容,当时想着定义一个哈希表,哈希表的键值是字符,而值就是该字符出现的次数,其实题意完全不相关,也是佩服自己当时为什么会那么想,这个题其实可以这么想,既然要找第一次出现的某个数,而且这个数也有可能重复,那我其实让它停止的条件可以是判断第一个小于当前值的下标,那么再判断这个下标加上1是否小于数组的长度,如果小于数组的长度,ok那么最终的输出就是要求的输出。
int mid;
int binary_search(int *a, int n, int key,int &low)
{
int high;
low = 0; high = n;
while (low <= high)
{
mid = (low + high) / 2;
if (key <=a[mid])
{
high = mid - 1;
}
else
low = mid + 1;
}
return low<n ?low:-1;
}
这样返回的low值就是最终要求的输出,返回的最终值就是加1之后的结果。
(3)第三种情况,找到重复数字最后一个出现的位置。这种情况跟第二种情况同理,其实我们要找的就是第一个大于这个数的位置,那么最终输出的位置就是当前位置减去1,再去判断减去1之后是不是大于-1,大于那么OK。
int mid;
int binary_search(int *a, int n, int key,int &low)
{
int high;
low = 0; high = n;
while (low <= high)
{
mid = (low + high) / 2;
if (key <a[mid])
{
high = mid - 1;
}
else
low = mid + 1;
}
return (low-1>0 && (a[low-1]==key))?low-1:-1;
}
注意if条件里只要小于mid值那么一直进行这样的操作,所以最后返回的结果就是减去1之后的结果。
(4)查找数组中第一个大于某个数的最小标,其实跟3的情况一样,就是返回的值不一样,返回的值就不需要减去1了,返回为
return low<=n?low:-1;
(5)查找数组中第一个小于某个数的最大标,跟2的情况很像,只是返回值变下,因为(2)的思想最终加了1,所以最终输出的时候记得减去1,输出代码为:
return (low - 1 >= 0) ? low - 1 : -1;
(6)对于判断一个数组中某个数的出现次数,其实是可以调用上述的函数,先求一个数第一次出现的位置记为first,再记录最后一个出现的位置就为last,那么出现的次数就是last-first+1啦。
变形的还有很多很多,学习的道路很长很长,加油吧,参考这篇文章写的,具体也可以参考这篇。