如何寫出優美的代碼(三)


(該文思想來自於經典著作《編程珠璣》)

 

看到有朋友評論說,美的代碼不僅僅是規范上面的事。規范的代碼可以讓我們減少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;
}

這個例子主要證明了正確理解問題的重要性。明確理解問題,針對特定條件去思考,是寫出優雅算法的第一步。這里用的位圖的技術非常簡潔,原作者引用的一句話給我很大啟發:“設計者確定其設計達到了完美的標准不是不能再增加任何東西,而是不能再減少任何東西。”


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM