关于STL:封装了许多的复杂数据结构算法和大量的常用数据结构操作。
1.vector 封装数组
2.list 封装了链表
3.map,set 封装了二叉树等
问题1:为哈map和set的插入和删除效率比用其他容器高?
对于关联容器来说,不需要做内存拷贝和内存移动,set和map容器内所有元素都以结点的方式来存储的,其结构和链表差不多,指向父节点和子节点,如图:
A
/ \
B C
/ \ / \
D E F G
因此插入的时候只需要稍做变换,把节点的指针指向新的节点就可以了。删除的时候类似,稍做变换后把指向删除节点的指针指向其他节点也OK了。这里的一切操作就是指针换来换去,和内存移动没有关系。
问题二:为何每次insert之后,以前保存的iterator不会失效?
iterator这里就相当于指向节点的指针,内存没有变,指向内存的指针怎么会失效呢(当然被删除的那个元素本身已经失效了)。相对于vector来说,每一次删除和插入,指针都有可能失效,调用push_back在尾部插入也是如此。因为为了保证内部数据的连续存放,iterator指向的那块内存在删除和插入过程中可能已经被其他内存覆盖或者内存已经被释放了。即使时push_back的时候,容器内部空间可能不够,需要一块新的更大的内存,只有把以前的内存释放,申请新的更大的内存,复制已有的数据元素到新的内存,最后把需要插入的元素放到最后,那么以前的内存指针自然就不可用了。特别时在和find等算法在一起使用的时候,牢记这个原则:不要使用过期的iterator。
问题三:当数据元素增多时,set的插入和搜索速度变化如何?
在set中查找是使用二分查找,也就是说,如果有16个元素,最多需要比较4次就能找到结果,有32个元素,最多比较5次。那么有10000个呢?最多比较的次数为log10000,最多为14次,如果是20000个元素呢?最多不过15次。看见了吧,当数据量增大一倍的时候,搜索次数只不过多了1次,多了1/14的搜索时间而已。你明白这个道理后,就可以安心往里面放入元素了。
set常用的几个函数:
begin(): 返回set容器的第一个元素
end() : 返回set容器的最后一个元素的后一个
clear(): 删除set容器中的所有的元素
empty() : 判断set容器是否为空
max_size() :返回set容器可能包含的元素最大个数
size() :返回当前set容器中的元素个数
rbegin:返回的值和end()相同
rend():返回的值和rbegin()相同
知识点梳理:
1.begin( )和cbegin( )异同
a:iterator,const_iterator作用:遍历容器内的元素,并访问这些元素的值。iterator可以改元素值,但const_iterator不可改。跟 C 的指针有点像。
b.const_iterator 对象可以用于const vector 或非 const vector,它自身的值可以改(可以指向其他元素),但不能改写其指向的元素 值。
c.cbegin()和cend()是C++11新增的,它们返回一个const的迭代器,不能用于修改元素。
auto i1 = Container.begin(); // i1 is Container<T>::iterator
auto i2 = Container.cbegin(); // i2 is Container<T>::const_iterator
2.begin()和crbegin()
c可以理解成const的缩写
r可以理解成reverse的缩写
Example:
#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()-1)<<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::begin
set::begin
#include<iostream>
#include<set>
using namespace std;
int main()
{
int a[] = { 10,3,2,5,1 };
set<int>s(a, a + 5);
for (set<int>::iterator it = s.begin();it != s.end();++it) cout << *it << endl;
return 0;
}
set::cbegin/cend
#include <iostream>
#include <set>
int main ()
{
std::set<int> myset = {50,20,60,10,25};
std::cout << "myset contains:";
for (auto it=myset.cbegin(); it != myset.cend(); ++it)
std::cout << ' ' << *it;
std::cout << '\n';
return 0;
}
myset contains: 10 20 25 50 60
set::rbegin/rend
#include <iostream>
#include <set>
int main ()
{
int myints[] = {21,64,17,78,49};
std::set<int> myset (myints,myints+5);
std::set<int>::reverse_iterator rit;
std::cout << "myset contains:";
for (rit=myset.rbegin(); rit != myset.rend(); ++rit)
std::cout << ' ' << *rit;
std::cout << '\n';
return 0;
}
myset contains: 78 64 49 21 17
set::crbegin/crend
#include <iostream>
#include <set>
int main ()
{
std::set<int> myset = {50,20,60,10,25};
std::cout << "myset backwards:";
for (auto rit=myset.crbegin(); rit != myset.crend(); ++rit)
std::cout << ' ' << *rit;
std::cout << '\n';
return 0;
}
myset backwards: 60 50 25 20 10
set::clear
#include <iostream>
#include <set>
int main ()
{
std::set<int> myset;
myset.insert (100);
myset.insert (200);
myset.insert (300);
std::cout << "myset contains:";
for (std::set<int>::iterator it=myset.begin(); it!=myset.end(); ++it)
std::cout << ' ' << *it;
std::cout << '\n';
myset.clear();
myset.insert (1101);
myset.insert (2202);
std::cout << "myset contains:";
for (std::set<int>::iterator it=myset.begin(); it!=myset.end(); ++it)
std::cout << ' ' << *it;
std::cout << '\n';
return 0;
}
myset contains: 100 200 300
myset contains: 1101 2202
set::insert (C++98)
insert(key_value); 将key_value插入到set中 ,返回值是pair<set<int>::iterator,bool>,bool标志着插入是否成功,而iterator代表插入的位置,若key_value已经在set中,则iterator表示的key_value在set中的位置。
inset(first,second);将定位器first到second之间的元素插入到set中,返回值是void.
#include <iostream>
#include <set>
int main ()
{
std::set<int> myset;
std::set<int>::iterator it;
std::pair<std::set<int>::iterator,bool> ret;
// set some initial values:
for (int i=1; i<=5; ++i) myset.insert(i*10); // set: 10 20 30 40 50
ret = myset.insert(20); // no new element inserted
if (ret.second==false) std::cout<<"fdsa"<<std::endl,it=ret.first; // "it" now points to element 20
myset.insert (it,25); // max efficiency inserting
myset.insert (it,24); // max efficiency inserting
myset.insert (it,26); // no max efficiency inserting
int myints[]= {5,10,15}; // 10 already in set, not inserted
myset.insert (myints,myints+3);
std::cout << "myset contains:";
for (it=myset.begin(); it!=myset.end(); ++it)
std::cout << ' ' << *it;
std::cout << '\n';
return 0;
}
set::count
count() 用来查找set中某个某个键值出现的次数。这个函数在set并不是很实用,因为一个键值在set只可能出现0或1次,这样就 变成了判断某一键值是否在set出现过了。
#include <iostream>
#include <set>
int main ()
{
std::set<int> myset;
// set some initial values:
for (int i=1; i<5; ++i) myset.insert(i*3); // set: 3 6 9 12
for (int i=0; i<10; ++i)
{
std::cout << i;
if (myset.count(i)!=0)
std::cout << " is an element of myset.\n";
else
std::cout << " is not an element of myset.\n";
}
return 0;
}
Edit & Run
0 is not an element of myset.
1 is not an element of myset.
2 is not an element of myset.
3 is an element of myset.
4 is not an element of myset.
5 is not an element of myset.
6 is an element of myset.
7 is not an element of myset.
8 is not an element of myset.
9 is an element of myset.
set::find
返回给定值值得定位器,如果没找到则返回end()。
#include <iostream>
#include <set>
int main ()
{
std::set<int> myset;
std::set<int>::iterator it;
// set some initial values:
for (int i=1; i<=5; i++) myset.insert(i*10); // set: 10 20 30 40 50
it=myset.find(20);
myset.erase (it);
myset.erase (myset.find(40));
std::cout << "myset contains:";
for (it=myset.begin(); it!=myset.end(); ++it)
std::cout << ' ' << *it;
std::cout << '\n';
return 0;
}
myset contains: 10 30 50
erase(iterator) ,删除定位器iterator指向的值
erase(first,second),删除定位器first和second之间的值
erase(key_value),删除键值key_value的值
#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::emplace
#include<bits/stdc++.h>
using namespace std;
int main()
{
set<string>s;
s.emplace("chen");
s.emplace("abc");
s.emplace("bcd");
for(auto it:s){
cout<<it<<endl;
}
return 0;
}
set::lower_bound/upper_bound
lower_bound(key_value) ,返回第一个大于等于key_value的定位器
upper_bound(key_value),返回最后一个大于等于key_value的定位器
#include <iostream>
#include <set>
int main ()
{
std::set<int> myset;
std::set<int>::iterator itlow,itup;
for (int i=1; i<10; i++) myset.insert(i*10); // 10 20 30 40 50 60 70 80 90
itlow=myset.lower_bound (30); // ^
itup=myset.upper_bound (60); // ^
myset.erase(itlow,itup); // 10 20 70 80 90
std::cout << "myset contains:";
for (std::set<int>::iterator it=myset.begin(); it!=myset.end(); ++it)
std::cout << ' ' << *it;
std::cout << '\n';
return 0;
}
myset contains: 10 20 70 80 90
set::equal_elements
equal_range() ,返回一对定位器,分别表示第一个大于或等于给定关键值的元素和 第一个大于给定关键值的元素,这个返回值是一个pair类型,如果这一对定位器中哪个返回失败,就会等于end()的值。具体这个有什么用途我还没遇到过~~~
#include <iostream>
#include <set>
int main ()
{
std::set<int> myset;
for (int i=1; i<=5; i++) myset.insert(i*10); // myset: 10 20 30 40 50
std::pair<std::set<int>::const_iterator,std::set<int>::const_iterator> ret;
ret = myset.equal_range(30);
std::cout << "the lower bound points to: " << *ret.first << '\n';
std::cout << "the upper bound points to: " << *ret.second << '\n';
return 0;
}
the lower bound points to: 30
the upper bound points to: 40
swap sets
#include <iostream>
#include <set>
main ()
{
int myints[]={12,75,10,32,20,25};
std::set<int> first (myints,myints+3); // 10,12,75
std::set<int> second (myints+3,myints+6); // 20,25,32
first.swap(second);
std::cout << "first contains:";
for (std::set<int>::iterator it=first.begin(); it!=first.end(); ++it)
std::cout << ' ' << *it;
std::cout << '\n';
std::cout << "second contains:";
for (std::set<int>::iterator it=second.begin(); it!=second.end(); ++it)
std::cout << ' ' << *it;
std::cout << '\n';
return 0;
}
Edit & Run
first contains: 20 25 32
second contains: 10 12 75
自定义比较函数
(1)元素不是结构体:
例:
//自定义比较函数myComp,重载“()”操作符
struct myComp
{
bool operator()(const your_type &a,const your_type &b)
{
return a.data>b.data;
}
}
set<int,myComp>s;
......
set<int,myComp>::iterator it;
(2)如果元素是结构体,可以直接将比较函数写在结构体内。
例:
struct Info
{
string name;
float score;
//重载“<”操作符,自定义排序规则
bool operator < (const Info &a) const
{
//按score从大到小排列
return a.score<score;
}
}
set<Info> s;
......
set<Info>::iterator it;