编程珠玑第五章


  前四章中,我们已经深入挖掘定义了正确的问题,仔细选择算法和数据结构,通过程序
验证了正确性,现在开始将成果整合到大的系统中了。  首先,我们要将二分搜索用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 functions
		Input lines:  algnum n numtests
		Output lines: algnum n numtests clicks nanosecs_per_elem
		See timedriver for algnum codes
 */

#include <stdio.h>
#include <stdlib.h>
#include <time.h>

#define MAXN 1000000

typedef 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;
		else
			u = 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;
	else
		return 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;
	else
		return 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 seqsearch3
void 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;
}


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值