编程珠玑第五章

来源:互联网 发布:淘宝宝贝描述代码下载 编辑:程序博客网 时间:2024/05/20 21:20

  前四章中,我们已经深入挖掘定义了正确的问题,仔细选择算法和数据结构,通过程序验证了正确性,现在开始将成果整合到大的系统中了。  首先,我们要将二分搜索用C语言实现,这个很简单,但是实现之后,就该对这个小函数功能进行测试。这里用一个脚手架写一个例子来测试。对于测试这个方法就有很多,以前只知道print输出,单步调试,这一章作者提出了断言。  对于断言,我就知道有这么个语法,但是从来没有用过。看了作者陈述,才知道断言是一门艺术。断言可以像第四章中用来证明程序的正确性,也可以知道测试代码的开发。所以,现在,将断言插入代码中,以确保程序运行时的行为与理解一致。  assert(n>=0):在n为0或更大什么都不用做,但n为负值会报告某种错误。  对于二分,断言主要加在以下方面:(详细还请看源代码)  1.在if语言中,assert(0<=m && m<n && x[m]==t),对于找到位置,且返回值在范围中加一个断言。  2.在循环结束没有找到位置时,这时候l和u已经交叉了,我们来断言我们找到了一对相邻的元素,一个小于目标值,一个大于目标值:assert(x[u]<t && x[u+1]>t),此时u<l,逻辑就像:如果排序后表中13相邻,那么2肯定不在表中。但是这个断言有缺陷,若n0,那么u就是-1,x[u]就索引数组之外的元素了。要使断言有效,必须将边界条件弱化:assert((u<0 || x[u]<t) && (u+1>=n || x[u+1]>t))  3.我们要证实每次迭代之后,范围都要减小,来证明搜索一定会结束。于是我们插入下面断言代码:oldsize=size;size=u-l+1;assert(size<oldsize)  4.对于二分搜索,前提要有序,所以我们还要断言排序函数。assert(sorted())但是该测试由于循环遍历n个元素,开销大,我们只在搜索前遍历一次。脚手架中写断言,无论从组测试还是系统测试都是很有效的。  但是上面的脚手架我们要自己输入例子,很麻烦,所以我们用机器来自动测试。  1.测试主循环,从0到最大值。  2.测试循环的第一部分:检验所有元素互异的情况。如下:for i=[0,n)         assert(s(10*i) ==i)         assert(s(10*i-5)==-1)     assert(s(10*n-5)==-1)     assert(s(10*n)==-1)测试函数定义:#define s binarysearch  3.测试循环的第二部分:探测所有元素相等的情况如下:for i=[0,n)         x[i]=10     if n==0 assert(s(10)==-1)     else assert(0<=s(10) && s(10)<n)     assert(s(5)==-1)     assert(s(15)==-1)  至此,自动测试脚手架已经全部完成。先面就是计时了。  这章虽然是小问题,但是大学问:  1.脚手架。最好的脚手架通常是最容易构建的脚手架。最好就是命令行技术。  2.编码:先伪代码构建程序框架,在翻译为实际语言。  3.测试。在脚手架中进行测试比在大系统中更容易。  4.调试:在脚手架中调试比在大系统中容易很多。  5.计时:对于二分搜索,如果是顺序的搜索,由于元素顺序存放,要考虑缓存的影响,所以最好的方法是将数组元素用random(),先随机化,在测试计时,这样更准确。  第一部分基础篇,已经看完了,作者一条主线:分析问题,选择算法和数据结构,证明程序正确性,编码测试调试。写代码的流程就形成了,作者这里介绍的都比较简单。要想详细掌握,我还要看更多的书籍。总之,继续努力。为找工作加油。。源代码:  
