第4章 编写正确的程序

来源:互联网 发布:linux vps speedtest 编辑:程序博客网 时间:2024/06/05 08:02

习题2.  如果原始的二分搜索对你来说太容易了,那么请试试这个演化后的版本:把t在数组x中第一个出现的位置返回给p(如果存在多个t的话,原始的算法会任意返回其中的一个),要求代码对数组元素进行对数次比较(该任务可以在log2(n)次比较之内完成)。

算法步骤:1) 按正常的二分查找算法查找t在数组中的位置pos;

                    2)将查找区间范围缩小为[left, pos -1]进行二分查找,如果查找到t,继续执行第二步,否则转到第三步;

                    3)在区间[left, pos - 1]中没有再次查找到t,说明位置pos即为第一次出现 t 的位置。

//把ikey在有序数组pArry中第一次出现的位置返回给pint BinarySearch_FirstPos(int * pArry, int iKey, int iLen){int left = 0;int right = iLen - 1;int middle;int p = -1; //如果数组中没有要查找的数,则返回-1while (left <= right){middle = (left + right) / 2;if (pArry[middle] == iKey){p = middle;right = middle - 1; // 找到第一个key值后,缩小区间,继续查找}else if (pArry[middle] > iKey){right = middle -1;}else{left = middle + 1;}}return p;}

习题3. 编写并验证一个递归的二分搜索程序。代码和证明中的哪些部分与迭代版本的二分搜索程序相同?哪些部分发生了改变?

       迭代版本的二分搜索:

int bin_search(elemtype s[], keytype k, int n){int low, mid, high;low = 0;high = n - 1;while (low <= high){mid = (low + high) / 2;if (s[mid].key == k){return mid;       //搜索成功} else if (s[mid].key < k){low = mid + 1;}else{high = mid - 1;}}       //end whilereturn -1;   //搜索不成功}
     递归的二分搜索版本:

int BinarySearch_recursion(int * pArry, int ikey, int l, int r){int low = l;int up = r;int mid = (low + up) / 2;   if (low <= up){if (pArry[mid] == ikey){return mid;   //查找成功,返回关键字的索引值}else if (pArry[mid] > ikey){BinarySearch_recursion(pArry, ikey, low, mid - 1);}else{BinarySearch_recursion(pArry, ikey, mid + 1, up);}}else{return -1;   //没有查找到返回-1}}

习题4. 给你的二分搜索程序添加虚拟的“计时变量”来计算程序的执行的比较次数,并使用程序验证技术来证明其运行时间确实是对数的。

            二分搜索平均搜索长度为log2(n+1)-1,其时间复杂度为O(log2(n))。在while循环体里,用一个变量来累计while循环的执行次数即可。

习题6. “咖啡罐问题”  给定一个盛有一些黑色豆子和一些白色豆子的咖啡罐以及一大堆“额外”的黑色的豆子,重复下面的过程,直至罐子仅剩下一颗豆子为止。

           从罐中随机选取两颗豆子,如果颜色相同,就将它们都扔掉并且放入一个额外的黑色豆子;如果颜色不同,就将白色的豆子放回罐中,而将黑色的豆子扔掉。

            证明该过程会终止。最后留在罐中的豆子的颜色与最初罐中白色豆子和黑色豆子的数量有何函数关系?

            因为每次随机选取都只会扔掉一个豆子,使罐中豆子减少一粒,所以该过程最终会终止。每次随机选取,要么是扔掉2颗或者零颗白色豆子,所以最初罐子中有奇数个白色豆子则最后剩下的是一颗白色豆子。若有偶数个白色豆子,则最后一颗黑色豆子或者没有任何豆子。

习题7. n对实数(ai, bi)构成的数组定义了n条直线yi = ai*x + bi。当x位于[0, 1]内时,对于区间[0, n-2]内的所有i,这些线段按yi < y(i+1)排列,用更形象的华说,这些线段在垂直方向上不交叉。给定一个满足0<= x <=1的点(x, y),他需要确定包围这个点得两条线段。他该如何快速解决该问题?

            因为yi是递增的,可以利用二分查找来找到包含给定点的两条线段,根据查找过程中的比较即可得到给定点的下方、上方线段。

习题11. 使用C或C++编写递归的二分搜索函数并证明其正确性,要求函数的声明如下:

              int BinarySearch(DataType x[], int n)

              单独使用该函数,不要调用其他任何递归函数。