最近思考到这样一个题目:在STL的set和vector容器里存储了1亿个QQ号,编写函数删除奇数QQ号。

1. STL容器简介

首先了解一下 set 和 vector 以及其他类似的 STL 容器:

实现描述:

容器 描述
vector 向量,一个有着N个或更多连续存储的元素的数组
list 列表,一个由节点组成的双向链表,每个节点中包含一个元素。
deque 双队列,一个有着N个或更多连续存储的指向不同元素的指针组成的数组
set 集合,一个由节点组成的红/黑树,每个节点包含一个元素,节点之间以某种作用与元素对的谓词排序,没有两个不同的元素能够拥有相同的次序。
multiset 多重集合,允许存在两个次序相同的元素的集合。
map 映射,一个由{键 , 值}对组成的集合,以某种作用于键对上的谓词排序,使用pair<键, 值>
multimap 多重映射,允许键有重复的,即一个键可以有多个对应的值。

时间和空间复杂度:

容器 vector deque list set/map
插入/删除 N N 常量 log(N)
从前面添加 N 常量 常量 log(N)
find(val) N N N log(N)
X(N) 常量 常量 N N
指针 0 1 2 3

其他容器适配器

这些容器几乎是由其他容器实现的容器,只是对存取元素方面进行了部分的限制。

容器 描述
stack 栈,后进先出的队列。
queue 队列,先进先出。
priority_queue 优先队列,一个队列,其中元素的次序是由作用于所存储值对上的某种谓词决定的,拥有高优先级的元素会先被出队。

2. 算法解析

第一个思路就是使用erase函数一个个去删,(不知道有没有什么更好的方法请在评论里指点一下,谢谢)这里,set和vector的存储方式是不一样的。但是它们都提供了一个删除元素的接口erase

// set
iterator erase(iterator it);
iterator erase(iterator first, iterator last);
size_type erase( const Key& key);
  • 第一个成员函数:删除 set 中由迭代器 it 指向的元素;
  • 第二个成员函数:删除 set 中区间为 [first , last )中的所有元素;
  • 第一和第二个成员函数都返回一个迭代器,指向紧接着被删除元素的下一个元素,如果没有这样的元素,则迭代器指向 end()。
  • 第三个成员函数:删除 set 中区间为 [lower_bound(key) , upper_bound(key) )中的具有给定排序键key的所有元素,返回删除元素的个数
// vector , list ,  deque
iterator erase(iterator it);
iterator erase(iterator first, iterator last);
  • 第一个成员函数:删除 vector/list/deque 中由迭代器 it 指向的元素;
  • 第二个成员函数:删除 vector/list/deque 中区间为 [first , last )中的所有元素;
  • 第一和第二个成员函数都返回一个迭代器,指向紧接着被删除元素的下一个元素,如果没有这样的元素,则迭代器指向 end()。
  • vector时,删除 N 个元素将导致调用 N 次析构函数以及从删除点至序列末端的每个元素都被赋值一次。由于不需要进行存储空间的重新分配,所以只有从指向第一个被删除元素到序列末端这个区域的迭代器以及引用才会失效。
  • list时,删除N个元素将调用N次析构函数。由于没有进行任何重新分配发生,只有指向被删除对象的迭代器和引用才会变为无效。
  • deque时,删除N个元素将导致N次调用析构函数以及从删除点至序列较近的末端的每个元素都被赋值一次。在序列的两端删除一个元素仅使得原先指向被删除元素的迭代器和引用变得无效,否则,删除一个元素将导致所有的迭代器和引用都变的无效。

了解了这个以后,能发现,算法题中的说存储在set和vector中,其实其内部存储是不一样的,删除的实现原理也是不同的。但都可以用同一个接口erase()去实现!及时这时候添加说还存储在list和deque中,也是可以使用的。我们可以写两个函数去实现这个功能,但由于在两个容器中,而调用的接口又都是一样的,所以自然而然想到可以使用模板函数!这是其一。

第二,题目中说是QQ号,众所周知,QQ目前已经多达11位了,以后还会更长,所以将QQ号设为整型肯定是不合适的了,所以这里需要使用long long 。同时,遍历容器时,肯定是要使用迭代器来进行遍历的,这样能保证速度。

第三,题目中说一亿个QQ号,目前还不知道这里藏着什么坑,感觉是有的,我写的代码反正是死掉了,一亿条,添加和删除的循环都搞死了。还请大神帮忙分析分析!

所以基于以上分析,写出以下代码:

#include <utility>
#include <set>
#include <vector> typedef long long dlong; template <typename T>
void qq_delete_stl_template(T &t){
typename T::iterator it=t.begin(); //typename用来说明T::iterator是一个类型,
//否则iterator会被认为是T中的一个成员变量
while(it!=t.end()){ //每次删除后都会导致t.end()指向的都是不同的位置
if((*it)&1){ //奇数
it=t.erase(it); //删除迭代起指向的内容,并返回删除后的下一项内容
}else{
++it;
}
}
} //调用时应该是:
set<dlong> s; //假设s里存有1亿个QQ号
qq_delete_stl_template(s);
vector<dlong> v; //假设v里存有1亿个QQ号
qq_delete_stl_template(v);

分析的比较浅显,希望大神指教!

完整测试源码

附录

