(該文思想來自於經典著作《編程珠璣》)
看到有朋友評論說,美的代碼不僅僅是規范上面的事。規范的代碼可以讓我們減少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;
}
這個例子主要證明了正確理解問題的重要性。明確理解問題,針對特定條件去思考,是寫出優雅算法的第一步。這里用的位圖的技術非常簡潔,原作者引用的一句話給我很大啟發:“設計者確定其設計達到了完美的標准不是不能再增加任何東西,而是不能再減少任何東西。”
