如何写出优美的代码(三)

(该文思想来自于经典著作《编程珠玑》)

 

看到有朋友评论说,美的代码不仅仅是规范上面的事。规范的代码可以让我们减少Debug的难度,增加可扩展性。当遇到性能问题的时候,我们就需要改进算法了。

编程珠玑的开篇提到了一个给最多一千万个7位电话号码排序的问题。首先我们看这个问题的常规解决方案:

C版本:

int intcomp(int *x,int *y){
	return *x - *y
}
int a[10000000]
int main(void){
	int i,n = 0;
	while (scanf("%d", &a[n] != EOF)
		n++;
	qsort(a, n, sizeof(int), intcomp);
	for (i = 0; i < n; i++)
		printf("%d\n", a[i]);
	return 0;
}

C++版本:

int main(void){
	set<int> S;
	int i;
	set<int>::iterator j;
	while (cin >> i)
		S.insert(i);
	for (j = S.begin(); j != S.end(); ++j)
		cout << *j << "\n";
	return 0;
}

但是,条件有限制:可用内存只有1MB。我们看到这么小的内存,直接想法是在磁盘上归并排序把。但是,进一步想,如果用32位整数存储电话号码,可以存250000个号码。这样,可以把号码按大小顺序分成40段,依次放到内存里快排。

再进一步分析该问题的特殊性:1)电话号码没有重复,2)数字小于1000万,3)需要排序的仅仅是电话号码,没有其他关联数据。由此想到,可以用一个1000万个位的字符串表示这个文件,当且仅当整数i在文件中存在时,第i位为1。还可以用位图表示集合,上代码:

//32位整数
#define BITSPERWORD 32 
#define SHIFT 5
#define MASK 0x1F
#define N 10000000
int a[1 + N/BITSPERWORD];

void set(int i) { a[i>>SHIFT] |= (1<<(i & MASK)); }
void clr(int i) { a[i>>SHIFT] &= ~(1<<(i & MASK)); }
int test(int i) { return a[i>>SHIFT] & (i>>(i & MASK)); }

int main(void) {
	int i;
	for (i = 0; i< N; i++)
		clr(i);
	while (scanf("%d", &i) != EOF)
		set(i);
	for (i = 0; i < N; i++)
		if (test(i))
			printf("%d\n", i);
	return 0;
}

这个例子主要证明了正确理解问题的重要性。明确理解问题,针对特定条件去思考,是写出优雅算法的第一步。这里用的位图的技术非常简洁,原作者引用的一句话给我很大启发:“设计者确定其设计达到了完美的标准不是不能再增加任何东西,而是不能再减少任何东西。”

posted on 2012-03-14 01:14  大俗人  阅读(2730)  评论(4编辑  收藏  举报