隶书文字为原创。
1.vector
在c++中,vector是一个十分有用的容器,下面对这个容器做一下总结。
1 基本操作
(1)头文件#include<vector>.
(2)创建vector对象,vector<int> vec;
(3)尾部插入数字:vec.push_back(a);
(4)使用下标访问元素,cout<<vec[0]<<endl;记住下标是从0开始的。
(5)使用迭代器访问元素.
vector<int>::iterator it;
for(it=vec.begin();it!=vec.end();it++)
cout<<*it<<endl;
(6)插入元素: vec.insert(vec.begin()+i,a);在第i+1个元素前面插入a;
(7)删除元素: vec.erase(vec.begin()+2);删除第3个元素
vec.erase(vec.begin()+i,vec.end()+j);删除区间[i,j-1];区间从0开始
(8)向量大小:vec.size();
(9)清空:vec.clear();
2
vector的元素不仅仅可以使int,double,string,还可以是结构体,但是要注意:结构体要定义为全局的,否则会出错。下面是一段简短的程序代码:
#include<stdio.h>
#include<algorithm>
#include<vector>
#include<iostream>
using namespace std; typedef struct rect
{
int id;
int length;
int width;
//对于向量元素是结构体的,可在结构体内部定义比较函数,下面按照id,length,width升序排序。 bool operator< (const rect &a) const { if(id!=a.id) return id<a.id; else { if(length!=a.length) return length<a.length; else return width<a.width; } }
}Rect; int main()
{
vector<Rect> vec;
Rect rect;
rect.id=1;
rect.length=2;
rect.width=3;
vec.push_back(rect);
vector<Rect>::iterator it=vec.begin();
cout<<(*it).id<<' '<<(*it).length<<' '<<(*it).width<<endl; return 0; }
3 算法
(1) 使用reverse将元素翻转:需要头文件#include<algorithm>
reverse(vec.begin(),vec.end());将元素翻转(在vector中,如果一个函数中需要两个迭代器,
一般后一个都不包含.)
(2)使用sort排序:需要头文件#include<algorithm>,
sort(vec.begin(),vec.end());(默认是按升序排列,即从小到大).
可以通过重写排序比较函数按照降序比较,如下:
定义排序比较函数:
bool Comp(const int &a,const int &b) { return a>b; } 调用时:sort(vec.begin(),vec.end(),Comp),这样就降序排序。
对于建立二维vector 或更高维vector,网上有人说用vector<***int> b之类的(有n个*就是n+1维),原理当然是数组b 存的是b的首地址,但是这样做将会导致插入删除不方便以及打出来的操作代码过于冗长。在这里我还是建议使用vector<vector<int>>这样的定义操作,这样操作以及调用动态存储比前一种做法方便多了,也简洁多了。
2.set
集和多集(set 和multiset 容器类)
构造
方法:
集合操作:
..........................
1.关于set
C++ STL 之所以得到广泛的赞誉,也被很多人使用,不只是提供了像vector, string, list等方便的容器,更重要的是STL封装了许多复杂的数据结构算法和大量常用数据结构操作。vector封装数组,list封装了链表,map和set封装了二叉树等,在封装这些数据结构的时候,STL按照程序员的使用习惯,以成员函数方式提供的常用操作,如:插入、排序、删除、查找等。让用户在STL使用过程中,并不会感到陌生。
关于set,必须说明的是set关联式容器。set作为一个容器也是用来存储同一数据类型的数据类型,并且能从一个数据集合中取出数据,在set中每个元素的值都唯一,而且系统能根据元素的值自动进行排序。应该注意的是set中数元素的值不能直接被改变。C++ STL中标准关联容器set, multiset, map, multimap内部采用的就是一种非常高效的平衡检索二叉树:红黑树,也成为RB树(Red-Black Tree)。RB树的统计性能要好于一般平衡二叉树,所以被STL选择作为了关联容器的内部结构。
关于set有下面几个问题:
(1)为何map和set的插入删除效率比用其他序列容器高?
大部分人说,很简单,因为对于关联容器来说,不需要做内存拷贝和内存移动。说对了,确实如此。set容器内所有元素都是以节点的方式来存储,其节点结构和链表差不多,指向父节点和子节点。结构图可能如下:
A / \ B C / \ / \ D E F G
因此插入的时候只需要稍做变换,把节点的指针指向新的节点就可以了。删除的时候类似,稍做变换后把指向删除节点的指针指向其他节点也OK了。这里的一切操作就是指针换来换去,和内存移动没有关系。
(2)为何每次insert之后,以前保存的iterator不会失效?
iterator这里就相当于指向节点的指针,内存没有变,指向内存的指针怎么会失效呢(当然被删除的那个元素本身已经失效了)。相对于vector来说,每一次删除和插入,指针都有可能失效,调用push_back在尾部插入也是如此。因为为了保证内部数据的连续存放,iterator指向的那块内存在删除和插入过程中可能已经被其他内存覆盖或者内存已经被释放了。即使时push_back的时候,容器内部空间可能不够,需要一块新的更大的内存,只有把以前的内存释放,申请新的更大的内存,复制已有的数据元素到新的内存,最后把需要插入的元素放到最后,那么以前的内存指针自然就不可用了。特别时在和find等算法在一起使用的时候,牢记这个原则:不要使用过期的iterator。
(3)当数据元素增多时,set的插入和搜索速度变化如何?
如果你知道log2的关系你应该就彻底了解这个答案。在set中查找是使用二分查找,也就是说,如果有16个元素,最多需要比较4次就能找到结果,有32个元素,最多比较5次。那么有10000个呢?最多比较的次数为log10000,最多为14次,如果是20000个元素呢?最多不过15次。看见了吧,当数据量增大一倍的时候,搜索次数只不过多了1次,多了1/14的搜索时间而已。你明白这个道理后,就可以安心往里面放入元素了。
2.set中常用的方法
begin() ,返回set容器的第一个元素
end() ,返回set容器的最后一个元素
clear() ,删除set容器中的所有的元素
empty() ,判断set容器是否为空
max_size() ,返回set容器可能包含的元素最大个数
size() ,返回当前set容器中的元素个数
rbegin ,返回的值和end()相同
rend() ,返回的值和rbegin()相同
写一个程序练一练这几个简单操作吧:
- #include <iostream>
- #include <set>
- using namespace std;
- int main()
- {
- set<int> s;
- s.insert(1);
- s.insert(2);
- s.insert(3);
- s.insert(1);
- cout<<"set 的 size 值为 :"<<s.size()<<endl;
- cout<<"set 的 maxsize的值为 :"<<s.max_size()<<endl;
- cout<<"set 中的第一个元素是 :"<<*s.begin()<<endl;
- cout<<"set 中的最后一个元素是:"<<*s.end()<<endl;
- s.clear();
- if(s.empty())
- {
- cout<<"set 为空 !!!"<<endl;
- }
- cout<<"set 的 size 值为 :"<<s.size()<<endl;
- cout<<"set 的 maxsize的值为 :"<<s.max_size()<<endl;
- return 0;
- }
- /*
- 运行结果:
- set 的 size 值为 :3
- set 的 maxsize的值为 :214748364
- set 中的第一个元素是 :1
- set 中的最后一个元素是:3
- set 为空 !!!
- set 的 size 值为 :0
- set 的 maxsize的值为 :214748364
- Process returned 0 (0x0) execution time : 2.523 s
- Press any key to continue.
- */
count() 用来查找set中某个某个键值出现的次数。这个函数在set并不是很实用,因为一个键值在set只可能出现0或1次,这样就变成了判断某一键值是否在set出现过了。
示例代码:
- #include <iostream>
- #include <set>
- using namespace std;
- int main()
- {
- set<int> s;
- s.insert(1);
- s.insert(2);
- s.insert(3);
- s.insert(1);
- cout<<"set 中 1 出现的次数是 :"<<s.count(1)<<endl;
- cout<<"set 中 4 出现的次数是 :"<<s.count(4)<<endl;
- return 0;
- }
- 运行结果:
- set 中 1 出现的次数是 :1
- set 中 4 出现的次数是 :0
- Process returned 0 (0x0) execution time : 5.112 s
- Press any key to continue.
equal_range() ,返回一对******,分别表示第一个大于或等于给定关键值的元素和 第一个大于给定关键值的元素,这个返回值是一个pair类型,如果这一对******中哪个返回失败,就会等于end()的值。
示例代码:
- #include <iostream>
- #include <set>
- using namespace std;
- int main()
- {
- set<int> s;
- set<int>::iterator iter;
- for(int i = 1 ; i <= 5; ++i)
- {
- s.insert(i);
- }
- for(iter = s.begin() ; iter != s.end() ; ++iter)
- {
- cout<<*iter<<" ";
- }
- cout<<endl;
- pair<set<int>::const_iterator,set<int>::const_iterator> pr;
- pr = s.equal_range(3);
- cout<<"第一个大于等于 3 的数是 :"<<*pr.first<<endl;
- cout<<"第一个大于 3的数是 : "<<*pr.second<<endl;
- return 0;
- }
- /**
- 运行结果:
- 1 2 3 4 5
- 第一个大于等于 3 的数是 :3
- 第一个大于 3的数是 : 4
- Process returned 0 (0x0) execution time : 3.090 s
- Press any key to continue.
- **/
erase(iterator) ,删除******iterator指向的值
erase(first,second),删除******first和second之间的值
erase(key_value),删除键值key_value的值
set中的删除操作是不进行任何的错误检查的,比如******的是否合法等等,所以用的时候自己一定要注意。
示例代码:
- #include <iostream>
- #include <set>
- using namespace std;
- int main()
- {
- set<int> s;
- set<int>::const_iterator iter;
- set<int>::iterator first;
- set<int>::iterator second;
- for(int i = 1 ; i <= 10 ; ++i)
- {
- s.insert(i);
- }
- //第一种删除
- s.erase(s.begin());
- //第二种删除
- first = s.begin();
- second = s.begin();
- second++;
- second++;
- s.erase(first,second);
- //第三种删除
- s.erase(8);
- cout<<"删除后 set 中元素是 :";
- for(iter = s.begin() ; iter != s.end() ; ++iter)
- {
- cout<<*iter<<" ";
- }
- cout<<endl;
- return 0;
- }
- /**
- 运行结果:
- 删除后 set 中元素是 :4 5 6 7 9 10
- Process returned 0 (0x0) execution time : 3.290 s
- Press any key to continue.
- **/
find() ,返回给定值值得******,如果没找到则返回end()。
示例代码:
- #include <iostream>
- #include <set>
- using namespace std;
- int main()
- {
- int a[] = {1,2,3};
- set<int> s(a,a+3);
- set<int>::iterator iter;
- if((iter = s.find(2)) != s.end())
- {
- cout<<*iter<<endl;
- }
- return 0;
- }
- /**
- 运行结果:
- 2
- Process returned 0 (0x0) execution time : 5.168 s
- Press any key to continue.
- **/
insert(key_value); 将key_value插入到set中 ,返回值是pair<set<int>::iterator,bool>,bool标志着插入是否成功,而iterator代表插入的位置,若key_value已经在set中,则iterator表示的key_value在set中的位置。
insert(first,second);将******first到second之间的元素插入到set中,返回值是void.
示例代码:
- #include <iostream>
- #include <set>
- #include <iterator>
- using namespace std;
- int main()
- {
- int a[] = {1,2,3};
- set<int> s;
- set<int>::iterator iter;
- s.insert(a,a+3);
- for(iter = s.begin() ; iter != s.end() ; ++iter)
- {
- cout<<*iter<<" ";
- }
- cout<<endl;
- pair<set<int>::iterator,bool> pr;
- pr = s.insert(5);
- if(pr.second)
- {
- cout<<"*pr.first= "<<*pr.first<<endl;
- // print all elements
- copy (s.begin(), s.end(),ostream_iterator<int>(cout," "));
- }
- return 0;
- }
- /**
- 运行结果:
- 1 2 3
- *pr.first= 5
- 1 2 3 5
- Process returned 0 (0x0) execution time : 0.521 s
- Press any key to continue.
- **/
lower_bound(key_value) ,返回第一个大于等于key_value的******
upper_bound(key_value),返回最后一个大于等于key_value的******
- #include <iostream>
- #include <set>
- using namespace std;
- int main()
- {
- set<int> s;
- s.insert(1);
- s.insert(3);
- s.insert(4);
- cout<<*s.lower_bound(2)<<endl;
- cout<<*s.lower_bound(3)<<endl;
- cout<<*s.upper_bound(3)<<endl;
- return 0;
- }
- /*
- 运行结果:
- 3
- 3
- 4
- Process returned 0 (0x0) execution time : 3.347 s
- Press any key to continue.
- */
3.map
1、map简介
map是一类关联式容器。它的特点是增加和删除节点对迭代器的影响很小,除了那个操作节点,对其他的节点都没有什么影响。对于迭代器来说,可以修改实值,而不能修改key。
2、map的功能
自动建立Key -value的对应。key 和value可以是任意你需要的类型。
根据key值快速查找记录,查找的复杂度基本是Log(N),如果有1000个记录,最多查找10次,1,000,000个记录,最多查找20次。
快速插入Key - Value 记录。
快速删除记录 根据Key 修改value记录。
遍历所有记录。
3、使用map
使用map得包含map类所在的头文件
#include <map> //注意,STL头文件没有扩展名.h
map对象是模板类,需要关键字和存储对象两个模板参数:
std:map<int, string> personnel;
这样就定义了一个用int作为索引,并拥有相关联的指向string的指针.
为了使用方便,可以对模板类进行一下类型定义,
typedef map<int, CString> UDT_MAP_INT_CSTRING;
UDT_MAP_INT_CSTRING enumMap;
4、在map中插入元素
改变map中的条目非常简单,因为map类已经对[]操作符进行了重载
enumMap[1] = "One";
enumMap[2] = "Two";
.....
这样非常直观,但存在一个性能的问题。插入2时,先在enumMap中查找主键为2的项,没发现,然后将一个新的对象插入enumMap,键是2, 值是一个空字符串,插入完成后将字符串赋为"Two"; 该方法会将每个值都赋为缺省值,然后再赋为显示的值,如果元素是类对象,则开销比较大。我们可以用以下方法来避免开销:
enumMap.insert(map<int, CString> :: value_type(2, "Two"))
5、查找并获取
map中的元素下标操作符给出了获得一个值的最简单方法:
CString tmp = enumMap[2];
但是,只有当map中有这个键的实例时才对,否则会自动插入一个实例,值为初始化值。 我们可以使用Find()和Count()方法来发现一个键是否存在。 查找map中是否包含某个关键字条目用find()方法,传入的参数是要查找的key,在这里需要提到的是begin()和end()两个成员,分别代表map对象中第一个条目和最后一个条目,这两个数据的类型是iterator.
int nFindKey = 2; //要查找的Key //
定义一个条目变量(实际是指针)
UDT_MAP_INT_CSTRING::iterator it= enumMap.find(nFindKey);
if(it == enumMap.end()) {
//没找到
}
else {
//找到
}
通过map对象的方法获取的iterator数据类型是一个std::pair对象,包括两个数据 iterator->first 和 iterator->second 分别代表关键字和存储的数据
6、从map中删除元素
移除某个map中某个条目用erase()
该成员方法的定义如下
iterator erase(iterator it); //
通过一个条目对象删除
iterator erase(iterator first, iterator last); //
删除一个范围
size_type erase(const Key& key); //
通过关键字删除clear()
就相当于
enumMap.erase(enumMap.begin(), enumMap.end());
1. map最基本的构造函数;
map<string , int >mapstring;
map<int ,string >mapint;
map<sring, char>mapstring;
map< char ,string>mapchar;
map<char ,int>mapchar;
map<int ,char >mapint;
2. map添加数据;
map<int ,string> maplive;
1.maplive.insert(pair<int,string>(102,"aclive"));
2.maplive.insert(map<int,string>::value_type(321,"hai"));
3, maplive[112]="April";//map中最简单最常用的插入添加!
3.map中元素的查找:
find()函数返回一个迭代器指向键值为key的元素,如果没找到就返回指向map尾部的迭代器。
map<int ,string >::iterator l_it;;
l_it=maplive.find(112);
if(l_it==maplive.end())
cout<<"we do not find 112"<<endl;
else cout<<"wo find 112"<<endl;
4,map中元素的删除:
如果删除112;
map<int ,string >::iterator l_it;
l_it=maplive.find(112);
if(l_it==maplive.end())
cout<<"we do not find 112"<<endl;
else
maplive.erase(l_it);
//delete 112;
5,map中swap的用法:
Map中的swap不是一个容器中的元素交换,而是两个容器交换;
For example:
#include <map>
#include <iostream>
using namespace std;
int main( )
{
map <int, int> m1, m2, m3;
map <int, int>::iterator m1_Iter;
m1.insert ( pair <int, int> ( 1, 10 ) );
m1.insert ( pair <int, int> ( 2, 20 ) );
m1.insert ( pair <int, int> ( 3, 30 ) );
m2.insert ( pair <int, int> ( 10, 100 ) );
m2.insert ( pair <int, int> ( 20, 200 ) );
m3.insert ( pair <int, int> ( 30, 300 ) );
cout << "The original map m1 is:";
for ( m1_Iter = m1.begin( ); m1_Iter != m1.end( ); m1_Iter++ )
cout << " " << m1_Iter->second;
cout << "." << endl;
// This is the member function version of swap
//m2 is said to be the argument map; m1 the target map
m1.swap( m2 );
cout << "After swapping with m2, map m1 is:";
for ( m1_Iter = m1.begin( ); m1_Iter != m1.end( ); m1_Iter++ )
cout << " " << m1_Iter -> second;
cout << "." << endl;
cout << "After swapping with m2, map m2 is:";
for ( m1_Iter = m2.begin( ); m1_Iter != m2.end( ); m1_Iter++ )
cout << " " << m1_Iter -> second;
cout << "." << endl;
// This is the specialized template version of swap
swap( m1, m3 );
cout << "After swapping with m3, map m1 is:";
for ( m1_Iter = m1.begin( ); m1_Iter != m1.end( ); m1_Iter++ )
cout << " " << m1_Iter -> second;
cout << "." << endl;
}
6.map的sort问题:
Map中的元素是自动按key升序排序,所以不能对map用sort函数:
For example:
#include <map>
#include <iostream>
using namespace std;
int main( )
{
map <int, int> m1;
map <int, int>::iterator m1_Iter;
m1.insert ( pair <int, int> ( 1, 20 ) );
m1.insert ( pair <int, int> ( 4, 40 ) );
m1.insert ( pair <int, int> ( 3, 60 ) );
m1.insert ( pair <int, int> ( 2, 50 ) );
m1.insert ( pair <int, int> ( 6, 40 ) );
m1.insert ( pair <int, int> ( 7, 30 ) );
cout << "The original map m1 is:"<<endl;
for ( m1_Iter = m1.begin( ); m1_Iter != m1.end( ); m1_Iter++ )
cout << m1_Iter->first<<" "<<m1_Iter->second<<endl;
}
The original map m1 is:
1 20
2 50
3 60
4 40
6 40
7 30
请按任意键继续. . .
7,map的基本操作函数:
C++ Maps是一种关联式容器,包含“关键字/值”对
begin() 返回指向map头部的迭代器
clear() 删除所有元素
count() 返回指定元素出现的次数
empty() 如果map为空则返回true
end() 返回指向map末尾的迭代器
equal_range() 返回特殊条目的迭代器对
erase() 删除一个元素
find() 查找一个元素
get_allocator() 返回map的配置器
insert() 插入元素
key_comp() 返回比较元素
key的函数 lower_bound() 返回键值>=给定元素的第一个位置
max_size() 返回可以容纳的最大元素个数
rbegin() 返回一个指向map尾部的逆向迭代器
rend() 返回一个指向map头部的逆向迭代器
size() 返回map中元素的个数
swap() 交换两个map
upper_bound() 返回键值>给定元素的第一个位置
value_comp() 返回比较元素value的函数