重新认识二分查找算法
2016-01-04 13:36
281 查看
自己也曾写过二分查找算法,可是认识却有点模糊,或者说对算法的流程理解的并不是很透彻。《编程珠玑》里提到用循环不变式的三个性质来检验算法的正确性,即:
1.初始化:保证循环开始前初始条件是正确的。
2.保持:如果在循环的某一次迭代开始之前它是正确的,那么,在下一次迭代开始之前,它也应该保持正确。
3.终止:循环能够终止,并且可以得到期望的结果。
如果key在数组中可能重复,要求返回key出现的第一个下标
对于要求返回最后一个等于key的位置x的算法,情况下更复杂一些.当array[mid]==key时,x可能存在于(mid,…,right)中,此时令left=mid,循环减少mid-left。由于mid通过除法运算舍去小数部分后更靠近left,所以mid==left时有left+1==right或left==right,不同于求第一次出现位置时的right==mid只有一种情况,与上例的主要区别也就在这里。因此循环终止条件应设为left<right-1.
递归版本的二分搜索原理与迭代版本相同,需要注意递归的不变式为判断语句,迭代为循环。
1.初始化:保证循环开始前初始条件是正确的。
2.保持:如果在循环的某一次迭代开始之前它是正确的,那么,在下一次迭代开始之前,它也应该保持正确。
3.终止:循环能够终止,并且可以得到期望的结果。
int BinSearch(int *array, int size, int key) //前置条件是数组已是升序排列 { if(!array) return -1; int left = 0, right = size, mid; while(left <= right) { mid = left + (right - left)/2; //或右移一位,这种写法是为了防止溢出 if(array[mid] < key) left = mid + 1; else if(array[mid] > key) right = mid - 1; else return mid; } return -1; }
如果key在数组中可能重复,要求返回key出现的第一个下标
int BinSearchFirst(int *array, int size, int key) //前置条件是数组已是升序排列 { if(!array) return -1; int left = 0, right = size, mid; while(left < right) { mid = left + (right - left)/2; //或右移一位,这种写法是为了防止溢出 if(array[mid] >= key) right = mid; //循环减少right-mid,如果right==mid(此时构成死循环),有right==left,因此循环终止条件不包括== else left = mid + 1; //循环减少mid+1-left,至少减少为1 } if(array[left] == key) //终止时有left>=right,若left>right,则left上一步有left=mid+1,mid+1>right,退出mid==right,left==right,循环一开始就不会出现 return left; //若left==right,如果array[left]==key,返回left即可 return -1; }
对于要求返回最后一个等于key的位置x的算法,情况下更复杂一些.当array[mid]==key时,x可能存在于(mid,…,right)中,此时令left=mid,循环减少mid-left。由于mid通过除法运算舍去小数部分后更靠近left,所以mid==left时有left+1==right或left==right,不同于求第一次出现位置时的right==mid只有一种情况,与上例的主要区别也就在这里。因此循环终止条件应设为left<right-1.
int BinSearchLast(int *array, int size, int key) { if(!array) return -1; int left = 0, right = size, mid; while(left < right-1) { mid = left + (right - left)/2; if(array[mid] <= key) left = mid; else right = mid - 1; } if(array[right] == key) return right; else if(array[left] == key) return left; else return -1; }
递归版本的二分搜索原理与迭代版本相同,需要注意递归的不变式为判断语句,迭代为循环。
//递归版本的二分搜索 int Search(int *array, int left, int right, int key) { int mid = left + (right-left)/2; if(left <= right) { if(array[mid] < key) return Search(array, mid+1, right, key); else if(array[mid] > key) return Search(array, left, mid-1, key); else return mid; } else return -1; } int BinSearch(int *array, int size, int key) { if(!array) return -1; int left = 0, right = size; return Search(array, left, right, key); }
相关文章推荐
- 使用Jenkins搭建持续集成(CI)环境
- Mongodb 数据类型及Mongoose常用CURD
- oracle12c怎么pdb容器不会自动关闭
- Android CountDownTimer 倒计时器
- Brackets 配置
- linux 命令 —— find
- 为何ViewController释放后不走dealloc
- Android端ORM框架——RapidORM
- Jenkins入门系列之——01第一章 Jenkins是什么?
- 鼓捣电视盒子
- 171,.plist文件中字典数据转成程序模型
- SAP R3 采购申请相关简单操作 :附Oracle后台数据库对应表明细。
- AngularJS 表格
- Jenkins入门系列之——02第二章 Jenkins安装与配置
- 设计模式(一)
- 利用C++11实现一个自动注册的工厂
- AndroidStudio快捷键(非复制粘贴)
- 源码安装mongoDB
- Mac环境下,numpy升级问题。
- codevs1796-最小完全图