实际上这个问题不光C++会遇到,其余全部语言的标准容器的实现及选择上都是要考虑的。作应用程序你可能以为影响不大,可是写算法或者核心代码就要当心了。今天改进代码,顺便又来温习基础功课了。
还记得Herb Sutter那极有味道的《C++对话系列》么,在其中《产生真正的hash对象》这个故事里就讲了map的选择。顺便回顾一下,也讲一下我在实用中的理解。
选择map容器,是为了更快的从关键字查找到相关的对象。与使用list这样的线性表容器相比,一能够简化查找的算法,二可使任意的关键字作索引,并与目标对象配对,优化查找算法。在C++的STL中map是使用树来作查找算法,这种算法差很少至关与list线性容器的折半查找的效率同样,都是O(log2N),而list就没有map这样易定制和操做了。
相比hash_map,hash_map使用hash表来排列配对,hash表是使用关键字来计算表位置。当这个表的大小合适,而且计算算法合适的状况下,hash表的算法复杂度为O(1)的,可是这是理想的状况下的,若是hash表的关键字计算与表位置存在冲突,那么最坏的复杂度为O(n)。
那么有了这样的认识,咱们应该怎么样选用算法呢?前两天看Python文章的时候,不知道哪一个小子说Python的map比c++的map快,如何如何的。可是他并不知道Python是默认使用的hash_map,并且这些语言特征本质上是使用c/c++写出来的,问题在与算法和手段,而不是在于语言自己的优劣,你熟悉了各类算法,各类语言的细节、设计思想,还能在这偏激的嚷嚷孰好孰坏(片面与偏激的看待事物只能代表愚昧与无知,任何事物都有存在的价值,包括技术)。显然C++的STL默认使用树结构来实现map,是有考究的。
树查找,在总查找效率上比不上hash表,可是它很稳定,它的算法复杂度不会出现波动。在一次查找中,你能够判定它最坏的状况下其复杂度不会超过O(log2N)。而hash表就不同,是O(1),仍是O(N),或者在其之间,你并不能把握。倘若你在开发一个供外部调用的接口,其内部有关键字的查找,可是这个接口调用并不频繁,你是会但愿其调用速度快、但不稳定呢,仍是但愿其调用时间平均、且稳定呢。反之倘若你的程序须要查找一个关键字,这个操做很是频繁,你但愿这些操做在整体上的时间较短,那么hash表查询在总时间上会比其余要短,平均操做时间也会短。这里就须要权衡了。
这里总结一下,选用map仍是hash_map,关键是看关键字查询操做次数,以及你所须要保证的是查询整体时间仍是单个查询的时间。若是是要不少次操做,要求其总体效率,那么使用hash_map,平均处理时间短。若是是少数次的操做,使用hash_map可能形成不肯定的O(N),那么使用平均处理时间相对较慢、单次处理时间恒定的map,考虑总体稳定性应该要高于总体效率,由于前提在操做次数较少。若是在一次流程中,使用hash_map的少数操做产生一个最坏状况O(N),那么hash_map的优点也所以丧尽了。 c++