二分查找是一种查找算法,指的是在一个有序且没有重复的数组中,查找某个指定的元素,并返回指定元素的位置,如果没有找到,则返回-1。 二分查找的原理也是分治思想,即定位在指定区间n-m的中间元素k,判断中间元素k跟要查找的值是否相等,如果相等就返回k,如果大于就m=k-1,如果小于就n=k+1,继续递归处理,直到n>m。 二分查找逻辑中易出错点:
1.循环退出条件是n<=m,不是n<m。
2.mid取值算法最好是n+((m-n)>>1),不要用最普通的(n+m)/2,因为n+m有可能很大值导致int类型越界,除2的操作没有位运算快。 二分查找的时间复杂度是logn。
二分查找算法是有使用场景的:
1.数据结构采用数组。【==
2.数据是有序的且非重复元素,如果无序还要使用排序算法对数组进行排序操作,然后再进行二分查找。
3.数据量过小的时候不适用,用for循环遍历也可以。
4.数据量过大的时候不适用,因为数组的内存空间需要连续的,如果数据量过大,对连续内存空间要求过高,数组可能无法装下。
以上摘抄自课程中的优质笔记
如果数据不断增删,维护数组有序的成本过高,不适合用二分。
如何编程实现“求一个数的平方根”?要求精确到小数点后 6 位
low = 0 mid = x / 2 high = x while abs(mid ** 2 - x) > 0.000001: if mid ** 2 < x: low = mid else: high = mid mid = (low + high) / 2 return mid
我刚才说了,如果数据使用链表存储,二分查找的时间复杂就会变得很高,那查找的时间复杂度究竟是多少呢?如果你自己推导一下,你就会深刻地认识到,为何我们会选择用数组而不是链表来实现二分查找了。
说说第二题吧,感觉争议比较大:
假设链表长度为n,二分查找每次都要找到中间点(计算中忽略奇偶数差异):
第一次查找中间点,需要移动指针n/2次;
第二次,需要移动指针n/4次;
第三次需要移动指针n/8次;
…
以此类推,一直到1次为值
总共指针移动次数(查找次数) = n/2 + n/4 + n/8 + …+ 1,这显然是个等比数列,根据等比数列求和公式:Sum = n - 1.
最后算法时间复杂度是:O(n-1),忽略常数,记为O(n),时间复杂度和顺序查找时间复杂度相同
但是稍微思考下,在二分查找的时候,由于要进行多余的运算,严格来说,会比顺序查找时间慢