最近思考到这样一个题目:在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. PIE SDK矢量数据项查看

    1. 功能简介 矢量数据由大量要素信息构成,矢量数据项查看可以看到数据的属性表,下面就基于PIE SDK,介绍矢量数据项查看功能的实现. 2. 功能实现说明 2.1. 实现思路及原理说明 第一步 加载 ...

  2. Yii2 执行Save()方法失败,却没有错误信息

    一般用$model->errors 就能查看到更新失败的原因,但是这次却什么错误信息都没有,最后发现是因为在模型类中定义了一个方法 public function beforeSave($ins ...

  3. 配置node.js中的express框架

    玩node.js,不玩后台那就是杀鸡牛刀,今天没事整理一下以前开发node.js后台的心得 1.首先安装node.js以及cnpm,在这儿我就不说了,看我node.js中的另一篇文章node.js的安 ...

  4. Echart 动态生成series数据

    要做成页面只传入数据,js生成图表,如下图 下面是js代码 var LineChart = function (ID, title, axisData,seriesData) { var myChar ...

  5. VUE中toast的使用与开发

    在这篇文章中介绍了toast是什么,这篇文章主要介绍toast的开发与使用. 开发 Vuejs很流行,并且官方也给出了路由插件vue-router.数据管理插件vuex,但是我们仅仅停留在了使用的阶段 ...

  6. 通过JavaScript动态生成html控件

    示例代码 <html> <head> <meta http-equiv="Content-Type" content="text/html& ...

  7. springboot整合mongo多数据源

    该实例已测试 POM.XML <!-- Spring Boot mongodb 依赖--> <dependency> <groupId>org.springfram ...

  8. axios请求报Uncaught (in promise) Error: Request failed with status code 404

    使用axios处理请求时,出现的问题解决 当url是远程接口链接时,会报404的错误: Uncaught (in promise) Error: Request failed with status ...

  9. JavaScript对象 继承

    JavaScript继承主要依靠原型链实现. 原型链 利用原型让一个引用类型继承另一个引用类型水位属性和方法. 每一个构造函数都有一个原型对象,原型对象都包含一个指向构造函数的指针,而实例都包含一个指 ...

  10. 数据库mysql中编码自动生成

    call PrGetRuleCodeNoDate('Table_Name'); call PrGetRuleCode('Table_Name');