编程之美-程序改错及扩展问题
2011-09-02 14:23
239 查看
原文的大意是这样的,要求写一个二分查找算法,并且当要查找的数出现不止一次时,返回最后那个数的下标。然后给你一段有错的代码,请你改。
这段有错的代码是这样的(我作了简化):
文中指出了代码中的错误,一是第7行(l+u)可能溢出,二是当程序运行到l=u-1时,计算出的m就与l相等,如果这时不幸地第8行的条件成立,那么就会进入死循环,因为这次迭代没有改变l和u的值,无论再迭代多少遍也不会了。
这两点分析都很正确,但接下来作者给出的修改版本,不仅完全不是在上面代码的基础上改,而且给出的代码逻辑复杂、混乱,缺乏一致性。
下面我将分析上面这段有错代码,给出自己的修改,然后再分析作者给出的版本。
上面代码的思想是清晰的,维护一个循环不变式:如果要找的数存在的话,它下标一定在区间[ l , u ]中,然后通过迭代,不断缩小区间,直到退化成一个点,最后检测这个点是不是目标值。循环体中对不变式的维护都没有错。问题就是怎样避免第8行的把m直接赋给l。题目要求返回最后一个满足的数,所以在循环体中,当检测到相等时,一不能立刻就返回,二不能缩减区间的后半段。要维护这样一个不变式,这个赋值在所难免。我能想到的唯一的办法就是,当l=u-1时,就退出循环,然后先后检查此时的a[u]和a[l]。
所以我的修改是这样的:
接下来,我要分析一下作者的修改,他的代码大意是这样的:
我们先无视注释,我完全搞不懂注释,文中也不解释清楚。从循环体的if-else语句判断,他要维护的不变式是考察区间[l, u),注意是“左闭右开”,要找的数下标一定在这个区间内,如果存在的话。而看他对区间端点的赋初值,u=e,把a[e]给排除在外了。那要找的数就是a[e]怎么办呢?他有这条语句把关呢,if (a[u] == v) return u;后面还十分堂皇地加了注释。其实如果初值正确的话,只需要检测a[l]即可,因为a[u]这个值根本不在我们要考察的区间里。
所以我对作者的版本的改法是:
这段有错的代码是这样的(我作了简化):
/* b和e是查找区间的两端,v是要找的数 */ int bsearch(int a[], int b, int e, int v) { int l = b; int u = e; while (l < u) { int m = (l + u) / 2; if (a[m] <= v) l = m; else u = m – 1; } return a[u]==v? u:-1; }
文中指出了代码中的错误,一是第7行(l+u)可能溢出,二是当程序运行到l=u-1时,计算出的m就与l相等,如果这时不幸地第8行的条件成立,那么就会进入死循环,因为这次迭代没有改变l和u的值,无论再迭代多少遍也不会了。
这两点分析都很正确,但接下来作者给出的修改版本,不仅完全不是在上面代码的基础上改,而且给出的代码逻辑复杂、混乱,缺乏一致性。
下面我将分析上面这段有错代码,给出自己的修改,然后再分析作者给出的版本。
上面代码的思想是清晰的,维护一个循环不变式:如果要找的数存在的话,它下标一定在区间[ l , u ]中,然后通过迭代,不断缩小区间,直到退化成一个点,最后检测这个点是不是目标值。循环体中对不变式的维护都没有错。问题就是怎样避免第8行的把m直接赋给l。题目要求返回最后一个满足的数,所以在循环体中,当检测到相等时,一不能立刻就返回,二不能缩减区间的后半段。要维护这样一个不变式,这个赋值在所难免。我能想到的唯一的办法就是,当l=u-1时,就退出循环,然后先后检查此时的a[u]和a[l]。
所以我的修改是这样的:
int bsearch(int a[], int b, int e, int v) { int l = b; int u = e; while (l < u -1) { int m = l + (u – l) * 0.5;//原来的/2并没错,但*0.5可以减少CPU时钟周期 if (a[m] <= v) l = m; else u = m – 1; } if (a[u] == v) return u; else if (a[l] == v) return l; else return -1;
接下来,我要分析一下作者的修改,他的代码大意是这样的:
int bsearch(int a[], int b, int e, int v) { int l = b; int u = e; //循环结束有两种情况: //若l为偶数则l==u //否则,l==u-1 while (l < u -1) { int m = l + (u – l)/ 2; if (a[m] <= v) l = m; else { //不需要m-1,防止l==u 为什么呢?不明白 u = m; } } if (a[u] == v) return u; //先判断序号最大的值 else if(a[l] == v) return l; else return -1; }
我们先无视注释,我完全搞不懂注释,文中也不解释清楚。从循环体的if-else语句判断,他要维护的不变式是考察区间[l, u),注意是“左闭右开”,要找的数下标一定在这个区间内,如果存在的话。而看他对区间端点的赋初值,u=e,把a[e]给排除在外了。那要找的数就是a[e]怎么办呢?他有这条语句把关呢,if (a[u] == v) return u;后面还十分堂皇地加了注释。其实如果初值正确的话,只需要检测a[l]即可,因为a[u]这个值根本不在我们要考察的区间里。
所以我对作者的版本的改法是:
int bsearch(int a[], int b, int e, int v) { int l = b; int u = e+1; //有改动 while (l < u -1) { int m = l + (u – l)* 0.5; if (a[m] <= v) l = m; else u = m; } return a[l]==v? l:-1; //有改动 }
相关文章推荐
- 编程之美-程序改错及扩展问题
- [编程之美] PSet3.11 程序改错:二分查找与扩展
- 编程之美,3.11程序改错, 二分扩展
- 解决高版本Stable Beta扩展程序强制停用问题
- UNIX环境高级编程中的11章程序11-2编译问题---undefined reference to `pthread_create'
- 由于扩展配置问题而无法提供您请求的页面。如果该页面是脚本,请添加处理程序。如果应下载文件,请添加MIME映射
- 你可能不知道的编程小问题:程序基本概念
- 编程之美---->蚂蚁爬杆之扩展问题,第i个蚂蚁什么时候走出木杆
- vs2005下Windows Shell扩展编程完全指南例子一中的问题解决
- 编程之美-MIN(1)一排石头的游戏 扩展问题
- 编程之美 2.3寻找发帖‘水王’ 扩展问题
- 编程之美 - 满足条件的两个数字及扩展问题
- WCF HTTP 错误 404.3 - Not Found(由于扩展配置问题而无法提供您请求的页面。如果该页面是脚本,请添加处理程序。如果应下载文件,请添加 MIME 映射。)
- HTTP 错误 404.3 NOT FOUND 由于扩展配置问题而无法提供您请求的页面。如果该页面是脚本,请添加处理程序。如果应下载文件,请添加MIME映射。
- 编程之美 2.3 寻找发帖水王扩展问题
- TTP 错误 404.3 - Not Found 由于扩展配置问题而无法提供您请求的页面。如果该页面是脚本,请添加处理程序。如果应下载文件,请添加 MIME 映射。
- 由于扩展配置问题而无法提供您请求的页面。如果该页面是脚本,请添加处理程序。如果应下载文件,请添加 MIME 映射。
- HTTP 错误 404.3 - Not Found 由于扩展配置问题而无法提供您请求的页面。如果该页面是脚本,请添加处理程序。如果应下载文件,请添加 MIME 映射。
- 《windows应用高级编程-C#编程篇》书中程序的小问题及改进
- 编程之美----扩展问题