二分查找------每次折一半------用于对有序排列的指定数字进行查找(无序是无法查找的,因相互之间大小排列非一致顺序,会漏查数字)
C语言中的典例,对整形数组进行二分查找。
如图,我们首先定义好数组,下标(包括中间下标值——mid),查找值,和一个标记值(确定是否找到查找值)
sizeof——既是关键字也是操作符,专门用于计算sizeof后内容的类型长度(存储大小),单位是字节,其返回类型是 size_t
上一图中我们对 right 的类型定义的int(整型),在运行过程中可能会出现精度丢失的问题,如上图二。出现的原因是 int(整型)表示的是有符号整数,而 size_t 表示的是无符号整数,虽然二者在32位机器下都是4字节(32位比特位),但如果我们强行将size_t的值赋值给int,就可能会丢失精度,所以编译器给出警告(不影响运行)。
既然要多次查找,我们自然要引入循环,循环判断条件设置如上图中注释所示。
对于循环内容部分,我们首先要对下标中间值赋值,若将 mid 赋值放置于循环外则会除了查找值为5外,不会显示任何输出结果(如上图二图三所示)。
(原因如下:left和right靠mid来修改,同样的mid也靠left和right改变,我们把mid赋值放在循环外,这样我们mid初始值为4,假设我们还是把key赋7,那么进入下面循环里 if 的条件判断,5<7所以 left 被重新赋值为4+1=5,但是left被重新赋值因为是在循环里,所以只会直接回到 while 循环的条件判断中,而不会回到循环外 “mid = (left + right) / 2;” 这一行代码中去改变这里left的值,所以mid值就不会随着left值改变而改变)
对于循环过程中 当中间下标所对应的值小于查找值时,代表着中间下标所对应的值及其前面的值都比查找值key小,但不确定右下标对应值与查找值关系,所以左下标加 1 来进一步二分查找。反之同理。
循环最后记得加上break跳出循环(找到)
上述 while 循环也可以改成 for 循环(如下图),至于 for 循环中为何省去初始化部分和调整部分先思考,在文章最后解答
我们在执行完循环过程后,循环中有两种结果:一: find 标记值已经找到指定数值。 二: 根本找不到对应数值。
所以我们在最后还要加上一组条件判断,如果找到了对应数值即 find==1(注意此处是等于一,对应上面循环中找到对应值,从而将find赋值为1的情况),同时打印查找值的下标;否则即为没找到,就打印没找到。如下图所示:
整体代码:
回答上面 for 循环的问题:1、对于省略初始化部分:for循环中的初始化部分就是用于初始化循环控制变量,在循环前我们已经有了定义并初始化,所以无需重复一次(加上也不会出错);
2、对于省略调整部分:for循环中的调整部分就是每次循环结束后更新循环控制变量的值。在上面程序中调整部分实际上已经包含在 for
循环体内部。在二分查找的每次迭代中,根据 arr[mid]
与 key
的比较结果,会更新 left
或 right
的值,从而缩小查找的范围。