C++的那些事:容器和泛型算法
一、顺序容器
1,标准库定义了3种类型的顺序容器:vector、list和deque。它们的差别主要在于访问元素的方式,以及添加或删除元素相关操作运算代价。标准库还提供了三种容器适配器:stack、queue和priority_queue。
2,将一个容器复制给另一个容器时,类型必须匹配,包括容器类型和元素类型。
- vector<int> ivec;
- vector<double> dvec(ivec); //error
- list<int> ilist(ivec); // error
3,可以用一对指针或一对迭代器,把它们之间的值复制给容器,可以允许类型不一致。
- vector<string> svec;
- list<string> slist(svec.begin(),svec.end());
- vector<string>::iterator mid = svec.begin() + svec.size() / ;
- deque<string> front(svec.begin(),mid); // 不包括 *mid
- // 用指针初始化
- char* word[] = {"monday","tuesday","wesday"};
- size_t words_size = sizeof(word) / sizeof(char*);
- list<string> words2(word, word + words_size);
4,注意除了引用外,所有内置或复合类型都可以做容器的元素类型。引用不支持一般意义的赋值操作。除输入输出标准库类型(以及auto_ptr)外,所有其他标准库类型都是有效的容器元素类型。
5,list容器的迭代器不支持算术运算,也不支持关系运算。因为list里的元素,没有序号或位置这个概念。
6,所有相同类型的容器都支持关系操作符来实现两个容器的比较:
1)如果两个容器具有相同的长度而且所有元素都相等,那么两个两个容器相等;否则,就不相等。
2)如果两个容器的长度不相同,但较短的容器中所有元素都等于较长容器中对应的元素,则称较短的容器小于另一容器。
3)如果两个容器都不是对方的初始子序列,则它们的比较结果取决于所比较的第一个不相等的元素。
如果容器内的元素不支持比较大小,则容器就不能比较大小。
7,获得容器元素的引用,有两种方法:1)front与back成员函数;2)迭代器解引用。
- list<int> ilist;
- if (!ilist.empty())
- {
- list<int>::reference val = ilist.front();
- list<int>::reference val1 = *ilist.begin();
- list<int>::reference last = ilist.back();
- list<int>::reference last1 = *--ilist.end();
- }
注意取引用时,一定要保证ilist非空。
8,在使用erase删除容器内两个迭代器之间的元素时,erase(elem1,elem2),这里删除的元素不包括elem2。
9,容器的赋值,顺序容器有几下几种赋值操作:
1)c1=c2:删除c1的所有元素,然后将c2的元素复制给c1,c1和c2的类型(容器类型与元素类型)必须相同。
2)c1.swap(c2):顾名思义,交换c1与c2的值,实际上这个操作,只是交换了彼此的地址。交换后c1批向了原来c2的指针内容。
3)c.assign(b,e):重新设置c的元素,将迭代器b与e之间的所有元素复制到c中,当然b与e不能是c的的迭代器。
4)c.assign(n,t):将容器c重新设置为存储n个值为t的元素。
注意assign操作允许发生类型转换。可以将char*元素assign给存储string的容器。swap是速度最快的,没有删除元素的成本。
10,一般意义下vector的元素是按顺序存储的,这就造成了,如果插入元素,则库将进行重新内存分配,并涉及到的旧vector的销毁。而实际中vector容器预留了这些额外的存储区用于存放新添加的元素。因此在实际上,比起list与deqeue容器,vector的增长效率通常会更高。
11,vector容器实际空间可能会比元素所占的空间更大,capacity成员函数用于返回容器实际的容量大小,一般比size要大。如果一直往vector内插入元素,则直到size==capacity之间,vector都不用重新进行内存分配。但如果再往里插入元素时,将又会重新分配,capacity又会比size大。
二、 关联容器
1,pair类型:
- pair<string, string> name("ronny", "young"); // 定义并初始化
- name = make_pair("ronny", "young");
- string fullName = name.first + name.second;
2,关联容器
1)关联容器map实际上是装有n个pair类型的集合。map定义了三个类型别名,key_type、mapped_type、value_type分别表示键的类型、键所关联的值的类型和map里pair类型。
2)当使用下标访问map的值时,如果下标不存在,则导致在map中新添一个新的元素,它的键即为该下标值。
3)map的迭代器指向的是pair类型,所以当对迭代器解引用时,得到的是一个pair类型。这与下标得到的类型不同。
4)统计单词出现次数的例子:
- map<string, int> word_cnt;
- string word;
- while (cin >> word)
- {
- ++word_cnt[word];
- }
5)利用insert返回的类型来重写上面的程序,insert返回了一个pair类型,它的first成员为一个迭代器,而second成员为一个bool变量,表明该元素是否被插入。
- map<string, int> word_cnt;
- string word;
- while (cin >> word)
- {
- pair<map<string, int>::iterator, bool>
- ret = word_cnt.insert(make_pair(word, ));
- if (!ret.second)
- ++(ret.first)->second;
- }
6)set容器是一个集合,它存储了键,且惟一不能修改。set的操作与map基本一致,只是没有mapped_type,而且vale_type就是key_type。在使用insert时,返回的也是pair类型的值。set不提供下标操作,只能使用find来查找元素是否存在,并且返回一个迭代器,如果不存在,则返回指向最后一个元素下一个的迭代器(end)。如果简单的判断某个键是否存在,则可以直接使用cout函数,它返回1或0。
7)multimap与multiset容器允许一个键值对应多个实例,实际上一个键值的多个实例是按顺序存储在一起的。它们的find的操作返回键值第一个实例的迭代器,cout返回键值有多少个实例。另外lower_bound与upper_bound分别用于返回所查找键值的第一个实例我迭代器与最后一个实例迭代器的下一位。
- multimap<string, string> books;
- typedef multimap<string, string>::iterator authors_it;
- string search_item = "matin";
- authors_it beg = books.lower_bound(search_item);
- authors_it end = books.upper_bound(search_item);
- while (beg != end)
- {
- cout << (beg++)->second << endl;
- }
更加方便的是equal_range函数,它返回了一个迭代器的pair对象,其实正好放着lower_bound和upper_bound
三、 泛型算法
1,泛型算法大部分在algorithm头文件中,而还有一些算术算法,它们在头文件numeric中。
2,int sum=accumulate(vec.begin,vec.end(),42)。accumulate返回一对迭代器之间元素和。注意第三个参数是很重要的,一方面它指定了sum的类型,使该类型可以进行加法运算;另一方面限制了容器的类型必须与第三个参数类型保持一致或可以转换。得到的sum为第三个参数的类型。
3,find_first_of用于查找第二段范围里的对象在第一段范围里出现的第一个位置。
- while (it=find_first_of(it,roster1.end,roster2.begin(),roster2.end())
- !=roster1.end())
上面代码用来循环查找,roster2中的元素在roster1中出现的位置。find_first_of的两个范围内的对象,并不要求容器类型一致,只需要容器内的元素可以进行比较即可。
4,写入算法:
fill(vec.begin(),vec.end(),0):将一对迭代器范围内的值设置为第三个参数的值。
fill_n(vec.begin(),10,0):如果vec内元素小于10个时,这段代码将会出现问题。用插入迭代器可以解决fill_n(back_inserter(vec),10,0);
copy(ilst.begin(),ilist.end(),back_inserter(ivec))会将ilist内的元素复制到ivec中。
replace(ilst.begin(),ilst.end(),0,42):将ilst中所有值为0的元素全部值设为42.
replace_copy(ilst.begin(),ilst.end(),back_inserter(ivec),0,42):ilst没有发生变化,ivec将储存ilst的一份副本,其实值为0的都变为了42.
5,去重复、排序算法
- char * arStr[] = { "the", "quick", "red", "fox", "jumps", "over", "the", "slow", "red", "turtle" };
- vector<string> sVec(arStr, arStr + );
- sort(sVec.begin(), sVec.end());
- vector<string>::iterator end_uniuqe = unique(sVec.begin(), sVec.end());
- sVec.erase(end_uniuqe,sVec.end());
- stable_sort(sVec.begin(), sVec.end(), isShorter);
- vector<string>::size_type len = count_if(sVec.begin(), sVec.end(), LongerThan6);
- bool isShorter(const string& s1, const string& s2)
- {
- return s1.size() < s2.size();
- }
- bool LongerThan6(const string& s)
- {
- return s.size() >= ;
- }
上面程序中,unique是一个去重复的函数,返回已经没有重复的序列最后一位下一个元素位置。
stable_sort可以保留重复元素开始的相对位置
7,插入迭代器:
front_inserter:调用push_front插入
back_inserter:调用push_back插入
inserter:调用insert插入
- list<int>::iterator it = find(ilst.begin(),ilst.end(),);
- // 先将ivec的一份拷贝中值为100的元素换为0,然后将其插入到ilst的迭代器it的前面
- replace_copy(ivec.begin(),ivec.end(),inserter(ilst,it),,);
上面三种操作一般都与copy或replace_copy函数一起用,作为其一个实参。
- list<int> lst1, lst2, lst3;
- for (list<int>::size_type i = ; i != ; i++)
- {
- lst1.push_back(i);
- }
- copy(lst1.begin(), lst1.end(), inserter(lst2, lst2.begin()));
- copy(lst1.begin(), lst1.end(), front_inserter(lst3));
C++的那些事:容器和泛型算法的更多相关文章
- STL容器及泛型算法
一.顺序容器 1.容器的选择 (1) 随机访问,选vector ,deque (2) 在中间插入或者删除元素,选list (3) 在头尾插入或删除元素 , 选deque 2.list的成员函数 (1) ...
- 【c++ Prime 学习笔记】第10章 泛型算法
标准库未给容器添加大量功能,而是提供一组独立于容器的泛型算法 算法:它们实现了一些经典算法的公共接口 泛型:它们可用于不同类型的容器和不同类型的元素 利用这些算法可实现容器基本操作很难做到的事,例如查 ...
- CH10 泛型算法
概述 大多数算法都定义在algorithm头文件中. Note:算法永远不会执行容器操作 泛型算法本身不会执行容器的操作,而是通过迭代器来访问.修改等操作 10.1 题目要求读取数据存入vector, ...
- C++ 泛型算法
<C++ Primer 4th>读书笔记 标准容器(the standard container)定义了很少的操作.标准库并没有为每种容器类型都定义实现这些操作的成员函数,而是定义了一组泛 ...
- C++ Primer : 第十章 : 泛型算法 之 只读、写和排序算法
大多数算法都定义在<algorithm>头文件里,而标准库还在头文件<numeric>里定义了一组数值泛型算法,比如accumulate. ● find算法,算法接受一对迭代 ...
- Chapter10:泛型算法
泛型算法的基础是迭代器. 迭代器令算法不依赖于容器,但是算法依赖于元素类型的操作.也即:算法永远不会执行容器的操作. 那么,如果想向容器中添加元素或者执行其他的一些操作呢?标准库提供了插入迭代器来完成 ...
- C++ Primer 学习笔记_46_STL实践与分析(20)--容器特有的算法
STL实践与分析 --容器特有的算法 与其它顺序容器所支持的操作相比,标准库为list容器定义了更精细的操作集合,使它不必仅仅依赖于泛型操作.当中非常大的一个原因就是list容器不是依照内存中的顺序进 ...
- C++ Primer 5th 第10章 泛型算法
练习10.1:头文件algorithm中定义了一个名为count的函数,它类似find,接受一对迭代器和一个值作为参数.count返回给定值在序列中出现的次数.编写程序,读取int序列存入vector ...
- C++标准库之泛型算法
本文中算法都是指泛型算法. 基本要点: 1)算法使用迭代器进行操作. 2)不依赖容器,但容器希望使用算法,就必须提供接口. 3)通用算法永远不会执行容器操作.操作仅指:更改容器大小的操作.但,容器内部 ...
随机推荐
- WPF TabControl 模拟动画
using System; using System.Threading; using System.Windows; using System.Windows.Controls; using Wan ...
- Spark-1.0.0 standalone分布式安装教程
Spark目前支持多种分布式部署方式:一.Standalone Deploy Mode:二Amazon EC2.:三.Apache Mesos:四.Hadoop YARN.第一种方式是单独部署,不需要 ...
- iOS: imageIO完成渐进加载图片
imageIO完成渐进加载图片 不得不说,人都是有惰性的,一个月又快结束了,这个月虽说有点儿忙,但是绝对不差写几篇博客的时间,有时间去n次桌球厅,有时间玩n把英雄联盟,所谓小撸怡情大撸伤身,这个月游戏 ...
- Hello Kitty微信主题很可爱?小心财产安全!
个性化是产品服务的一个趋势.微信很火,可为什么微信主题只有一个呢?你让那些小女生情何以堪?这时HelloKitty微信主题.大嘴猴.哆啦A梦等一大批主题在网上出现了,有些打着免费的旗号却做着盗号的勾当 ...
- (11)UI布局和分辨率适配
一.Cocos编辑器 自动布局系统主要涉及固定与拉伸属性: 如图,总共可以修改控件的上下左右四个图钉和中间的两个拉伸条六个属性. 效果 1.当打开其中的任意一个图钉时,当前节点与父节点的对应边 ...
- Java中的向上转型和向下转型
首先要明白一点向上转型和向下转型他们都是建立在继承的基础上. 一.向上转型 子类到父类的转换通常称作向上转型,通俗的说就是定义父类对象指向子类对象. 下面通过一个例子来深入理解向上转型. //定义一个 ...
- JVM垃圾收集策略解析
地址:http://developer.51cto.com/art/201002/184385_all.htm
- 新一代 Tor发布,它牛在哪里?
导读 知名匿名搜索引擎Tor,最近发布了基于火狐浏览器45-ESR的6.0版本,增强了对HTML5的支持,并更新了用来保护加密流量及其更新机制的安全功能.火狐45-ESR版本的全称为Firefox E ...
- 在link的url里新增参数
(文章都是从我的个人主页上粘贴过来的,大家也可以访问我的主页 www.iwangzheng.com) <%= link_to image_tag("/images/icons/aaa. ...
- zookeeper 用法和日常运维
本文以ZooKeeper3.4.3版本的官方指南为基础:http://zookeeper.apache.org/doc/r3.4.3/zookeeperAdmin.html,补充一些作者运维实践中的要 ...