合并小文件——一个算法在实际程序开发中应用的例子
2008-08-29 13:24 JimLiu 阅读(3631) 评论(14) 编辑 收藏 举报现在的学生爱说算法对实际项目开发没多大作用,其实这是错误的——现在就园子里看到的一个讨论,提出一个我的方案,作为为一部分朋友举例说明“程序=数据结构+算法”这个不变的道理
讨论源于此http://space.cnblogs.com/question/2616/
讨论中,lexus朋友还是打算将小文件选择性合并,于是有了新讨论http://space.cnblogs.com/question/2630/
简单说一下算法的要求:当两个文件的大小(KB)小于某个设定值时,两个文件就合并,这样一直合并下去。
有朋友提出用排序来解决,我觉得开销太大,排序一次时间O(nlogn),如果每次都排序则复杂度高达O((n^2)logn),不值。
也有朋友提出使用简单插入,那么复杂度是O(n^2)。
“合并文件”,让我想起一道经典的ACM题目——“合并果子”,合并两个文件可以采用贪心,类似Huffman算法,这里合并多个文件和合并两个文件是一样的。
传统Huffman算法的时间复杂度是O(n^2),技巧不好的话会更多,通常的改进办法是使用堆进行优化。
关于堆(Heap),不了解的朋友可以参考一下数据结构的基础书籍
多余背景资料我在这里就不多做介绍了,下面说下我对这个问题的解决方案:
注:下文中每次对堆进行操作后都进行堆维护,不再赘述。
1.设缓冲区内文件总大小是buffer,堆顶文件大小是top;
2.查看top
if (buffer + top <= max_file_size) 则将堆顶弹出到缓冲区
else 将缓冲区内文件合并,新文件压入堆中
3.循环2,直到缓冲区为空,且top >= max_file_size
实际上这里的堆就是个优先队列(Priority Queue),STL中的PQ就是用堆实现的。
分析一下整个算法的性能:
文件总数为n
建立堆需要O(nlogn)
遍历所有文件需要O(n),这个过程中需要进行堆维护,每次O(logn)
所以总的时间复杂度是O(nlogn),和用堆改进的Huffman算法是一样的。
再看看空间需求:
直接算最坏的需求,如果所有文件都足够小,能把所有文件合并在一起,那么缓冲区需要n的长度,所以最坏需要n辅助空间。
以上是我自己能想到最快的算法。
从这个例子看出,在实际应用中,数据结构和算法依然占据核心的地位不会动摇,打好了基础才能做出好的程序。
面对STL,面对java,面对.NET Framework Library,这些琳琅满目的库,我们可以方便地应用各种数据结构和算法,但是如果我们对他们本身的实现没有一定的了解,有怎么能知道在不同的场合下什么选择才合适呢?
所以我还是坚信“程序=数据结构+算法”这个道理是恒定不变的真理。