关于c++中的STL的学习与再认识(三)
2015-07-29 16:45
549 查看
上一篇讲了经常用到和非常重要的迭代器。
**特别注意:**insert()函数返回值类型并不是void,而是返回一个迭代器,此时的it值会改变,指向一块不清楚的内存,将不在是v1.begin();因此以下用法会出错。
第一次插入正确,之后it将不在指向初始迭代器,出错。想继续插入的情况下,必须为insert()函数设置返回值。
此外,insert()函数还有以下用法:
在指定地方插入多个相同的值,返回多个插入值的第一个的位置;
在指定地方插入某一区间的值;
erase()函数:
删除指定位置的一个数,返回删除后第一个数的下标;
删除指定区间的数据,返回删除后第一个数的下标;
切记有返回值
具体实例看代码。
* 添加一个元素,若元素已存在,舍弃;
* 移除元素
* 获取元素个数(不同元素的个数)
* 检测集合中是否存在某个元素
在O(log N)(N是set中对象的个数)的时间复杂度下添加,移除元素,并检测元素时候存在
常数时间复杂度O(1)返回set的元素个数
set没有push_back()函数,因为set中元素的添加顺序不是很重要。insert()最常用的是插入一个元素,返回这个元素的迭代器和一个布尔值(是否插入成功)
set不是线性容器,不能用下标获取set的值。遍历set元素的唯一方法是使用迭代器(print_set函数)
关于find()函数:有一个全局find(),输入两个迭代器和一个元素,时间复杂度为O(N)。但set和map(包括multiset,hash_map)中搜索元素时,不要使用全局find(),而应该使用
4000
时间复杂度为O(logN)。
set中没有排序函数。set有一个区间构造函数。
上述中,v2与s包含相同元素,并且移除了v中重复的元素,可以对v2进行排序。任何可比较的元素都可以存储在set中。
可以看到:map和set非常像,只是它包含的不只是值,而是键值对
* 遍历map只能用迭代器,迭代器是键值对,用it->second来取值。
* 非常相爱那个python中字典。
注意事项:
从内部看,map 和 set 几乎都是以红黑树的结构存储。要记住的是,遍历容器时 map 和 set 的元素总是按升序排列。而这也是为何在遍历 map 或 set时,极力不推荐改变键值的原因:如果所做的修改破坏了元素间的顺序,这至少会导致容器的算法失效。
比较常用的有sort()函数:sort(begin, end) 按升序对一个区间的元素进行排序。注意,sort() 需要随机存取迭代器,因此它不能作用在所有类型的容器上。
find():find()。调用 find(begin, end, element) 返回‘element’首次出现时对应的迭代器,如果找不到则返回 end。和 find(…) 相反,count(begin, end, element) 返回一个元素在容器或容器的某个范围内出现的次数。
Vertor中的数据操作
可以用insert()函数往Vertor中插入一个元素:int n[] = { 22, 33, 11, 44, 55, 66, 99, 55, 88 }; vector<int> v1(n, n + 9); vector<int> v2(n, n + 2); vector<int>::iterator it = v1.begin(); v1.insert(it + 1, 31); //22, 31, 33, 11, 44, 55, 66, 99, 55, 88
**特别注意:**insert()函数返回值类型并不是void,而是返回一个迭代器,此时的it值会改变,指向一块不清楚的内存,将不在是v1.begin();因此以下用法会出错。
v1.insert(it + 1, 31); //22, 31, 33, 11, 44, 55, 66, 99, 55, 88 v1.insert(it, 32);
第一次插入正确,之后it将不在指向初始迭代器,出错。想继续插入的情况下,必须为insert()函数设置返回值。
it = v1.insert(it + 1, 31); //22, 31, 33, 11, 44, 55, 66, 99, 55, 88 v1.insert(it, 32);//22, 32, 31, 33, 11, 44, 55, 66, 99, 55, 88
此外,insert()函数还有以下用法:
int n[] = { 22, 33, 11, 44, 55, 66, 99, 55, 88 }; vector<int> v1(n, n + 9); vector<int> v2(n, n + 2); vector<int>::iterator it = v1.begin(); it = v1.insert(it + 1, 31); //22, 31, 33, 11, 44, 55, 66, 99, 55, 88 it = v1.insert(it, 32);//22, 32, 31, 33, 11, 44, 55, 66, 99, 55, 88 it = v1.insert(it, 3, 100);//22,100,100,100 32, 31, 33, 11, 44, 55, 66, 99, 55, 88 it = v1.insert(it, all(v2));//22, 22, 33 ,100,100,100 32, 31, 33, 11, 44, 55, 66, 99, 55, 88 it = v1.erase(v1.begin() + 1); //22, 33 ,100,100,100 32, 31, 33, 11, 44, 55, 66, 99, 55, 88 *it = 33; it = v1.erase(v1.begin() + 3, v1.begin() + 5); //22, 33 ,100 32, 31, 33, 11, 44, 55, 66, 99, 55, 88 *it = 32; cout << *it << endl;
在指定地方插入多个相同的值,返回多个插入值的第一个的位置;
在指定地方插入某一区间的值;
erase()函数:
删除指定位置的一个数,返回删除后第一个数的下标;
删除指定区间的数据,返回删除后第一个数的下标;
切记有返回值
具体实例看代码。
Set
容器特性:* 添加一个元素,若元素已存在,舍弃;
* 移除元素
* 获取元素个数(不同元素的个数)
* 检测集合中是否存在某个元素
#include <iostream> #include <vector> #include <algorithm> #include <stdio.h> #include <set> using namespace std; void print_set(set<int> s) { for (set<int>::iterator it = s.begin(); it != s.end(); it++) cout << *it << " "; cout << endl; } int main() { set<int> s; for (int i = 1; i < 10; i++) s.insert(i); print_set(s); //1, 2, 3, 4, 5, 6, 7, 8, 9 s.insert(10); //1, 2, 3, 4, 5, 6, 7, 8, 9,10 s.insert(11); //1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11 s.erase(10); //1, 2, 3, 4, 5, 6, 7, 8, 9,11 s.erase(s.find(2), s.find(4)); //1, 2, 3, 4, 5, 6, 7, 8, 9, 11 print_set(s); cout << s.size() << endl; //8 cout << endl; system("pause"); return 0; }
在O(log N)(N是set中对象的个数)的时间复杂度下添加,移除元素,并检测元素时候存在
常数时间复杂度O(1)返回set的元素个数
set没有push_back()函数,因为set中元素的添加顺序不是很重要。insert()最常用的是插入一个元素,返回这个元素的迭代器和一个布尔值(是否插入成功)
set不是线性容器,不能用下标获取set的值。遍历set元素的唯一方法是使用迭代器(print_set函数)
关于find()函数:有一个全局find(),输入两个迭代器和一个元素,时间复杂度为O(N)。但set和map(包括multiset,hash_map)中搜索元素时,不要使用全局find(),而应该使用
set::find(),
4000
时间复杂度为O(logN)。
set中没有排序函数。set有一个区间构造函数。
vector<int> v; set<int> s(all(v)); vertor<int> v2(all(s));
上述中,v2与s包含相同元素,并且移除了v中重复的元素,可以对v2进行排序。任何可比较的元素都可以存储在set中。
Map
#include <iostream> #include <vector> #include <algorithm> #include <stdio.h> #include <set> #include <map> using namespace std; void print_map(map<string ,int> m) { for (map<string, int>::iterator it = m.begin(); it != m.end(); it++){ cout << it->second << " "; } cout << endl; } int main() { map<string, int> m; m["first"] = 1; m["second"] = 2; m["third"] = 3; int sum = m["first"] + m["third"]; cout << sum << endl; //4 cout << m.find("second")->second << endl; //2 cout << (*m.find("second")).second << endl; //2 print_map(m); system("pause"); return 0; }
可以看到:map和set非常像,只是它包含的不只是值,而是键值对
pair<key,value>.Map保证最多只有一个键值拥有指定键。
* 遍历map只能用迭代器,迭代器是键值对,用it->second来取值。
* 非常相爱那个python中字典。
注意事项:
从内部看,map 和 set 几乎都是以红黑树的结构存储。要记住的是,遍历容器时 map 和 set 的元素总是按升序排列。而这也是为何在遍历 map 或 set时,极力不推荐改变键值的原因:如果所做的修改破坏了元素间的顺序,这至少会导致容器的算法失效。
常用算法
大部分算法都生声明在标准头文件#include<algorithm>。首先,STL提供了三种很简单的算法:min(a,b),max(a ,b ),swap(a,b)。
比较常用的有sort()函数:sort(begin, end) 按升序对一个区间的元素进行排序。注意,sort() 需要随机存取迭代器,因此它不能作用在所有类型的容器上。
find():find()。调用 find(begin, end, element) 返回‘element’首次出现时对应的迭代器,如果找不到则返回 end。和 find(…) 相反,count(begin, end, element) 返回一个元素在容器或容器的某个范围内出现的次数。
特别建议
在编写程序的过程中,模板列表能简化代码的阅读。typedef vector<int> vi; typedef vector<vi> vii; typedef pair<int, int> ii; #define sz(a) int(a.size()) //求对象a的大小 #define pb push_back #define all(c) c.begin(),c.end() //注意,all(c)后无括号 #define present(c,x) ((c).find(x) != (c).end()) //元素x存在与c中,用于set,map等 #define cpresent(c,x) (find(all(c),x) != (c).end()) //通用算法find,适用于全部容器,时间复杂度O(n)。
相关文章推荐
- 设计模式之行为型模式 - 调用行为的传递问题
- Ruby中的迭代器详解
- Ruby中Block和迭代器的使用讲解
- Lua中的迭代器浅析
- Lua中的迭代器和泛型for介绍
- C#特性-迭代器(上)及一些研究过程中的副产品
- C#迭代器模式(Iterator Pattern)实例教程
- C++ Vector用法详解
- Lua中的迭代器和泛型for学习总结
- C#特性 迭代器(下) yield以及流的延迟计算
- 大家注意vector, list, set, map成员函数erase
- ruby 迭代器使用方法
- 使用迭代器 遍历文件信息的详解
- PHP迭代器的内部执行过程详解
- java中vector与hashtable操作实例分享
- C++ vector删除符合条件的元素示例分享
- C#中使用迭代器处理等待任务
- Lua的迭代器使用中应该避免的问题和技巧
- C++ Vector用法深入剖析
- vector与map的erase()函数详细解析