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

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

 

看到有朋友评论说,美的代码不仅仅是规范上面的事。规范的代码可以让我们减少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;

}

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

你可能感兴趣的:(代码)