STL 常见的注意问题

先说说STL的容器一些常见的注意问题:有网友说,为什么用了STL,程序的效率反而下降了呢?是的,如果用不好,你编程是方便了,可是效率下降了.
1: Vector,这个是基于线性数组的容器
注意事项: 在声明一个vector的时候,尽量指明大小,如果输入数据不超过10^6,那就声明一个10^6大小的vector,否则,vector的默认大小是10.(太小了),但是vector的大小可以自动扩大,不要以为仅仅是在已经分配的空间后面再多申请一块,而是新开辟一块空间,把原来的复制过去.想一下,如果你的vector不断的扩容,不断的复制,效率能不低吗?这就是有的网友问为什么STL的vector没有数组的效率高的原因.

2: Set, Map, 都是基于RB-Tree的容器,所以有 自动排序功能
插入删除,查找效率都很高,查找1000个记录,最多查找10次,查找1000000个记录,最多查找20次
注意事项: 许多人喜欢用,但是如果频繁的插入,删除,不建议使用.因为每插入一次或者删除一次,都要对RB-tree进行一次调整,n次插入,时间复杂度nlgn. 但是如果插入,删除不频繁的情况下是首选.

3: hash_set, hash_map, 都是基于hash_table的, 没有自动排序功能
注意事项: 在声明的时候也要尽量指明大小,否则哈希表的容量达到thresh_hold的时候要自动扩容,所有元素再哈希一次.时间不容忽视. hash_table默认初始大小53, 然后扩容至97,193,389,故意是质数.默认的是朴素哈希函数:比如"apple"的hash code: 5*(5*5*(5*'a'+'p')+'p')+'l')+'e' % 53 = 78066%53 = 50
hash_map使用hash表来排列配对,hash表是使用关键字来计算表位置。当这个表的大小合适,并且计算算法合适的情况下,hash表的算法复杂度为O(1)的,但是这是理想的情况下的,如果hash表的关键字计算与表位置存在冲突,那么最坏的复杂度为O(n)。 
RB-tree树查找,在总查找效率上比不上hash表,但是它很稳定,它的算法复杂度不会出现波动。在一次查找中,你可以断定它最坏的情况下其复杂度不会超过O(log2N)。而hash表就不一样,是O(1),还是O(N),或者在其之间,你并不能把握。

目前hash_set hash_map都已经不再是标准的容器,namespace也从 std move to stdext. Linux下名字空间是 __gnu_cxx. (不推荐使用)

4: list: 双向链表,内存空间不连续
只能用remove,remove_if, erase来删除,inset插入,不可以直接修改pre,next.插入删除效率比较高

5: deque 双端队列
分段连续内存空间,可以遍历(提供iterator)

6: stack,queue
栈和队列,唯一注意的是选择底层容器,默认是deque,可以选择list,vector,根据插入,删除情况选择合适的容器.(不同的底层容器扩容时带来的效率影响), 二者均不提供iterator

7: priority_queue 优先级队列 (STL里面最笨拙的容器)
基于堆,默认是大根堆,可以在构造函数里面提供自己的比较函数实现小根堆.
不提供遍历,不能查找,不能修改里面的元素,只提供top,push,pop
A*搜索的朋友注意了,添加新的子节点到openlist时,要判断是否有重复节点,修改F值,这时才能体会到这个容器的笨拙之处.
用途就不用多说了吧,例如Huffman编码、分支限界、A*启发式都需要用到优先队列存放信息。

优先队列最基本的功能就是出队时不是按照先进先出的规则,而是按照队列中优先级顺序出队。

知识点:1、一般存放实型类型,可比较大小

2、默认情况下底层以Vector实现

3、默认情况下是大顶堆,也就是大者优先级高,后面可以自定义优先级比较规则


8: Algorithm里面提供了make_heap, push_heap, pop_heap, 如果单纯做 搜索,能不用就不用了吧,pop_heap并没有把元素弹出,而是放到了末尾. 适合对一个未排序的数组进行堆排序使用.

其实我想说的是如果我们真的需要一个优先级队列,前提是我们能对这个优先级队列查找,遍历,修改(当然修改优先级之后能自动排序),那就用map或者set来做吧.(取决于你要存储的数据,前者是key,value对,后者只有key).

举例如下:
map<int,int,less<int>> m; //最小的永远处于前面
m[8] = 10;
m[3] = 9;
m[9] = 8;
m[1] = 22;

for(map<int,int,less<int>>::const_iterator itor = m.begin();itor != m.end();itor++)
printf("%d\n",itor->first);

//输出 1 3 8 9

m[5] = 100;
for(map<int,int,less<int>>::const_iterator itor = m.begin();itor != m.end();itor++)
printf("%d\n",itor->first);

//输出 1 3 5 8 9

如果要修改优先级怎么办呢? 反正修改之后也要对RB_tree进行调整,那就先remove掉,再放进一个新的,比如上面的例子我要把m[5]的优先级改为10,可以如下方式:
(注意,不可以直接修改key,map的iterator提供的key是只读的,也就是说itor->first是const的)

int value = m[5];
m.erase(5);
m[10] = value;
for(map<int,int,less<int>>::const_iterator itor = m.begin();itor != m.end();itor++)
printf("%d\n",itor->first);
//输出 1 3 8 9 10

以上是自己对STL做个小小的总结。 
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值