/* Copyright (C) 1999 Lucent Technologies *//* From 'Programming Pearls' by Jon Bentley *//* search.c -- test and time binary and sequential search   Select one of three modes by editing main() below.   1.) Probe one function   2.) Test one function extensively   3.) Time all functionsInput lines:  algnum n numtestsOutput lines: algnum n numtests clicks nanosecs_per_elemSee timedriver for algnum codes */#include <stdio.h>#include <stdlib.h>#include <time.h>#define MAXN 1000000typedef int DataType;DataType x[MAXN];int n;/* Scaffolding */int i = -999999;#define assert(v) { if ((v) == 0) printf("  binarysearch bug %d %d\n", i, n); }/* Alg 1: From Programming Pearls, Column 4: raw transliteration */int binarysearch1(DataType t){int l, u, m;l = 0;u = n-1;for (;;) {if (l > u)return -1;m = (l + u) / 2;if (x[m] < t)l = m+1;else if (x[m] == t)return m;else /* x[m] > t */u = m-1;}}/* Alg 2: Make binarysearch1 more c-ish */int binarysearch2(DataType t){int l, u, m;l = 0;u = n-1;while (l <= u) {m = (l + u) / 2;if (x[m] < t)l = m+1;else if (x[m] == t)return m;else /* x[m] > t */u = m-1;}return -1;}/* Alg 3: From PP, Col 8 */int binarysearch3(DataType t){int l, u, m;l = -1;u = n;while (l+1 != u) {m = (l + u) / 2;if (x[m] < t)l = m;elseu = m;}if (u >= n || x[u] != t)return -1;return u;}/* Alg 4: From PP, Col 9 */int binarysearch4(DataType t){int l, p;if (n != 1000)return binarysearch3(t);l = -1;if (x[511]   < t) l = 1000 - 512;if (x[l+256] < t) l += 256;if (x[l+128] < t) l += 128;if (x[l+64 ] < t) l += 64;if (x[l+32 ] < t) l += 32;if (x[l+16 ] < t) l += 16;if (x[l+8  ] < t) l += 8;if (x[l+4  ] < t) l += 4;if (x[l+2  ] < t) l += 2;if (x[l+1  ] < t) l += 1;p = l+1;if (p >= n || x[p] != t)return -1;return p;}/* Alg 9: Buggy, from Programming Pearls, Column 5 */int sorted(){   int i;    for (i = 0; i < n-1; i++)        if (x[i] > x[i+1])            return 0;    return 1;}int binarysearch9(DataType t){int l, u, m;/* int oldsize, size = n+1; */l = 0;u = n-1;while (l <= u) {/* oldsize = size;size = u - l +1;assert(size < oldsize); */m = (l + u) / 2;/* printf("  %d %d %d\n", l, m, u); */if (x[m] < t)l = m;else if (x[m] > t)u = m;else {/* assert(x[m] == t); */return m;}}/* assert(x[l] > t && x[u] < t); */return -1;}/* Alg 21: Simple sequential search */int seqsearch1(DataType t){int i;for (i = 0; i < n; i++)if (x[i] == t)return i;return -1;}/* Alg 22: Faster sequential search: Sentinel */int seqsearch2(DataType t){int i;DataType hold = x[n];x[n] = t;for (i = 0; ; i++)if (x[i] == t)break;x[n] = hold;if (i == n)return -1;elsereturn i;}/* Alg 23: Faster sequential search: loop unrolling */int seqsearch3(DataType t){int i;DataType hold = x[n];x[n] = t;for (i = 0; ; i+=8) {if (x[i] == t)   {          break; }if (x[i+1] == t) { i += 1; break; }if (x[i+2] == t) { i += 2; break; }if (x[i+3] == t) { i += 3; break; }if (x[i+4] == t) { i += 4; break; }if (x[i+5] == t) { i += 5; break; }if (x[i+6] == t) { i += 6; break; }if (x[i+7] == t) { i += 7; break; }}x[n] = hold;if (i == n)return -1;elsereturn i;}/* Scaffolding to probe one algorithm */void probe1(){int i;DataType t;while (scanf("%d %d", &n, &t) != EOF) {for (i = 0; i < n; i++)x[i] = 10*i;printf(" %d\n", binarysearch9(t));}}/* Torture test one algorithm */#define s seqsearch3void test(int maxn){int i;for (n = 0; n <= maxn; n++) {printf("n=%d\n", n);/* distinct elements (plus one at top) */for (i = 0; i <= n; i++)x[i] = 10*i;for (i = 0; i < n; i++) {assert(s(10*i)     ==  i);assert(s(10*i - 5) == -1);}assert(s(10*n - 5) == -1);assert(s(10*n)     == -1);/* equal elements */for (i = 0; i < n; i++)x[i] = 10;if (n == 0) {assert(s(10) == -1);} else {assert(0 <= s(10) && s(10) < n);}assert(s(5) == -1);assert(s(15) == -1);}}/* Timing */int p[MAXN];void scramble(int n){int i, j;DataType t;for (i = n-1; i > 0; i--) {j = (RAND_MAX*rand() + rand()) % (i + 1);t = p[i]; p[i] = p[j]; p[j] = t;}}void timedriver(){int i, algnum, numtests, test, start, clicks;while (scanf("%d %d %d", &algnum, &n, &numtests) != EOF) {for (i = 0; i < n; i++)x[i] = i;for (i = 0; i < n; i++)p[i] = i;scramble(n);start = clock();for (test = 0; test < numtests; test++) {for (i = 0; i < n; i++){switch (algnum) {case 1:  assert(binarysearch1(p[i]) == p[i]); break;case 2:  assert(binarysearch2(p[i]) == p[i]); break;case 3:  assert(binarysearch3(p[i]) == p[i]); break;case 4:  assert(binarysearch4(p[i]) == p[i]); break;case 9:  assert(binarysearch9(p[i]) == p[i]); break;case 21: assert(seqsearch1(p[i]) == p[i]); break;case 22: assert(seqsearch2(p[i]) == p[i]); break;case 23: assert(seqsearch3(p[i]) == p[i]); break;}}}clicks = clock() - start;printf("%d\t%d\t%d\t%d\t%g\n",algnum, n, numtests, clicks,1e9*clicks/((float) CLOCKS_PER_SEC*n*numtests));}}/* Main */int main(){/* probe1(); *//* test(25); */timedriver();return 0;}


原创粉丝点击