目录
1、STL的基本概念:
2、常用容器:
(1)、string容器
1)、string容器存取字符的操作
2)、string的拼接操作
3)、string查找和替换
4)、字符串比较:
5)、string的字串
6)、string和c-style字符串的转换
(2)、vector容器
1)、vector中size与容量的变化规律
2)、vector构造函数
3)、赋值
4)、vector大小的操作
5)、vector插入和删除操作
6)、巧用swap收缩空间
(3)、deque容器
1)、deque容器的特性
2)、常用的API
(4)、综合案例
(5)、stack容器(栈容器)
1)、stack容器的特性
2)、常用API
(6)、queue容器(队列容器)
1)、queue容器的特性
2)、常用API
(7)、list容器(双向链表)
1)、list容器的特性
(8)、set和multiset容器
1)、set容器的特性
2)、multiset容器的特性
3)、常用API
(9)、对组
1)、对组的特性
(10)、map/multimap容器
1)、常用API
(11)、STL容器的总结:
3、算法:
(1)、仿函数(函数对象)
(2)、谓词
(3)、内建函数对象(由STL提供的函数对象)
4、适配器:
(1)、函数对象作为适配器
(2)、函数指针作为适配器
(3)、成员函数做适配器
(4)、取反适配器、
5、常用算法:
(1)、遍历算法
(2)、transform算法
(3)、find 算法 查找元素
(4)、find_if 算法 条件查找
(5)、adjacent_find 算法
(6)、binary_search 算法 二分查找法
(7)、binary_search二分法查找算法
(8)、count 算法 统计元素出现次数
(9)、count_if算法统计元素出现次数
(10)、排序算法 merge 合并
(11)、sort排序算法
(12)、random_shuffle 洗牌算法
(13)、reverse 算法 反转指定范围的元素
(14)、copy 算法 将容器内指定范围的元素拷贝到另一容器中
(15)、replace 算法 将容器内指定范围的旧元素修改为新元素
(16)、accmulate 算法 计算容器元素累计总和
(17)、fill 算法 向容器中添加元素
(18)、常用集合算法
为了建立数据结构和算法的一套标准,并且降低他们之间的耦合关系,以提升各自的独立性、弹性、交互操作(相互合作性)诞生了STL。
容器:存放数据。
算法:操作数据。
迭代器:算法通过迭代器操作容器。
仿函数:为算法提供策略,如:运算符重载。
适配器:为算法提供接口。
空间配置器:为算法和容器管理内存空间。
算法分为:质变算法和非质变算法。
质变算法:指的是运算过程中会改变区间的元素的内容。例如拷贝替换删除等。
非质变算法:指的是运算过程中不会改变区间元素的内容。例如查找、计数、遍历、查找极值。
iterator(迭代器)模式定义如下:
提供一种方法,使之能够依序寻访某个容器所含的各个元素,而又无需暴露该容器内部表示方式。
常用的一些操作:
构造
string();//创建一个空的字符串 例如: string str;
string(const string& str);//使用一个 string 对象初始化另一个 string 对象
string(const char* s);//使用字符串 s 初始化
string(int n, char c);//使用 n 个字符 c 初始化 v
赋值
string& operator=(const char* s);//char*类型字符串 赋值给当前的字符串
string& operator=(const string &s);//把字符串 s 赋给当前的字符串
string& operator=(char c);//字符赋值给当前的字符串
string& assign(const char *s);//把字符串 s 赋给当前的字符串
string& assign(const char *s, int n);//把字符串 s 的前 n 个字符赋给当前的字符串
string& assign(const string &s);//把字符串 s 赋给当前字符串
string& assign(int n, char c);//用 n 个字符 c 赋给当前字符串
string& assign(const string &s, int start, int n);//将 s 从 start 开始 n 个字符赋值给字符串
例子:
void test02()
{
string str = "hello world";
cout << str[1] << " " << str.at(1) << endl;
}
常用的一些操作:
string 拼接操作
string& operator+=(const string& str);//重载+=操作符
string& operator+=(const char* str);//重载+=操作符
string& operator+=(const char c);//重载+=操作符
string& append(const char *s);//把字符串 s 连接到当前字符串结尾
string& append(const char *s, int n);//把字符串 s 的前 n 个字符连接到当前字符串结尾
string& append(const string &s);//同 operator+=()
string& append(const string &s, int pos, int n);//把字符串 s 中从 pos 开始的 n 个字符连接到当前字符串结尾
string& append(int n, char c);//在当前字符串结尾添加 n 个字符 c
*/
例子:
void test03()
{
string str1("hello");
string str2("world");
str1 += str2; //拼接、追加
cout << str1 << endl;
string str3("hahaxixi");
//从第零位开始的后面四个拼接
str1.append(str3, 0, 4);
cout << str1 << endl;
}
常用操作:
int find(const string& str, int pos = 0) const; //查找 str 第一次出现位置,
从 pos 开始查找
int find(const char* s, int pos = 0) const; //查找 s 第一次出现位置,从 po
s 开始查找
int find(const char* s, int pos, int n) const; //从 pos 位置查找 s 的前 n
个字符第一次位置
int find(const char c, int pos = 0) const; //查找字符 c 第一次出现位置
int rfind(const string& str, int pos = npos) const;//查找 str 最后一次位
置,从 pos 开始查找
int rfind(const char* s, int pos = npos) const;//查找 s 最后一次出现位置,
从 pos 开始查找
int rfind(const char* s, int pos, int n) const;//从 pos 查找 s 的前 n 个字符
最后一次位置
int rfind(const char c, int pos = 0) const; //查找字符 c 最后一次出现位置
string& replace(int pos, int n, const string& str); //替换从 pos 开始 n 个
字符为字符串 str
string& replace(int pos, int n, const char* s); //替换从 pos 开始的 n 个字
符为字符串 s
例子:
void test04()
{
string str1("hello world");
string str2("world");
//在str1中寻找str2的开头
cout << str1.find(str2) << endl;
//在str1中寻找最后一个l
cout << str1.rfind('l') << endl;
}
void test05()
{
string str("cdaberuyabodabcd");
int pos = 0;
while(1)
{ //寻找ab在字符串中的位置并且返回到ret中
int ret = str.find("ab", pos);
if(ret < 0) break;
//替换掉ad位**
str.replace(ret, 2, "**");
pos = ret + 2;
}
cout << str << endl;
}
常用操作
string 比较操作
compare 函数在>时返回 1, <时返回 -1, ==时返回 0。
int compare(const string &s) const;//与字符串 s 比较
int compare(const char *s) const;//与字符串 s 比较
例子:
void test06()
{
string str1("hello");
string str2("hollo");
#if 1
if(str1 > "hollo"){
cout << "str1 大于 str2" << endl;
}
else if(str1 < "hollo"){
cout << "str1 小于 str2" << endl;
}
else{
cout << "str1 等于 str2" << endl;
}
#endif
if(str1.compare(str2) == 0){
cout << "str1 等于 str2" << endl;
}else{
cout << "str1 不等于 str2" << endl;
}
}
/*
string 子串
string substr(int pos = 0, int n = npos) const;//返回由 pos 开始的 n 个字符
组成的字符串
*/
void test07()
{
string str("hello world");
cout << str.substr(2, 5) << endl;
}
*
string 和 c-style 字符串转换
*/
void test09()
{
//char *转string 编译器默认支持
string str = "hello world";
//string 转char *
const char *p = str.c_str();
cout << p << endl;
}
vector容器的优点:
类模板,单端动态数组,vector容器时随机访问迭代器。
动态数组,可以自动改变大小,支持动态增加删除元素以及随机访问元素,提供面向对象的接口
oid test01()
{
vector v;
cout << "v的size = " << v.size() << " 容量 = " << v.capacity() << endl;
for(int i = 0; i < 1000; i++){
v.push_back(i);
cout << "v的size = " << v.size() << " 容量 = " << v.capacity() << endl;
}
}
差不多可以理解为1.5倍
vector 构造函数
vector v; //采用模板实现类实现,默认构造函数
vector(v.begin(), v.end());//将 v(begin(), end())区间中的元素拷贝给本身。
vector(n, elem);//构造函数将 n 个 elem 拷贝给本身。
vector(const vector &vec);//拷贝构造函数。
#include
#include
using namespace std;
void test01()
{
vectorv1(5,10);
//vector容器,存放int型数据,初始化5个元素全部为10。
//利用迭代器来遍历vector容器
vector::iterator it =v1.begin();
//v1.begin()指向容器的开头,v1.end()指向容器的结尾。
for(;it !=v1.end();it++)
{
cout<<*it<<" ";
//it指针取值就是当前的数据。
}
cout<
vector 常用赋值操作
assign(beg, end);//将[beg, end)区间中的数据拷贝赋值给本身。
assign(n, elem);//将 n 个 elem 拷贝赋值给本身。
vector& operator=(const vector &vec);//重载等号操作符
swap(vec);// 将 vec 与本身的元素互换。
#include
#include
using namespace std;
void myprintf(vector&v)
{
vector::iterator it =v.begin();
for(;it != v.end();it++)
{
cout<<*it<<" ";
}
cout<v1;
v1.push_back(10);
v1.push_back(20);
v1.push_back(30);
v1.push_back(40);
myprintf(v1);
vectorv2;
v2=v1;
myprintf(v2);
vectorv3;
v3.assign(5,10);
myprintf(v3);
vectorv4;
v4.assign(v1.begin(),v1.end());
myprintf(v4);
v4.swap(v3);
myprintf(v4);
}
int main(int argc, char *argv[])
{
test01();
return 0;
}
vector 大小操作
size();//返回容器中元素的个数
empty();//判断容器是否为空
resize(int num);//重新指定容器的长度为 num,若容器变长,则以默认值填充新位置。
如果容器变短,则末尾超出容器长度的元素被删除。
resize(int num, elem);//重新指定容器的长度为 num,若容器变长(容量的大小也会发生变化),则以 elem 值填
充新位置。如果容器变短,则末尾超出容器长>度的元素被删除(但容量不会发生变化)。
capacity();//容器的容量
reserve(int len);//容器预留 len 个元素长度,预留位置不初始化,元素不可访问。
#include
#include
using namespace std;
void myprintf(vector&v)
{
vector::iterator it =v.begin();
for(;it != v.end();it++)
{
cout<<*it<<" ";
}
cout<v1;
v1.push_back(10);
v1.push_back(20);
v1.push_back(30);
v1.push_back(40);
myprintf(v1);
if(v1.empty())
{
cout<<"v1为空容器"<v2;
v2.reserve(10);
cout<
insert(const_iterator pos, int count,ele);//迭代器指向位置 pos 插入 count
个元素 ele.
push_back(ele); //尾部插入元素 ele
pop_back();//删除最后一个元素
erase(const_iterator start, const_iterator end);//删除迭代器从 start 到 end之间的元素
erase(const_iterator pos);//删除迭代器指向的元素
clear();//删除容器中所有元素
#include
#include
using namespace std;
void myprintf(vector&v)
{
vector::iterator it =v.begin();
for(;it != v.end();it++)
{
cout<<*it<<" ";
}
cout<v1;
v1.push_back(10);
v1.push_back(20);
v1.push_back(30);
v1.push_back(40);
myprintf(v1);
//pop_back从vector容器后面删除
v1.pop_back();
v1.pop_back();
myprintf(v1);
//三个参数:位置,插入的数量,插入的参数
v1.insert(v1.begin()+1,3,100);
myprintf(v1);
//删除
v1.erase(v1.begin()+1,v1.begin()+4);
myprintf(v1);
v1.clear();
myprintf(v1);
}
int main(int argc, char *argv[])
{
test01();
return 0;
}
void test01()
{
vectorv1(5,100);
v1.reserve(1000);
cout<(v1).swap(v1);
cout<
双端插入和删除的动态数组,采用随机迭代器。没用容量概念,数据由缓冲区管理
1.deque 构造函数
deque deqT;//默认构造形式
deque(beg, end);//构造函数将[beg, end)区间中的元素拷贝给本身。
deque(n, elem);//构造函数将 n 个 elem 拷贝给本身。
deque(const deque &deq);//拷贝构造函数。
2.deque赋值操作
deque 赋值操作
assign(beg, end);//将[beg, end)区间中的数据拷贝赋值给本身。
assign(n, elem);//将 n 个 elem 拷贝赋值给本身。
deque& operator=(const deque &deq); //重载等号操作符
swap(deq);// 将 deq 与本身的元素互换
3.deque大小的操作
deque 大小操作
deque.size();//返回容器中元素的个数
deque.empty();//判断容器是否为空
deque.resize(num);//重新指定容器的长度为 num,若容器变长,则以默认值填充新位
置。 如果容器变短,则末尾超出容器长度的元素被删除。
deque.resize(num, elem); //重新指定容器的长度为 num,若容器变长,则以 elem 值
填充新位置,如果容器变短,则末尾超出容器长度的元素被删除。
4.deque的双端插入与删除
deque 双端插入和删除操作
push_back(elem);//在容器尾部添加一个数据
push_front(elem);//在容器头部插入一个数据
pop_back();//删除容器最后一个数据
pop_front();//删除容器第一个数据
5.deque数据存取
deque 数据存取
at(idx);//返回索引 idx 所指的数据,如果 idx 越界,抛出 out_of_range。
operator[];//返回索引 idx 所指的数据,如果 idx 越界,不抛出异常,直接出错。
front();//返回第一个数据。
back();//返回最后一个数据
6.deque插入操作
deque 插入操作
insert(pos,elem);//在 pos 位置插入一个 elem 元素的拷贝,返回新数据的位置。
insert(pos,n,elem);//在 pos 位置插入 n 个 elem 数据,无返回值。
insert(pos,beg,end);//在 pos 位置插入[beg,end)区间的数据,无返回值。
7.deque的删除操作
deque 删除操作
clear();//移除容器的所有数据
erase(beg,end);//删除[beg,end)区间的数据,返回下一个数据的位置。
erase(pos);//删除 pos 位置的数据,返回下一个数据的位置。
案例:
void printDequeInt(deque &d)
{
deque::iterator it = d.begin();
for(; it != d.end(); it++)
cout << *it << " ";
cout << endl;
}
void test01()
{
deque d1;
//尾部插入
d1.push_back(10);
d1.push_back(20);
d1.push_back(30);
//头部插入
d1.push_front(40);
d1.push_front(50);
printDequeInt(d1);
deque d2;
d2 = d1;
printDequeInt(d2);
cout << "d2的大小为:" << d2.size() << endl;
}
有 5 名选手:选手 ABCDE,10 个评委分别对每一名选手打分,去除最高分,去除评委中最低分,取平均分。
#include
#include
#include
#include
using namespace std;
class person
{
friend void printperson(vector&v);
friend void playgame(vector&v);
private:
string name;
float score;
public:
person(){}
person(string name,float score):name(name),score(score){}
~person(){}
};
//无名选手的初始化名字,并且放入vector容器
void creatperson(vector&v)
{
string tmpname="ABCDE";
for(int i =0;i<5;i++)
{
string name ="选手";
name+=tmpname[i];
v.push_back(person(name,0.0f));
}
}
//十个评委打分放在另一个deque容器中,采用随机数方法初始化
//vector容器五个选手,每个选手有一个deque容器存放分数
#include
void playgame(vector&v)
{
srand(time(NULL));
vector::iterator it =v.begin();
for(;it != v.end();it++)
{
dequed;
for(int i =0;i<10;i++)
{
float score = (float)(rand()%41+60);
d.push_back(score);
}
sort(d.begin(),d.end());
d.pop_front();
d.pop_back();
float sum = accumulate(d.begin(),d.end(),0);
(*it).score = sum/d.size();
}
}
void printperson(vector&v)
{
vector::iterator it = v.begin();
for(;it != v.end();it++){
cout<<(*it).name<<" 的成绩 "<<(*it).score<v;
creatperson(v);
//参加比赛
playgame(v);
//打印选手的成绩
printperson(v);
}
int main(int argc, char *argv[])
{
test01();
return 0;
}
先进后出。永远指向栈顶元素。只能通过栈顶元素访问栈容器。不提供遍历没用迭代器
#include
#include
using namespace std;
void test01()
{
stacks;
s.push(10);
s.push(20);
s.push(30);
s.push(40);
s.push(50);
cout<
先进先出,有俩个口,一个入口,一个出口,没有迭代器不支持遍历
#include
#include
using namespace std;
void test01()
{
queueq;
q.push(10);
q.push(20);
q.push(30);
q.push(40);
q.push(50);
cout<
list容器在物理上非连续,非顺序存储,在逻辑上是连续的,属于线性存储结构。
list含有迭代器,使用双向迭代器。没有容器的概念没有容量的概念
list 构造函数
list lstT;//list 采用采用模板类实现,对象的默认构造形式:
list(beg,end);//构造函数将[beg, end)区间中的元素拷贝给本身。
list(n,elem);//构造函数将 n 个 elem 拷贝给本身。
list(const list &lst);//拷贝构造函数。
list 数据元素插入和删除操作
push_back(elem);//在容器尾部加入一个元素
pop_back();//删除容器中最后一个元素
push_front(elem);//在容器开头插入一个元素
pop_front();//从容器开头移除第一个元素
insert(pos,elem);//在 pos 位置插 elem 元素的拷贝,返回新数据的位置。
insert(pos,n,elem);//在 pos 位置插入 n 个 elem 数据,无返回值。
insert(pos,beg,end);//在 pos 位置插入[beg,end)区间的数据,无返回值。
clear();//移除容器的所有数据千锋教育——用良心做教育 http://www.mobiletrain.org/
erase(beg,end);//删除[beg,end)区间的数据,返回下一个数据的位置。
erase(pos);//删除 pos 位置的数据,返回下一个数据的位置。
remove(elem);//删除容器中所有与 elem 值匹配的元素。
list 大小操作
size();//返回容器中元素的个数
empty();//判断容器是否为空
resize(num);//重新指定容器的长度为 num,
//若容器变长,则以默认值填充新位置。
//如果容器变短,则末尾超出容器长度的元素被删除。
resize(num, elem);//重新指定容器的长度为 num,
//若容器变长,则以 elem 值填充新位置。
//如果容器变短,则末尾超出容器长度的元素被删除。
list 赋值操作
assign(beg, end);//将[beg, end)区间中的数据拷贝赋值给本身。
assign(n, elem);//将 n 个 elem 拷贝赋值给本身。
list& operator=(const list &lst);//重载等号操作符
swap(lst);//将 lst 与本身的元素互换。
list 数据的存取
front();//返回第一个元素。
back();//返回最后一个元素。
3.6.4.6 list 反转排序
reverse();//反转链表,比如 lst 包含 1,3,5 元素,运行此方法后, lst 就包含 5,3,1
元素。
sort(); //list 排序
案例:
#include
#include
using namespace std;
void printListInt(list &l)
{
list::iterator it = l.begin();
for(;it != l.end(); it++)
cout << *it << " ";
cout << endl;
}
void test01()
{
list l1;
l1.push_back(10);
l1.push_back(20);
l1.push_back(30);
l1.push_front(40);
l1.push_front(50);
l1.push_front(60);
cout << "大小为 : " << l1.size() << endl;
printListInt(l1);
list::iterator it = l1.begin();
//list容器不支持+/-运算
it++;
l1.insert(it, 3, 100);
printListInt(l1);
l1.remove(100);
printListInt(l1);
l1.reverse();
printListInt(l1);
//STL提供的sort只支持随机访问迭代器,不支持双向迭代器
//sort(l1.begin(), l1.end());
l1.sort();
printListInt(l1);
}
int main(int argc, char *argv[])
{
test01();
return 0;
}
1.会根据元素的键值自动排序(从小到大),插入数据时会根据键值自动排号顺序,底层用树实现。
2.set的键值和实值是一个值,不允许两个元素有相同的键值,不允许任意修改set元素的值。
迭代器类型为const_iterator
set容器的基本遍历:
#include
#include
#include
using namespace std;
void myprintf(set&s)
{ //set容器存放后自动排序并且不能改变里面的元素,否则破坏顺序
set::const_iterator it =s.begin();
for(;it != s.end();it++)
{
cout<<*it<<" ";
}
cout<s;
s.insert(50);
s.insert(30);
s.insert(20);
s.insert(10);
s.insert(400);
myprintf(s);
}
int main(int argc, char *argv[])
{
test01();
return 0;
}
set容器默认从小到大排序,我们修改他的排序顺序(从大到小):
set容器没有reverse也没有reverse iterator所以用仿函数实现逆向排序的函数功能
#include
#include
#include
using namespace std;
class Mgreater
{
public:
//重载匿名对象仿函数,按照从大到小排序
bool operator()(int a,int b)
{
return a>b;
}
};
void myprintf(set&s)
{ //set容器存放后自动排序并且不能改变里面的元素,否则破坏顺序
set::const_iterator it =s.begin();
for(;it != s.end();it++)
{
cout<<*it<<" ";
}
cout<s;
//这里的Mgreater类会创建匿名对象Mygreater()()重载仿函数
//重载之后的仿函数相当于函数,可以之间接收数据,并且比较大小
s.insert(50);
s.insert(30);
s.insert(20);
s.insert(10);
s.insert(40);
myprintf(s);
}
int main(int argc, char *argv[])
{
test01();
return 0;
}
set容器存放自定义类必须使用仿函数来排序:
自定义数据类型无返自动比较大小。仿函数重载。
#include
#include
#include
using namespace std;
//set容器存放自定义数据类型,必须要重载仿函数,因为无法确认比较哪个参数
class mygreater;
//自定义数据类型
class person
{ friend void print(set&s);
friend class mygreater;
private:
int num;
string name;
float score;
public:
person(){}
person(int num,string name,float score):num(num),name(name),score(score){}
};
//重载仿函数(),传入类具体去比较大小
class mygreater
{
public:
bool operator()(person ob1,person ob2)
{
return ob1.num>ob2.num;
}
};
void print(set&s)
{
set::const_iterator it=s.begin();
//这里的*it代表的是person类而不是成员
for(;it !=s.end();it++ )
{
cout<<(*it).num<<" ";
}
cout<s;
s.insert(person(10,"hh",0.0f));
s.insert(person(50,"ha",0.0f));
s.insert(person(20,"hx",0.0f));
s.insert(person(40,"hd",0.0f));
s.insert(person(30,"hc",0.0f));
print(s);
}
int main(int argc, char *argv[])
{
test01();
return 0;
}
multiset与set的特性与用法基本一致,mutilset允许键值重复。底层的实现也是利用红黑树。
set
和multiset
是 C++ STL 中的关联容器,它们都基于红黑树实现,并提供了一些常用的操作,如插入、删除、查找等。
set
和multiset
的不同之处在于元素的唯一性:
set
:set
容器中的元素是唯一的,即不允许重复元素。当插入一个已存在的元素时,插入操作会被忽略。
multiset
:multiset
容器中的元素允许重复。可以插入多个相同的元素,并且在搜索时可以找到所有相同的元素。这两个容器都支持以下操作:
插入元素:可以使用
insert()
函数将元素插入到容器中。时间复杂度为 O(log n)。删除元素:可以使用
erase()
函数删除指定的元素。时间复杂度为 O(log n)。查找元素:可以使用
find()
函数来查找指定的元素,如果找到则返回元素的迭代器,否则返回容器末尾的迭代器。时间复杂度为 O(log n)。此外,
set
和multiset
还提供了其他一些常用操作,如大小判断、遍历等。需要注意的是,由于
set
和multiset
内部使用红黑树实现,其总体性能较好,但相对于向量容器(vector
)等,它们可能会有更高的内存使用和插入/删除操作的开销。因此,在选择使用set
或multiset
时,需要根据具体需求权衡其优缺点和性能特点。
红黑树的具体实现:
set 构造函数
set st;//set 默认构造函数:
mulitset mst; //multiset 默认构造函数:
set(const set &st);//拷贝构造函数
set 赋值操作
set& operator=(const set &st);//重载等号操作符
swap(st);//交换两个集合容器
set 大小操作
size();//返回容器中元素的数目
empty();//判断容器是否为空
set 插入和删除操作
insert(elem);//在容器中插入元素。
clear();//清除所有元素
erase(pos);//删除 pos 迭代器所指的元素,返回下一个元素的迭代器。
erase(beg, end);//删除区间[beg,end)的所有元素 ,返回下一个元素的迭代器。
erase(elem);//删除容器中值为 elem 的元素。
set 查找操作
find(key);//查找键 key 是否存在,若存在,返回该键的元素的迭代器;若不存在,返回 set.end();
count(key);//查找键 key 的元素个数
lower_bound(keyElem);//返回第一个 key>=keyElem 元素的迭代器。
upper_bound(keyElem);//返回第一个 key>keyElem 元素的迭代器。
equal_range(keyElem);//返回容器中 key 与 keyElem 相等的上下限的两个迭代器
例子:实现set的从大到小排序(只有利用红黑树的容器才可以)
#include
#include
using namespace std;
struct MyGreater
{
bool operator()(int num1, int num2)
{
return num1 > num2;
}
};
void printSetInt( set& s)
{
for (auto it = s.begin(); it != s.end(); ++it) {
cout << *it << " ";
}
cout << endl;
}
void printSetInt(set &s)
{
for(auto it = s.begin();it != s.end(); it++){
cout <<"+ " << *it << " ";
}
cout << endl;
}
void test01()
{
set s1;
s1.insert(30);
s1.insert(50);
s1.insert(10);
s1.insert(20);
s1.insert(40);
printSetInt(s1);
}
int main(int argc, char *argv[])
{
test01();
return 0;
}
案例2:set容器存放自定义数据
class Person;
class LessPerson
{
public:
bool operator()(Person ob1, Person ob2);
};
class Person
{ friend void printSetPerson(set &s);
friend class LessPerson;
private:
int num;
string name;
public:
Person() {}
Person(int num, string name)
{
this->num = num;
this->name = name;
}
/* bool operator<(Person &ob)
{
return this->num < ob.num;
}*/
};
void printSetPerson(set &s)
{
set::const_iterator it = s.begin();
for(; it != s.end(); it ++)
{
//*it --->Person
cout <<(*it).num << " " << (*it).name << endl;
}
}
void test01()
{
set s;
s.insert(Person(105, "lucy"));
s.insert(Person(102, "bob"));
s.insert(Person(103, "white"));
s.insert(Person(104, "eric"));
s.insert(Person(101, "frike"));
printSetPerson(s);
}
int main(int argc, char *argv[])
{
test01();
return 0;
}
bool LessPerson::operator()(Person ob1, Person ob2)
{
return ob1.num < ob2.num;
}
案例3:find、count、lower_bound、upper_bound、equal_range应用
count(计数):
void test05()
{
sets;
s.insert(10);
s.insert(20);
s.insert(30);
s.insert(40);
s.insert(50);
//cout计数在set中只有0和1,因为set中重复元素会被覆盖
int ret=s.count(10);
cout<
find(查找元素的位置返回迭代器)
void test02()
{
sets;
s.insert(10);
s.insert(20);
s.insert(30);
s.insert(40);
s.insert(50);
//find寻找某个值的位置,返回的是迭代器
set::const_iterator ret;
ret = s.find(50);
if(ret != s.end())
{
cout<<*ret<
lower_bound(下限),upper_bound(上限)返回值也是迭代器
void test03()
{
sets;
s.insert(10);
s.insert(20);
s.insert(30);
s.insert(40);
s.insert(50);
set::iterator ret;
ret = s.lower_bound(40);
if(ret != s.end())
{
cout<<"下限为"<<*ret<
equal_range(上下限)由于返回值是俩个所以用对组存放
//以对组的方式存储上下限
void test04()
{
sets;
s.insert(10);
s.insert(20);
s.insert(30);
s.insert(40);
s.insert(50);
//由于C++返回值只有一个,这个返回值是一个下限一个上限,用pair来接收。
pair::iterator,set::iterator> pa;
//pa里面第一个存放的是下限,第二个是上线
pa =s.equal_range(40);
if(pa.first != s.end())
{
cout<<"下限是"<<*(pa.first)<
案例4:multiset使用
void test03()
{
multiset s;
s.insert(10);
s.insert(10);
s.insert(10);
s.insert(10);
s.insert(10);
cout << s.count(10) << endl;
multiset::const_iterator it = s.begin();
for(; it != s.end(); it++)
cout << *it << " ";
cout << endl;
}
对组(pair)将一对值组合成一个值,这一对值可以有不同的数据类型,俩个值可以分别用pair的俩个公有属性first和second访问。
类模板: template struct pair.
//对组,是一个类模板,存放俩种不同的数据类型
void test06()
{
pairp1(10,"bob");
cout<p2=make_pair(10,"bob");
cout<
map 的特性是,所有元素都会根据元素的键值自动排序。 map 所有的元素都是pair,同时拥有实值和键值, pair 的第一元素被视为键值,第二元素被视为实值,map 不允许两个元素有相同的键值,键值不能修改。multimap允许键值重复。
map和multimap容器的迭代器是const_iterator(只读迭代器)
map 构造函数
map mapTT;//map 默认构造函数:
map(const map &mp);//拷贝构造函数
map 赋值操作
map& operator=(const map &mp);//重载等号操作符
swap(mp);//交换两个集合容器
map 大小操作
size();//返回容器中元素的数目
empty();//判断容器是否为空
插入数据元素操作map.
insert(...); //往容器插入元素,返回 pair
案例1:map容器插入与遍历
void test01()
{
map m;
//方式1:
m.insert(pair(10086, "移动"));
//方式2:
m.insert(make_pair(10010, "联通")); ///< 建议使用
//方式3:
m.insert(map::value_type(10000, "电信"));
//方式4:
m[9527] = "华安";
map::const_iterator it = m.begin();
for(;it != m.end(); it++){
cout << "键值: " << (*it).first << " 实值" << (*it).second << endl;
}
}
案例2:map存储私有数据
class Person
{ friend void printMapPerson(map &m);
private:
int num;
string name;
public:
Person() {}
Person(int num, string name)
{
this->num = num;
this->name = name;
}
};
void printMapPerson(map &m)
{
map::const_iterator it = m.begin();
for(;it != m.end(); it++){
//*it
cout <<"学号为:" << (*it).first << " 姓名" << (*it).second.name << endl;
}
}
void test02()
{
map m;
m.insert(make_pair(101, Person(101, "lucy")));
m.insert(make_pair(103, Person(103, "bob")));
m.insert(make_pair(102, Person(102, "white")));
printMapPerson(m);
}
案例:公司今天招聘了 5 个员工, 5 名员工进入公司之后,需要指派员工在那个部门工作人员信息有: 姓名 年龄 电话 工资等组成
通过 Multimap 进行信息的插入 保存 显示分部门显示员工信息 显示全部员工信息
#include
#include
#include
vector容器:单端动态数组 随机访问迭代器 经常用于数据的临时存储。
deque容器:双端动态数组 随机访问迭代器
stack容器: 没有迭代器 先进后出
queue容器: 没有迭代器 先进先出
list容器:双向链表 双向迭代器
set/multiset容器:只有键值 set键值不能重复 自动排序 不能修改内部元素的值 只读迭代器
map/multimap容器:键值--实值 map键值不能重复 成对出现(键值与实值)自动排序 只读迭代器
仿函数就是利用运算符重载(),把实例化的对象作为函数来使用。
class MyPrint
{
public:
void operator()(string str)
{
cout << str << endl;
}
};
void test01()
{
MyPrint ob;
ob("hello world");
//创建匿名对象
MyPrint()("hello world");
}
返回值为bool类型的普通函数或者仿函数(为函数内部提供条件判断)
有一个参数叫一元谓词
有两个参数叫二元谓词
案例1:一元谓词使用
class Greater
{
public:
bool operator()(int val)
{
return val > 20;
}
};
bool my_greater(int val)
{
return val > 30;
}
void test01()
{
vector v;
v.push_back(10);
v.push_back(20);
v.push_back(30);
v.push_back(40);
v.push_back(50);
vector::iterator ret;
// ret = find_if(v.begin(), v.end(), Greater());
ret = find_if(v.begin(), v.end(), my_greater);
if(ret != v.end()){
cout << *ret << endl;
}
}
案例2:二元谓词使用
class MyGreater
{
public:
bool operator()(int v1, int v2)
{
return v1 > v2;
}
案例2:二元谓词使用
class MyGreater
{
public:
bool operator()(int v1, int v2)
{
return v1 > v2;
}
};
bool myGreater(int v1, int v2)
{
return v1 > v2;
}
void test02()
{
vector v;
v.push_back(20);
v.push_back(40);
v.push_back(10);
v.push_back(50);
v.push_back(30);
for_each(v.begin(), v.end(), my_print);
cout << endl;
//排序的默认顺序:小 --- 大
sort(v.begin(), v.end());
for_each(v.begin(), v.end(), my_print);
cout << endl;
// sort(v.begin(), v.end(), MyGreater());
sort(v.begin(), v.end(), myGreater);
for_each(v.begin(), v.end(), my_print);
cout << endl;
}
6 个算数类函数对象,除了 negate 是一元运算,其他都是二元运算
template T plus//加法仿函数
template T minus//减法仿函数
template T multiplies//乘法仿函数
template T divides//除法仿函数
template T modulus//取模仿函数
template T negate//取反仿函数
6 个关系运算类函数对象,每一种都是二元运算
template bool equal_to//等于
template bool not_equal_to//不等于
template bool greater//大于
template bool greater_equal//大于等于
template bool less//小于
template bool less_equal//小于等于
逻辑运算类运算函数,not 为一元运算,其余为二元运算
template bool logical_and//逻辑与
template bool logical_or//逻辑或
template bool logical_not//逻辑非
案例1:利用内建函数对象实现从大到小排序
sort(v.begin(), v.end(), greater
());
下面是简单的greater
template
struct greater {
bool operator()(const T& a, const T& b) const {
return a > b;
}
};
适配器可以将类适配到另一个不兼容的接口
#include
#include
#include
using namespace std;
//1.公共继承binary_function<参数列表(类型,顺序), 返回值类型>
class MyPrint:public binary_function
{
public: //2.用const修饰函数调用运算重载
void operator()(int val, int tmp) const
{
cout << val << " " << tmp << endl;
cout << val + tmp << endl;
}
};
void test01()
{
vector v;
v.push_back(10);
v.push_back(20);
v.push_back(30);
v.push_back(40);
v.push_back(50);
//bin1st与bind2nd进行参数绑定,将参数绑定到函数对象第几个形参上
for_each(v.begin(), v.end(), bind1st(MyPrint(), 100));
}
int main(int argc, char *argv[])
{
test01();
return 0;
}
bind1st : 将参数绑定为函数对象的第一个参数
bind2nd : 将参数绑定为函数对象的第二个参数
for_each(v.begin(), v.end(), bind1st(ptr_fun(myPrint)
void myPrint(int val, int tmp)
{
cout << val << " " << tmp << endl;
cout << val + tmp << endl;
}
//函数指针做适配器,要在函数名前加上ptr_fun
for_each(v.begin(), v.end(), bind1st(ptr_fun(myPrint), 100));
#include
#include
#include
using namespace std;
//1.公共继承binary_function<参数列表(类型,顺序), 返回值类型>
class Data
{
private:
int a;
public:
Data() {}
Data(int a):a(a){}
void showData()
{
cout << a << endl;
}
};
void test02()
{
vector v;
v.push_back(Data(10));
v.push_back(Data(20));
v.push_back(Data(30));
v.push_back(Data(40));
v.push_back(Data(50));
for_each(v.begin(), v.end(), mem_fun_ref(&Data::showData));
}
int main(int argc, char *argv[])
{
test02();
return 0;
}
not1 一元取反
not2 二元取反
用法:not1(表达式),但是一元取反与二元取反的选择需要考虑(表达式的参数)
案例:一元取反与二元取反
void test03()
{
vector v;
v.push_back(10);
v.push_back(20);
v.push_back(30);
v.push_back(40);
v.push_back(50);
vector::iterator ret;
ret = find_if(v.begin(), v.end(), not1(bind2nd(greater(), 30)));
if(ret != v.end()){
cout << "找到结果:" << *ret << endl;
}
//lambda表达式
for_each(v.begin(), v.end(), [](int val){
cout << val << " ";
});
cout << endl;
sort(v.begin(), v.end(), greater());
for_each(v.begin(), v.end(), [](int val){
cout << val << " ";
});
cout << endl;
sort(v.begin(), v.end(), not2(greater()));
for_each(v.begin(), v.end(), [](int val){
cout << val << " ";
});
cout << endl;
}
for_each遍历算法 遍历容器元素
/*
@param beg 开始迭代器
@param end 结束迭代器
@param _callback 函数回调或者函数对象
@return 函数对象
*/
for_each(iterator beg, iterator end, _callback);
int func01(int val)
{
return (val + 100);
}
/*
transform 算法 将指定容器区间元素搬运到另一容器中
注意 : transform 不会给目标容器分配内存,所以需要我们提前分配好内存
@param beg1 源容器开始迭代器
@param end1 源容器结束迭代器
@param beg2 目标容器开始迭代器
@param _cakkback 回调函数或者函数对象
@return 返回目标容器迭代器
transform(iterator beg1, iterator end1, iterator beg2, _callbakc);
*/
void test01()
{
vector v1;
v1.push_back(10);
v1.push_back(20);
v1.push_back(30);
v1.push_back(40);
v1.push_back(50);
vector v2;
v2.resize(v1.size());
transform(v1.begin(), v1.end(), v2.begin(), func01);
for_each(v2.begin(), v2.end(), [](int val){
cout << val << " " ;
});
cout << endl;
}
/*
@param beg 容器开始迭代器
@param end 容器结束迭代器
@param value 查找的元素
@return 返回查找元素的位置
*/
find(iterator beg, iterator end, value)
/*
@param beg 容器开始迭代器
@param end 容器结束迭代器
@param callback 回调函数或者谓词(返回 bool 类型的函数对象)
@return bool 查找返回 true 否则 false
*/
find_if(iterator beg, iterator end, _callback);
/*
adjacent_find 算法 查找相邻重复元素
@param beg 容器开始迭代器
@param end 容器结束迭代器
@param _callback 回调函数或者谓词(返回 bool 类型的函数对象)
@return 返回相邻元素的第一个位置的迭代器
adjacent_find(iterator beg, iterator end, _callback);
*/
void test01()
{
vector v;
v.push_back(10);
v.push_back(20);
v.push_back(20);
v.push_back(30);
v.push_back(30);
vector::iterator ret;
ret = adjacent_find(v.begin(), v.end());
if(ret != v.end())
cout << *ret << endl;
}
注意: 在无序序列中不可用
/*
adjacent_find 算法 查找相邻重复元素
@param beg 容器开始迭代器
@param end 容器结束迭代器
@param _callback 回调函数或者谓词(返回 bool 类型的函数对象)
@return 返回相邻元素的第一个位置的迭代器
*/
adjacent_find(iterator beg, iterator end, _callback);
/*
binary_search 算法 二分查找法
注意: 在无序序列中不可用
@param beg 容器开始迭代器
@param end 容器结束迭代器
@param value 查找的元素
@return bool 查找返回 true 否则 false
*/
void test02()
{
vector v;
v.push_back(10);
v.push_back(20);
v.push_back(30);
v.push_back(40);
bool ret = binary_search(v.begin(), v.end(), 20);
if(ret)
cout << "有" << endl;
else
cout << "没有" << endl;
}
/*
count 算法 统计元素出现次数
@param beg 容器开始迭代器
@param end 容器结束迭代器
@param value 回调函数或者谓词(返回 bool 类型的函数对象)
@return int 返回元素个数
*/
count(iterator beg, iterator end, value);
/*
count_if 算法 统计元素出现次数
@param beg 容器开始迭代器
@param end 容器结束迭代器
@param callback 回调函数或者谓词(返回 bool 类型的函数对象)
@return int 返回元素个数
count_if(iterator beg, iterator end, _callback);
*/
void test03()
{
vector v;
v.push_back(10);
v.push_back(20);
v.push_back(30);
v.push_back(40);
v.push_back(50);
cout << count_if(v.begin(), v.end(), bind2nd(greater(), 20)) << endl;
}
merge 算法 容器元素合并,并存储到另一容器中
注意:两个容器必须是有序的
/*
merge 算法 容器元素合并,并存储到另一容器中
注意:两个容器必须是有序的
@param beg1 容器 1 开始迭代器
@param end1 容器 1 结束迭代器
@param beg2 容器 2 开始迭代器
@param end2 容器 2 结束迭代器
@param dest 目标容器开始迭代器
merge(iterator beg1, iterator end1, iterator beg2, iterator end2, itera
tor dest)*/
void test04()
{
vector v1;
v1.push_back(10);
v1.push_back(20);
v1.push_back(40);
vector v2;
v2.push_back(20);
v2.push_back(30);
v2.push_back(60);
vector v3;
v3.resize(v1.size() + v2.size());
merge(v1.begin(), v1.end(), v2.begin(), v2.end(), v3.begin());
for_each(v3.begin(), v3.end(), [](int val){
cout << val << " ";
});
cout << endl;
}
/*
sort 算法 容器元素排序
@param beg 容器 1 开始迭代器
@param end 容器 1 结束迭代器
@param _callback 回调函数或者谓词(返回 bool 类型的函数对象)
*/
sort(iterator beg, iterator end, _callback)
打乱容器内元素的顺序
/*
random_shuffle 算法 对指定范围内的元素随机调整次序
@param beg 容器开始迭代器
@param end 容器结束迭代器
random_shuffle(iterator beg, iterator end)
*/
#include
void test05()
{
srand(time(NULL));
vector v;
v.push_back(10);
v.push_back(20);
v.push_back(30);
v.push_back(40);
random_shuffle(v.begin(), v.end());
for_each(v.begin(), v.end(), [](int val){
cout << val << " ";
});
cout << endl;
}
/*
reverse 算法 反转指定范围的元素
@param beg 容器开始迭代器
@param end 容器结束迭代器
*/
reverse(iterator beg, iterator end)
/*
@param beg 容器开始迭代器
@param end 容器结束迭代器
@param dest 目标起始迭代器
*/
copy(iterator beg, iterator end, iterator dest)
void test06()
{
vector v1;
v1.push_back(10);
v1.push_back(20);
v1.push_back(30);
v1.push_back(40);
v1.push_back(50);
vector v2;
v2.resize(v1.size());
copy(v1.begin(), v1.end(), v2.begin());
for_each(v2.begin(), v2.end(), [](int val){
cout << val << " ";
});
cout << endl;
copy(v2.begin(), v2.end(), ostream_iterator(cout, " "));
cout << endl;
}
/*
replace 算法 将容器内指定范围的旧元素修改为新元素
@param beg 容器开始迭代器
@param end 容器结束迭代器
@param oldvalue 旧元素
@param oldvalue 新元素
*/
replace(iterator beg, iterator end, oldvalue, newvalue);
/*
replace_if 算法 将容器内指定范围满足条件的元素替换为新元素
@param beg 容器开始迭代器
@param end 容器结束迭代器
@param callback 函数回调或者谓词(返回 Bool 类型的函数对象)
@param oldvalue 新元素
*/
replace_if(iterator beg, iterator end, _callback, newvalue)
void test07()
{
vector v1;
v1.push_back(10);
v1.push_back(20);
v1.push_back(30);
v1.push_back(40);
v1.push_back(50);
replace_if(v1.begin(), v1.end(), bind2nd(greater(), 30), 60);
copy(v1.begin(), v1.end(), ostream_iterator(cout, " "));
cout << endl;
}
/*
accumulate 算法 计算容器元素累计总和
@param beg 容器开始迭代器
@param end 容器结束迭代器
@param value 累加值
*/
accumulate(iterator beg, iterator end, value)
初始化容器时以value填充容器元素值
/*
@param beg 容器开始迭代器
@param end 容器结束迭代器
@param value t 填充元素
*/
fill(iterator beg, iterator end, value)
/*
set_intersection 算法 求两个 set 集合的交集
注意:两个集合必须是有序序列
@param beg1 容器 1 开始迭代器
@param end1 容器 1 结束迭代器
@param beg2 容器 2 开始迭代器
@param end2 容器 2 结束迭代器
@param dest 目标容器开始迭代器
@return 目标容器的最后一个元素的迭代器地址
*/
set_intersection(iterator beg1, iterator end1, iterator beg2, iterator
end2, iterator dest)
/*
set_union 算法 求两个 set 集合的并集
注意:两个集合必须是有序序列
@param beg1 容器 1 开始迭代器
@param end1 容器 1 结束迭代器
@param beg2 容器 2 开始迭代器
@param end2 容器 2 结束迭代器
@param dest 目标容器开始迭代器
@return 目标容器的最后一个元素的迭代器地址
*/
set_union(iterator beg1, iterator end1, iterator beg2, iterator end2, i
terator dest)
/*
set_difference 算法 求两个 set 集合的差集
注意:两个集合必须是有序序列
@param beg1 容器 1 开始迭代器
@param end1 容器 1 结束迭代器
@param beg2 容器 2 开始迭代器
@param end2 容器 2 结束迭代器
@param dest 目标容器开始迭代器
@return 目标容器的最后一个元素的迭代器地址
*/
set_difference(iterator beg1, iterator end1, iterator beg2, iterator en
d2, iterator dest)
注意:操作后的结果也是放到容器中,此时我们需要考虑目标容器的大小。