1.STL容器
1.1 set容器
1.1.1 set容器基本概念
Set的特性是:所有元素都会根据元素的键值自动被排序。Set的元素不像map那样可以
同时拥有实值和键值,set的元素即是键值又是实值。Set不允许两个元素有相同的键值。
set拥有和list某些相同的性质,当对容器中的元素进行插入操作或者删除操作的时候,
操作之前所有的迭代器,在操作完成之后依然有效,被删除的那个元素的迭代器必然是一
个例外。
1.1.2 multiset容器基本概念
multiset特性及用法和set完全相同,唯一的差别在于它允许键值重复。set和multiset
的底层实现是红黑树,红黑树为平衡二叉树的一种。
当一个二叉搜索树的左子树和右子树不平衡的时候,搜索最大值所花费的时间要比
搜索最小值所花费的时间要多,由于我们的输入或者经过我们插入或者删除操作,二
叉树失去平衡,造成搜索效率降低。
所以我们有了一个平衡二叉树的概念,所谓的平衡不是指的完全平衡。
1.1.3 set容器常用API
1.1.3.1 set构造函数
set<T> st;//set默认构造函数:
mulitset<T> mst; //multiset默认构造函数:
set(const set &st);//拷贝构造函数
1.1.3.2 set赋值操作
set&operator=(const set &st);//重载等号操作符
swap(st);//交换两个集合容器
1.1.3.3 set大小操作
size();//返回容器中元素的数目
empty();//判断容器是否为空
1.1.3.4 set插入和删除操作
insert(elem);//在容器中插入元素。
clear();//清除所有元素
erase(pos);//删除pos迭代器所指的元素,返回下一个元素的迭代器。
erase(beg, end);//删除区间[beg,end)的所有元素 ,返回下一个元素的迭代器。
erase(elem);//删除容器中值为elem的元素。
1.1.3.5 set查找操作
find(key);//查找键key是否存在,若存在,返回该键的元素的迭代器;若不存在,返回set.end();
1.count(key);//查找键key的元素个数
2.lower_bound(keyElem);//返回第一个key>=keyElem元素的迭代器。
3.upper_bound(keyElem);//返回第一个key>keyElem元素的迭代器。
equal_range(keyElem);//返回容器中key与keyElem相等的上下限的两个迭代器。
#define _CRT_SECURE_NO_WARNINGS
#include<iostream>
#include<string>
#include<set>
#include<algorithm>
using namespace std;
void test()
{
set<int>::iterator it;
it++;
it--;
}
void printSet(set<int>& s)
{
for (set<int>::iterator it = s.begin(); it != s.end(); it++)
{
cout << *it << " ";
}
cout << endl;
}
void test01()
{
set<int> s;
s.insert(5);
s.insert(8);
s.insert(2);
s.insert(4);
s.insert(3);
s.insert(1);
pair<set<int>::iterator,bool>ret = s.insert(1);
if (ret.second == true)
cout << "插入成功!" << endl;
else
cout << "插入失败!" << endl;
s.erase(2);
s.erase(s.begin());
printSet(s);
}
struct MyFunc
{
bool operator()(int a1, int a2) const
{
return a1 > a2;
}
};
void printSet1(set<int, MyFunc>& s)
{
for (set<int, MyFunc>::iterator it = s.begin(); it != s.end(); it++)
{
cout << *it << " ";
}
cout << endl;
}
void test02()
{
set<int, MyFunc> s;
s.insert(5);
s.insert(8);
s.insert(2);
s.insert(4);
s.insert(3);
s.insert(1);
s.insert(1);
printSet1(s);
}
void mySort(int a)
{
cout<<a<<" ";
}
void test03()
{
multiset<int> s;
s.insert(5);
s.insert(8);
s.insert(2);
s.insert(4);
s.insert(3);
s.insert(1);
s.insert(1);
for_each(s.begin(), s.end(), mySort);
}
void test04()
{
set<int> s;
s.insert(5);
s.insert(8);
s.insert(2);
s.insert(4);
s.insert(3);
set<int>::iterator it = s.find(4);
if (it == s.end())
cout << "查找失败!" << endl;
else
cout << "查找成功!" <<*it<< endl;
it = s.lower_bound(1);
if (it == s.end())
cout << "查找失败!" << endl;
else
cout << "查找成功!" << *it << endl;
pair<set<int>::iterator, set<int>::iterator>ret = s.equal_range(1);
cout << *(ret).first << endl;
cout << *(ret).second << endl;
multiset<int> s1;
s1.insert(5);
s1.insert(8);
s1.insert(2);
s1.insert(5);
s1.insert(4);
s1.insert(3);
cout << s1.count(3) << endl;
}
class Student
{
public:
Student(string name, int age)
{
this->age = age;
this->name = name;
}
string name;
int age;
};
struct Myfunc1
{
bool operator()(const Student& a1,const Student& a2) const
{
return a1.age > a2.age;
}
};
void test05()
{
set<Student, Myfunc1> s;
s.insert(Student("aaa", 18));
s.insert(Student("bbb", 19));
s.insert(Student("ccc", 17));
s.insert(Student("ddd", 21));
s.insert(Student("eee", 20));
for (set<Student, Myfunc1>::iterator it = s.begin(); it != s.end(); it++)
{
cout << "姓名:" << (*it).name << " 年龄:" << (*it).age << endl;
}
}
int main()
{
test05();
system("pause");
return 0;
}
1.2 对组
对组(pair)将一对值组合成一个值,这一对值可以具有不同的数据类型,两个值可以分
别用pair的两个公有属性first和second访问。
#define _CRT_SECURE_NO_WARNINGS
#include<iostream>
#include<string>
#include<vector>
using namespace std;
int main()
{
pair<string, int> mpr("aa", 10);
cout << mpr.first << " " << mpr.second << endl;
system("pause");
return 0;
}
1.3 map容器
1.3.1 map/multimap容器基本概念
Map的特性是,所有元素都会根据元素的键值自动排序。Map所有的元素都是pair,同时
拥有实值和键值,pair的第一元素被视为键值,第二元素被视为实值,map不允许两个元
素有相同的键值。
Map和list拥有相同的某些性质,当对它的容器元素进行新增操作或者删除操作时,操
作之前的所有迭代器,在操作完成之后依然有效,当然被删除的那个元素的迭代器必然
是个例外。
Multimap和map的操作类似,唯一区别multimap键值可重复。
Map和multimap都是以红黑树为底层实现机制。
1.3.2 map容器常用API
1.3.2.1 map构造函数
map<T1, T2> mapTT;//map默认构造函数:
map(const map &mp);//拷贝构造函数
1.3.2.2 map赋值操作
map&operator=(const map &mp);//重载等号操作符
swap(mp);//交换两个集合容器
1.3.2.3 map大小操作
size();//返回容器中元素的数目
empty();//判断容器是否为空
1.3.2.4 map插入数据元素操作
map.insert(...); //往容器插入元素,返回pair<iterator,bool>
map<int, string> mapStu;
// 第一种 通过pair的方式插入对象
mapStu.insert(pair<int, string>(3, "小张"));
// 第二种 通过pair的方式插入对象
mapStu.inset(make_pair(-1, "校长"));
// 第三种 通过value_type的方式插入对象
mapStu.insert(map<int, string>::value_type(1, "小李"));
// 第四种 通过数组的方式插入值
mapStu[3] = "小刘";
mapStu[5] = "小王";
1.3.2.5 map删除操作
clear();//删除所有元素
erase(pos);//删除pos迭代器所指的元素,返回下一个元素的迭代器。
erase(beg,end);//删除区间[beg,end)的所有元素 ,返回下一个元素的迭代器。
erase(keyElem);//删除容器中key为keyElem的对组。
1.3.2.6 map查找操作
find(key);//查找键key是否存在,若存在,返回该键的元素的迭代器;/若不存在,返回map.end();
count(keyElem);//返回容器中key为keyElem的对组个数。对map来说,要么是0,要么是1。对multimap来说,值可能大于1。
lower_bound(keyElem);//返回第一个key>=keyElem元素的迭代器。
upper_bound(keyElem);//返回第一个key>keyElem元素的迭代器。
equal_range(keyElem);//返回容器中key与keyElem相等的上下限的两个迭代器。
#define _CRT_SECURE_NO_WARNINGS
#include<iostream>
#include<string>
#include<map>
#include<algorithm>
using namespace std;
void test()
{
map<int, string>::iterator it;
it++;
it--;
}
void myPrint(map<int, string>& t)
{
for (map<int, string>::iterator it = t.begin(); it != t.end(); it++)
{
cout << "Key:" << (*it).first << " Value:" << (*it).second << endl;;
}
}
void test01()
{
map<int, string> m;
m.insert(pair<int, string>(3, "aaa"));
m.insert(make_pair(6, "bbb"));
m.insert(map<int, string>::value_type(2, "ccc"));
m[4] = "ddd";
myPrint(m);
cout << "Size:" << m.size() << endl;
cout << m[100] << endl;
cout << "Size:" << m.size() << endl;
}
struct Myfunc1
{
bool operator()(int v1, int v2) const
{
return v1 > v2;
}
};
void myPrint1(map<int, string, Myfunc1>& t)
{
for (map<int, string, Myfunc1>::iterator it = t.begin(); it != t.end(); it++)
{
cout << "Key:" << (*it).first << " Value:" << (*it).second << endl;;
}
}
void test02()
{
map<int, string,Myfunc1> m;
m.insert(pair<int, string>(3, "aaa"));
m.insert(make_pair(6, "bbb"));
m.insert(map<int, string>::value_type(2, "ccc"));
m[4] = "ddd";
myPrint1(m);
}
void test03()
{
map<int, string> m;
m[1] = "aaa";
m[2] = "bbb";
m[3] = "ccc";
m[4] = "ddd";
m[5] = "eee";
map<int, string>::iterator it = m.find(5);
if (it == m.end())
cout << "查找失败!" << endl;
else
cout << "查找成功!" << (*it).second <<endl;
it = m.lower_bound(0);
if (it == m.end())
cout << "查找失败!" << endl;
else
cout << "查找成功!" << (*it).second << endl;
it = m.upper_bound(6);
if (it == m.end())
cout << "查找失败!" << endl;
else
cout << "查找成功!" << (*it).second << endl;
cout << "--------------------" << endl;
pair<map<int,string>::iterator,map<int,string>::iterator>ret = m.equal_range(5);
if (ret.first == m.end())
cout << "查找失败!" << endl;
else
cout << "查找成功!" << " "<<
"第一个对组元素中的Key:"<<ret.first->first << "第一个对组元素中的Value:" << ret.first->second << endl;
if (ret.second != m.end())
cout << "第二个对组元素中的Key:" << ret.second->first << "第二个对组元素中的Value:" << ret.second->second << endl;
else
cout << "查找失败!" << endl;
}
int main()
{
test03();
system("pause");
return 0;
}
1.3.2.7 multimap案例
#define _CRT_SECURE_NO_WARNINGS
#include<iostream>
#include<string>
#include<vector>
#include<map>
#include<algorithm>
#include<ctime>
using namespace std;
#define SALE_DEPATMENT 1
#define DEVELOP_DEPATMENT 2
#define FINACIAL_DEPATMENT 3
class Student
{
public:
Student(){}
Student(string name,int age,int salary)
{
this->name = name;
this->age = age;
this->salary = salary;
}
public:
string name;
int age;
int salary;
};
void createStudent(vector<Student>& v)
{
string randName = "ABCDE";
for (int i = 0; i < 5; i++)
{
Student s;
s.age = rand() % 20 + 18;
s.salary = rand() % 1000 + 6000;
s.name = "员工";
s.name += randName[i];
v.push_back(s);
}
}
void studentWork(vector<Student>& v, multimap<int, Student>& m)
{
int len = v.size();
for (vector<Student>::iterator it = v.begin(); it != v.end(); it++)
{
int temp = rand() % 3 + 1;
pair<int, Student> tempStu(temp, *it);
m.insert(tempStu);
}
v.erase(v.begin(), v.end());
}
void printStu(multimap<int, Student> &m)
{
for (multimap<int, Student>::iterator it = m.begin(); it != m.end(); it++)
{
switch(it->first)
{
case SALE_DEPATMENT:
cout << "部门:SALE_DEPATMENT(销售)" << endl;
break;
case DEVELOP_DEPATMENT:
cout << "部门:DEVELOP_DEPATMENT(研发)" << endl;
break;
case FINACIAL_DEPATMENT:
cout << "部门:FINACIAL_DEPATMENT(财务)" << endl;
break;
default:
break;
}
cout <<"\t员工姓名:" << it->second.name << " 员工年龄:" << it->second.age << " 员工工资:" << it->second.salary << endl;
}
}
void test()
{
srand((unsigned int)time(NULL));
vector<Student> v;
multimap<int, Student> m;
createStudent(v);
studentWork(v,m);
printStu(m);
}
int main()
{
test();
system("pause");
return 0;
}
1.4 STL中的深浅拷贝
STL容器所提供的都是值,也就是说当我们给容器中插入元素的时候,容器内部实施
了拷贝动作,将我们要插入的元素再另行拷贝一份放入到容器中,而不是将原数据元素
直接放进容器中,也就是说我们提供的元素必须能够被拷贝。因此:
1.拷贝构造要能被调用
2.注意浅拷贝问题
2.函数对象
2.1 基本概念
重载函数调用操作符的类,其对象常称为函数对象(function object),即它们是
行为类似函数的对象,也叫仿函数(functor),其实就是重载“()”操作符,使得类对象可以
像函数那样调用。
注意:
1.函数对象(仿函数)是一个类,不是一个函数。
2.函数对象(仿函数)重载了”() ”操作符使得它可以像函数一样调用。
3.假定某个类有一个重载的operator(),而且重载的operator()要求获取一个参数,
我们就将这个类称为“一元仿函数”(unary functor);相反,如果重载的operator()
要求获取两个参数,就将这个类称为“二元仿函数”(binary functor)
谓词:谓词是指普通函数或重载的operator()返回值是bool类型的函数对象(仿函数)。
如果operator接受一个参数,那么叫做一元谓词,如果接受两个参数,那么叫做二元谓
词,谓词可作为一个判断式。
2.2 函数对象和普通函数的区别
1.函数对象可以有自己的状态,即普通函数是全局的权限是公共的,但是函数对象可
以是私有的有自己的权限
2.普通函数没有类型,函数对象有自己的类型
3.函数对象的执行效率高于普通函数(成员函数自动申请为内联函数)
#define _CRT_SECURE_NO_WARNINGS
#include<iostream>
#include<string>
#include<vector>
#include<functional>
#include<algorithm>
using namespace std;
bool Myfuc(int a1,int a2)
{
return a1 > a2;
}
void test01()
{
vector<int> v;
v.push_back(5);
v.push_back(3);
v.push_back(1);
v.push_back(2);
v.push_back(4);
sort(v.begin(), v.end(), greater<int>());
for (vector<int>::iterator it = v.begin(); it != v.end(); it++)
{
cout << *it << " ";
}
cout << endl;
}
void func()
{
}
struct MyFunc
{
public:
MyFunc()
{
n = 0;
}
void operator()()
{
cout << "hhello" << endl;
}
public:
int n;
};
void test02()
{
plus<int> myPlus;
cout << myPlus(10, 20) << endl;
}
int main()
{
test02();
system("pause");
return 0;
}
2.3 函数对象适配
1.进行空间适配,将二元谓词转换为一元谓词
1.1.1(bind1st和bind2nd)1.进行空间适配第一步,继承binary_function<参数1,参数2,返回值类型>
1.1.2 第二部加上const称为常函数
1.1.3 实现函数体
1.1.4.用bind2nd来绑定函数对象
注:bind1st和bind2nd的区别:bind1st绑定的是第一个参数,bind2nd绑定的是第二个参数
2.1.1 not1和not2:not1针对一元函数对象,not2针对二元函数对象
2.1.2 第一步,继承
2.1.3 3.适配NOT1(针对一元的)(NOT2 针对二元的)
2.普通函数进行适配
2.1 第一步转换为二元参数
2.2 把普通函数变为函数对象,使用ptr_fun()把普通函数转化为函数对象
3.成员函数适配
3.1 mem_fun:如果存储的是对象指针,需要使用mem_fun
3.2 mem_fun_ref:如果存储的是对象,需要使用mem_fun_ref
#define _CRT_SECURE_NO_WARNINGS
#include<iostream>
#include<string>
#include<vector>
#include<functional>
#include<algorithm>
using namespace std;
struct Myfunc:public binary_function<int ,int, void>
{
void operator()(int v1, int v2) const
{
cout << "v1 = " << v1 << endl;
cout << "v2 = " << v2 << endl;
cout << v1 + v2 << endl;
}
};
void test01()
{
vector<int> v;
v.push_back(10);
v.push_back(20);
v.push_back(30);
v.push_back(40);
v.push_back(50);
for_each(v.begin(), v.end(), bind2nd(Myfunc(),100));
}
struct MyNotFunc:public unary_function<int,bool>
{
public:
bool operator()(int v) const
{
return v >= 20;
}
};
void test02()
{
vector<int> v;
v.push_back(10);
v.push_back(20);
v.push_back(30);
v.push_back(40);
v.push_back(50);
vector<int>::iterator it = find_if(v.begin(), v.end(), not1(MyNotFunc()));
if (it == v.end())
cout << "查找失败!" << endl;
else
cout << "查找成功!" << *it << endl;
vector<int> v1;
v1.push_back(20);
v1.push_back(30);
v1.push_back(10);
v1.push_back(50);
v1.push_back(40);
sort(v1.begin(), v1.end(), less<int>());
for_each(v1.begin(), v1.end(), [](int val) {cout << val << endl; });
sort(v1.begin(), v1.end(),not2(less<int>()));
for_each(v1.begin(), v1.end(), [](int val) {cout << val << endl; });
}
void printMyfun(int val,int val2)
{
cout << val + val2 << endl;
}
void test03()
{
vector<int> v1;
v1.push_back(20);
v1.push_back(30);
v1.push_back(10);
v1.push_back(50);
v1.push_back(40);
for_each(v1.begin(), v1.end(), bind2nd(ptr_fun(printMyfun),100));
}
class Maker
{
public:
Maker(string name, int age)
{
this->age = age;
this->name = name;
}
void myPrint()
{
cout << "Name:" << this->name << " Age:" << this->age << endl;
}
int age;
string name;
};
void test04()
{
vector<Maker> v;
v.push_back(Maker("aa", 10));
v.push_back(Maker("bb", 20));
v.push_back(Maker("cc", 30));
for_each(v.begin(), v.end(), mem_fun_ref(&Maker::myPrint));
vector<Maker*> v1;
v1.push_back(new Maker("aa", 10));
v1.push_back(new Maker("bb", 20));
v1.push_back(new Maker("cc", 30));
for_each(v1.begin(), v1.end(), mem_fun(&Maker::myPrint));
}
int main()
{
test04();
system("pause");
return 0;
}
2.4 空间配置器
如果申请的内存大小超过128,那么空间配置器就自动调用一级空间配置器。反之调
用二级空间配置器。
一级空间配置器,STL源码中的一级空间配置器命名为class __malloc_alloc_template ,
就是对malloc,free,realloc等系统分配函数的一层封装。二级空间配置器,由一个内
存池和自由链表配合实现的。