如何写出优美的代码(三)
(该文思想来自于经典著作《编程珠玑》)
看到有朋友评论说,美的代码不仅仅是规范上面的事。规范的代码可以让我们减少Debug的难度,增加可扩展性。当遇到性能问题的时候,我们就需要改进算法了。
编程珠玑的开篇提到了一个给最多一千万个7位电话号码排序的问题。首先我们看这个问题的常规解决方案:
C版本:
1 2 3 4 5 6 7 8 9 10 11 12 13 | 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++版本:
1 2 3 4 5 6 7 8 9 10 | 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。还可以用位图表示集合,上代码:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 | //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; } |
这个例子主要证明了正确理解问题的重要性。明确理解问题,针对特定条件去思考,是写出优雅算法的第一步。这里用的位图的技术非常简洁,原作者引用的一句话给我很大启发:“设计者确定其设计达到了完美的标准不是不能再增加任何东西,而是不能再减少任何东西。”
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】凌霞软件回馈社区,博客园 & 1Panel & Halo 联合会员上线
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】博客园社区专享云产品让利特惠,阿里云新客6.5折上折
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步