STL容器及算法题:删除奇数的QQ号的更多相关文章

  1. 【坐在马桶上看算法】算法4:队列——解密QQ号

            新学期开始了,小哈是小哼的新同桌(小哈是个小美女哦~),小哼向小哈询问QQ号,小哈当然不会直接告诉小哼啦,原因嘛你懂的.所以小哈给了小哼一串加密过的数字,同时小哈也告诉了小哼解密规则. ...

  2. 算法5:队列——解密 QQ 号

    新学期开始了,小哈是小哼的新同桌(小哈是个小美女哦~),小哼向小哈询问 QQ 号,小哈当然不会直接告诉小哼啦,原因嘛你懂的.所以小哈给了小哼一串加密过的数字,同时小哈也告诉了小哼解密规则.规则是这样的 ...

  3. 刷题常用的STL容器总结

    本文归纳总结刷题常用到STL容器以及一些标准算法,主要包括: string.vector.map.pair.unordered_map.set.queue.priority_queue.stack,以 ...

  4. 每天一道算法题(4)——O(1)时间内删除链表节点

    1.思路 假设链表......---A--B--C--D....,要删除B.一般的做法是遍历链表并记录前驱节点,修改指针,时间为O(n).删除节点的实质为更改后驱指针指向.这里,复制C的内容至B(此时 ...

  5. C++进阶 STL(1) 第一天 [容器,算法,迭代器] string容器 vector容器 deque容器

    课程大纲 02实现基本原理 容器,算法,迭代器 教室:容器 人:元素 教室对于楼:容器 序列式容器: 容器元素在容器中的位置是由进入容器的时间和地点来决定 序列式容器 关联式容器: 教室中 按年龄排座 ...

  6. 【pat】C++之刷题常用STL容器整理

    1.vector 动态数组,方便的动态扩容,方便的变量初始化(int类型默认初始化为0,bool默认初始化为false),可以用来实现邻接表(结点数太多的图). 头文件 #include<vec ...

  7. 《STL源码剖析》——第五、六:关联容器与算法

    第五章.关联容器  5.0.关联容器 标准的STL关联式容器分为set(集合)和map(映射表)两大类,以及这两大类的衍生体multiset(多键集合)和multimap(多键映射表).这些容器的底层 ...

  8. STL容器删除元素的陷阱

    今天看Scott Meyers大师的stl的用法,看到了我前段时间犯的一个错误,发现我写的代码和他提到错误代码几乎一模一样,有关stl容器删除元素的问题,错误的代码如下:std::vector< ...

  9. STL容器的遍历删除

    STL容器的遍历删除 今天在对截包程序的HashTable中加入计时机制时,碰到这个问题.对hash_map中的每个项加入时间后,用查询函数遍历hash_map,以删除掉那些在表存留时间比某个阈值长的 ...

随机推荐

  1. poj1318 Word Amalgamation 字符串排序(qsort)

    Word Amalgamation Time Limit: 1000MS   Memory Limit: 10000K Total Submissions: 9794   Accepted: 4701 ...

  2. Ubuntu电源键软关机设置

    对于不连接显示器的Ubuntu设备,通过直接拔电源或者长按电源键是普遍的关机方法,但这种方法长期势必会对设备造成损坏. 下面设置电源键软关机(短摁电源按钮关机)的方法可以解决此问题.(默认摁电源键会弹 ...

  3. 第三次 Scrum Meeting

    第三次 Scrum Meeting 写在前面 会议时间 会议时长 会议地点 2019/4/7 20:00 60min 新主楼G411 附Github仓库:WEDO 例会照片 工作情况总结(4.5-4. ...

  4. Python 垃圾回收机制(转)

    概述 python采用的是引用计数机制为主,标记-清除和分代收集两种机制为辅的策略. 引用计数 Python语言默认采用的垃圾收集机制是『引用计数法 Reference Counting』,该算法最早 ...

  5. js实现CkeckBox全选与反选

    全选与反选 function SelectAll(){ var check = document.getElementsByTagName("input"); // 获取所有inp ...

  6. RequireJS 2.0 正式发布

    就在前天晚上RequireJS发布了一个大版本,直接从version1.0.8升级到了2.0.随后的几小时James Burke又迅速的将版本调整为2.0.1,当然其配套的打包压缩工具r.js也同时升 ...

  7. maven module

    通过将一个maven项目拆分成多个module,会引入一定的项目复杂度,但随着后期项目代码的逐渐增多,最直观的感受是,每次build代码,不必build整个项目,可节省很多时间. 如果各个module ...

  8. PLC总结

    PLC编程总结 PLC控制部分总体有三大部分组成,PLC硬件,组态以及梯形图程序.PLC硬件应与组态一一对应,不容有任何偏差:而梯形图与操作的组态的IO口也应该一一对应.因此,整个系统达到了由梯形图程 ...

  9. 虚拟环境--pipenv

    1.安装pipenv,这个工具属于python3 升级pip : pip3 install pipenv 2.在项目中创建虚拟环境 3.激活虚拟环境,进入虚拟环境 进入虚拟环境之前: pipenv s ...

  10. 系统更新后vs2012无法打开方案资源管理器

    系统更新后vs2012无法打开方案资源管理器 vs调试报错: 未找到与约束 ContractName Microsoft.VisualStudio.Language.Intellisense.IGly ...