可复用利用的东西!
面向对象和泛型编程(模板)的 目的->提升复用性
为了建立数据结构和算法的一套标准->STL横空出世
序列式排序:强调值的排序,序列式容器中的每个元素均有固定的位置。
关联式排序:二叉树结构,各元素之间没有严格的物理的顺序关系。
提供一种方法,使之间能够依次序访问某个容器所含的各个元素,而又无需暴露该容器的内部表示方式。每个容器都有自己专属的迭代器。类似于指针,可简单理解为指针。
迭代器种类:
种类 | 功能 | 支持运算 |
---|---|---|
输入迭代器 | 对数据的只读访问 | 只读,支持++、==、!= |
输出迭代器 | 对数据的只写访问 | 只写,支持++ |
前向迭代器 | 读写操作,并能向前推进迭代器 | 读写,支持++、==、!= |
双向迭代器 | 读写操作,并能向前和向后操作 | 读写,支持++、--, |
随机访问迭代器 | 读写操作,可以以跳跃的方式访问任意数据,功能最强的迭代器 | 读写,支持++、--、[n]、-n、<、<=、>、>= |
常用的容器中迭代器种类为双向迭代器,和随机访问迭代器
创建、插入、遍历
案例代码:
//.h
#pragma once
#include "iostream"
#include"vector"
#include "algorithm"
class STL_Vector
{
public:
void test_exp();
};
//.cpp
#include "STL_Vector.h"
using namespace std;
void func(int val)
{
cout << val << endl;
}
void STL_Vector::test_exp()
{
//创建
vector v;
//添加
v.push_back(1);
v.push_back(2);
v.push_back(3);
v.push_back(4);
v.push_back(5);
v.push_back(6);
//遍历
vector::iterator it_begin = v.begin();
vector::iterator it_end = v.end();
//方式一
while (it_begin != it_end)
{
cout << *it_begin << endl;
it_begin++;
}
//方式二
for (vector::iterator it = v.begin(); it != v.end(); it++)
{
cout << *it << endl;
}
//方式三
for_each(v.begin(), v.end(), func);
}
//mian
#include "iostream"
using namespace std;
#include "STL_Vector.h"
int main()
{
STL_Vector sv = STL_Vector();
sv.test_exp();
system("pause");
return 0;
}
运行结果:
代码示例:
//.h
#pragma once
#include "iostream"
#include"vector"
#include "algorithm"
class STL_Vector
{
public:
void test_exp();
};
//.cpp
#include "STL_Vector.h"
using namespace std;
class Animal
{
public:
Animal(int age,string name)
{
m_age = age;
m_name = name;
}
public:
int m_age;
string m_name;
};
void func(int val)
{
cout << val;
}
void STL_Vector::test_exp()
{
//创建
vectorv_p;
vectorv_point;
//添加
Animal a1(12,"僧面侯");
Animal a2(12, "熊猫");
Animal a3(12, "考拉");
Animal a4(12, "袋鼠");
v_p.push_back(a1);
v_p.push_back(a2);
v_p.push_back(a3);
v_p.push_back(a3);
v_point.push_back(&a1);
v_point.push_back(&a2);
v_point.push_back(&a3);
v_point.push_back(&a4);
//遍历
for (vector::iterator it = v_p.begin(); it != v_p.end(); it++)
{
cout << "年龄:" << it->m_age << "姓名:" << (*it).m_name << endl;
}
for (vector::iterator it = v_point.begin(); it != v_point.end(); it++)
{
cout << "年龄:" << (*it)->m_age << "姓名:" << (*it)->m_name << endl;
}
}
//main
#include "iostream"
using namespace std;
#include "STL_Vector.h"
int main()
{
STL_Vector sv = STL_Vector();
sv.test_exp();
system("pause");
return 0;
}
运行结果:
代码示例:
//.h
#pragma once
#include "iostream"
#include"vector"
#include "algorithm"
class STL_Vector
{
public:
void test_exp();
};
//.cpp
#include "STL_Vector.h"
using namespace std;
class Animal
{
public:
Animal(int age,string name)
{
m_age = age;
m_name = name;
}
public:
int m_age;
string m_name;
};
void func(int val)
{
cout << val;
}
void STL_Vector::test_exp()
{
//创建
vector> v_nest;
vector v_nest1;
vector v_nest2;
vector v_nest3;
vector v_nest4;
//添加
for (int i = 0; i < 5; i++)
{
if (i % 2 == 0)
{
v_nest1.push_back("我里个豆");
v_nest2.push_back("我里个豆");
v_nest3.push_back("我里个豆");
v_nest4.push_back("我里个豆");
}
else
{
v_nest1.push_back("我里个乖");
v_nest2.push_back("我里个乖");
v_nest3.push_back("我里个乖");
v_nest4.push_back("我里个乖");
}
}
v_nest.push_back(v_nest1);
v_nest.push_back(v_nest2);
v_nest.push_back(v_nest3);
v_nest.push_back(v_nest4);
//遍历
for (vector>::iterator it = v_nest.begin(); it != v_nest.end(); it++)
{
for (vector::iterator itt = (*it).begin(); itt != (*it).end(); itt++)
{
cout << (*itt) ;
}
cout << endl;
}
}
//mian
#include "iostream"
using namespace std;
#include "STL_Vector.h"
int main()
{
STL_Vector sv = STL_Vector();
sv.test_exp();
system("pause");
return 0;
}
本质:string是C++风格的字符串,string是一个类。
char *是一个指针,是C风格的字符串
string是一个类,封装了char*,管理和维护char*的容器
代码示例:
//.h
#pragma once
#include "iostream"
using namespace std;
class string_
{
public:
void test();
};
//.cpp
#include "string_.h"
#include "string"
void string_::test()
{
//
string str1;
string str2 = "无语";
string str3 = string(str2);
string str4 = string(4, 'c');
cout << "str1:" << str1 << endl;
cout << "str2:" << str2 << endl;
cout << "str3:" << str3 << endl;
cout << "str4:" << str4 << endl;
}
int main()
{
string_ t;
t.test();
system("pause");
return 0;
}
运行结果:
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赋给当前字符串
代码示例:
//.h
#pragma once
#include "iostream"
using namespace std;
class string_
{
public:
void test01();
};
//.cpp
#include "string_.h"
#include "string"
using namespace std;
//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赋给当前字符串
void string_::test01()
{
string str1 = "无语考拉";
string str2 = str1;
string str3;
str3 = 'a';
string str4;
str4.assign("无语拉拉");
string str5;
str5.assign(str4);
string str6;
str6.assign(4, 'c');
cout << "str1 = " << str1 << endl;
cout << "str2 = " << str2 << endl;
cout << "str3 = " << str3 << endl;
cout << "str4 = " << str4 << endl;
cout << "str5 = " << str5 << endl;
cout << "str6 = " << str6 << endl;
}
int main()
{
string_ t;
t.test01();
system("pause");
return 0;
}
运行结果:
string& operator+=(const char* str);
//重载+=操作符
string& operator+=(const char c);
//重载+=操作符
string& operator+=(const string& str);
//重载+=操作符
string& append(const char *s);
//把字符串s连接到当前字符串结尾
string& append(const char *s, int n);
//把字符串s的前n个字符连接到当前字符串结尾
string& append(const string &s);
//同operator+=(const string& str)
string& append(const string &s, int pos, int n);
//字符串s中从pos开始的n个字符连接到字符串结尾
代码示例:
//.h
#pragma once
#include "iostream"
using namespace std;
class string_
{
public:
void test02();
};
//.cpp
#include "string_.h"
#include "string"
using namespace std;
//*`string& operator+=(const char* str); ` //重载+=操作符
//* `string& operator+=(const char c); ` //重载+=操作符
//* `string& operator+=(const string& str); ` //重载+=操作符
//* `string& append(const char* s); ` //把字符串s连接到当前字符串结尾
//* `string& append(const char* s, int n); ` //把字符串s的前n个字符连接到当前字符串结尾
//* `string& append(const string& s); ` //同operator+=(const string& str)
//* `string& append(const string& s, int pos, int n); `/ / 字符串s中从pos开始的n个字符连接到字符串结尾
void string_::test02()
{
string str1 = "WC!";
string str2;
str2 += str1;
string str3;
str3 += str2;
str3 += 'm';
string str4;
str4 += str2;
str4 += "md";
string str5;
str5.append(str2);
string str6;
str6.append(str1, 2);
str6.append(str2, 0, 2);
cout << "str1 = " << str1 << endl;
cout << "str2 = " << str2 << endl;
cout << "str3 = " << str3 << endl;
cout << "str4 = " << str4 << endl;
cout << "str5 = " << str5 << endl;
cout << "str6 = " << str6 << endl;
}
int main()
{
string_ t;
t.test02();
system("pause");
return 0;
}
运行结果:
int find(const string& str, int pos = 0) const;
//查找str第一次出现位置,从pos开始查找
int find(const char* s, int pos = 0) const;
//查找s第一次出现位置,从pos开始查找
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
总结:
find查找是从左往后,rfind从右往左
find找到字符串后返回查找的第一个字符位置,找不到返回-1
replace在替换时,要指定从哪个位置起,多少个字符,替换成什么样的字符串(全换进去)
字符串比较是按字符的ASCII码进行对比
= 返回 0
> 返回 1
< 返回 -1
函数原型:
int compare(const string &s) const;
//与字符串s比较
int compare(const char *s) const;
//与字符串s比较
string& insert(int pos, const char* s);
//插入字符串
string& insert(int pos, const string& str);
//插入字符串
string& insert(int pos, int n, char c);
//在指定位置插入n个字符c
string& erase(int pos, int n = npos);
//删除从Pos开始的n个字符
插入和删除的起始坐标0开始!
函数原型:
string substr(int pos = 0, int n = npos) const;
//返回由pos开始的n个字符组成的字符串
代码示例:
void string_::test04()
{
string str = "sefgsfsdfdsfg";
string substr = str.substr(1, 5);
cout << "substr:" << substr<
运行结果:
string中单个字符存取方式有两种
char& operator[](int n);
//通过[]方式取字符
char& at(int n);
//通过at方法获取字符
代码示例:
void string_::test03()
{
string str = "卧槽了,我去!";
str[2] = 'a';
for (int i = 0; i < str.size(); i++)
{
cout << str[i] ;
}
cout << endl;
str.at(2) = 'a';
for (int i = 0; i < str.size(); i++)
{
cout << str.at(i);
}
}
string字符串中单个字符存取有两种方式,利用 [ ] 或 at
又称单端数组
与数组的最大区别,数组静态的,vector可动态申请空间,采用的方式是动态扩展
即复制原数据到新开辟空间的上,并释放原空间
常用函数及迭代器:
vector容器是支持随机访问的迭代器
vector
//采用模板实现类实现,默认构造函数
vector(v.begin(), v.end());
//将v[begin(), end())前闭后开区间中的元素拷贝给本身。
vector(n, elem);
//构造函数将n个elem拷贝给本身。
vector(const vector &vec);
//拷贝构造函数。
vector& operator=(const vector &vec);
//重载等号操作符
assign(beg, end);
//将[beg, end)区间中的数据拷贝赋值给本身。
assign(n, elem);
//将n个elem拷贝赋值给本身。
empty();
//判断容器是否为空,空返回为true,否则为false
capacity();
//容器的容量capacity >= size;
size();
//返回容器中元素的个数
resize(int num);
//重新指定容器的长度为num,若容器变长,则以默认值(0)填充新位置。
//如果容器变短,则末尾超出容器长度的元素被删除。
resize(int num, elem);
//重新指定容器的长度为num,若容器变长,则以elem值填充新位置。
//如果容器变短,则末尾超出容器长度的元素被删除
push_back(ele);
//尾部插入元素ele
pop_back();
//删除最后一个元素
insert(const_iterator pos, ele);
//迭代器指向位置pos插入元素ele
insert(const_iterator pos, int count,ele);
//迭代器指向位置pos插入count个元素ele
erase(const_iterator pos);
//删除迭代器指向的元素
erase(const_iterator start, const_iterator end);
//删除迭代器从start到end之间的元素
clear();
//删除容器中所有元素
at(int idx);
//返回索引idx所指的数据
operator[];
//返回索引idx所指的数据
front();
//返回容器中第一个数据元素
back();
//返回容器中最后一个数据元素
注意:是迭代器参数!
功能描述:
实现两个容器内元素进行互换
函数原型:
swap(vec);
// 将vec与本身的元素互换
实际用途:收缩内存空间
v.swap(v);
v的申请空间很大,但实际用的很少,内存浪费!于是vector
vector
功能描述:
减少vector在动态扩展容量时的扩展次数
函数原型:
reserve(int len);
//容器预留len个元素长度,预留位置不初始化,元素不可访问。
功能:
双端数组,可以对头端进行插入删除操作
deque与vector区别:
vector对于头部的插入删除效率低,数据量越大,效率越低
deque相对而言,对头部的插入删除速度回比vector快
vector访问元素时的速度会比deque快,这和两者内部实现有关
常用迭代器和函数:
deque内部工作原理:
deque内部有个中控器,维护每段缓冲区中的内容,缓冲区中存放真实数据
中控器维护的是每个缓冲区的地址,使得使用deque时像一片连续的内存空间
deque容器的迭代器也是支持随机访问的。
deque
deqT; //默认构造形式
deque(beg, end);
//构造函数将[beg, end)区间中的元素拷贝给本身。
deque(n, elem);
//构造函数将n个elem拷贝给本身。
deque(const deque &deq);
//拷贝构造函数
注意:
//参数是const只读模式,则迭代器也应该变为只读迭代器
void printDeque(const deque
& d)
{
for (deque::const_iterator it = d.begin(); it != d.end(); it++) {
cout << *it << " ";}
cout << endl;
}
deque& operator=(const deque &deq);
//重载等号操作符
assign(beg, end);
//将[beg, end)区间中的数据拷贝赋值给本身。
assign(n, elem);
//将n个elem拷贝赋值给本身。
deque.empty();
//判断容器是否为空
deque.size();
//返回容器中元素的个数
deque.resize(num);
//重新指定容器的长度为num,若容器变长,则以默认值(0)填充新位置。
//如果容器变短,则末尾超出容器长度的元素被删除。
deque.resize(num, elem);
//重新指定容器的长度为num,若容器变长,则以elem值填充新位置。
//如果容器变短,则末尾超出容器长度的元素被删除。
注意:
deque没有capacity属性!
push_back(elem);
//在容器尾部添加一个数据
push_front(elem);
//在容器头部插入一个数据
pop_back();
//删除容器最后一个数据
pop_front();
//删除容器第一个数据
指定位置操作:
pos是迭代器位置
insert(pos,elem);
//在pos位置插入一个elem元素的拷贝,返回新数据的位置。
insert(pos,n,elem);
//在pos位置插入n个elem数据,无返回值。
insert(pos,v.beg,v.end);
//在pos位置插入迭代器[beg,end)区间的数据,无返回值。
clear();
//清空容器的所有数据
erase(beg,end);
//删除迭代器[beg,end)区间的数据,返回下一个数据的位置。
erase(pos);
//删除pos位置的数据,返回下一个数据的位置。
at(int idx);
//返回索引idx所指的数据
operator[];
//返回索引idx所指的数据
front();
//返回容器中第一个数据元素
back();
//返回容器中最后一个数据元素
sort(iterator beg, iterator end)
//对beg和end区间内元素进行排序
注意:#include ”algorithm“;
有5名选手,10个评委分别对每一名选手打分,去除最高分,去除评委中最低分,取平均分。
代码示例:
//.h
#pragma once
#include "vector"
#include "deque"
#include "string"
using namespace std;
class player
{
public:
string m_name;
deque m_scores;
};
class Exa_evaluate_score
{
public:
Exa_evaluate_score();
void eval(int index);
void summarizing(int index);
public:
vector m_p;
};
//.cpp
#include "Exa_evaluate_score.h"
#include "string"
#include "deque"
#include
#include "algorithm"
using namespace std;
Exa_evaluate_score::Exa_evaluate_score()
{
m_p.resize(10);
}
void Exa_evaluate_score::eval(int index)
{
cout << "请输入第" << index+1 << "位选手得分:" << endl;
cout << "输入姓名:" ;
string name;
getline(cin, name);
m_p[index].m_name= name;
for (int j = 0; j < 10; j++)
{
cout << "第" << j + 1 << "位评委请对" << index+1 << "位选手打分:" << endl;
float temp_score;
cin >> temp_score;
m_p[index].m_scores.push_back(temp_score);
}
}
void Exa_evaluate_score::summarizing(int index)
{
sort(m_p[index].m_scores.begin(), m_p[index].m_scores.end());
cout << "最低分为:" << m_p[index].m_scores.front() << endl;
cout << "最高分为:" << m_p[index].m_scores.back() << endl;
m_p[index].m_scores.pop_back();
m_p[index].m_scores.pop_front();
float sum = 0;
for (deque::iterator it = m_p[index].m_scores.begin(); it != m_p[index].m_scores.end(); it++)
{
sum += *it;
}
cout << "去除最低分最高分后平均分为:" <<(float)sum / m_p[index].m_scores.size() << endl;
}
int main()
{
Exa_evaluate_score e;
for (int i = 0; i < 2; i++)
{
e.eval(i);
e.summarizing(i);
}
system("pause");
return 0;
}
运行结果:
FILO(First In Last Out)
stack
//stack采用模板类实现, stack对象的默认构造形式
stack(const stack &stk);
//拷贝构造函数
stack& operator=(const stack &stk);
//重载等号操作符
push(elem);
//向栈顶添加元素
pop();
//从栈顶移除第一个元素
top();
//返回栈顶元素
empty();
//判断堆栈是否为空
size();
//返回栈的大小
FIFO(First In First Out)
常用函数:尾入头出
queue
//queue采用模板类实现,queue对象的默认构造形式
queue(const queue &que);
//拷贝构造函数
queue& operator=(const queue &que);
//重载等号操作符
push(elem);
//往队尾添加元素
pop();
//从队头移除第一个元素
back();
//返回最后一个元素
front();
//返回第一个元素
empty();
//判断堆栈是否为空
size();
//返回栈的大小
双向循环链表:list容器的迭代器是双向迭代器,不支持随机访问!
由于链表的存储方式并不是连续的内存空间,因此链表list中的迭代器只支持前移和后移,属于双向迭代器
list的优点:
采用动态存储分配,不会造成内存浪费和溢出
链表执行插入和删除操作十分方便,修改指针即可,不需要移动大量元素
list的缺点:
链表灵活,但是空间(指针域) 和 时间(遍历)额外耗费较大
STL中List和vector是两个最常被使用的容器,各有优缺点
list
//list采用采用模板类实现,对象的默认构造形式:
list(beg,end);
//构造函数将[beg, end)区间中的元素拷贝给本身。
list(n,elem);
//构造函数将n个elem拷贝给本身。
list(const list &lst);
//拷贝构造函数。
assign(beg, end);
//将迭代器[beg, end)区间中的数据拷贝赋值给本身。
assign(n, elem);
//将n个elem拷贝赋值给本身。
list& operator=(const list &lst);
//重载等号操作符
swap(lst);
//将lst与本身的元素互换。
注:不要求两个交换的list的数据个数相同!
size();
//返回容器中元素的个数
empty();
//判断容器是否为空
resize(num);
//重新指定容器的长度为num,若容器变长,则以默认值填充新位置。
//如果容器变短,则末尾超出容器长度的元素被删除。
resize(num, elem);
//重新指定容器的长度为num,若容器变长,则以elem值填充新位置。
//如果容器变短,则末尾超出容器长度的元素被删除。
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();//移除容器的所有数据
erase(beg,end);//删除[beg,end)区间的数据,返回下一个数据的位置。
erase(pos);//删除pos位置的数据,返回下一个数据的位置。
remove(elem);//删除容器中所有与elem值匹配的元素。
list不支持随机访问,即无 [] ,at等随机访问的方法;
front();
//返回第一个元素。
back();
//返回最后一个元素。
reverse();
//反转链表
sort();
//链表排序 参数为一个回调函数,其中声明了排序次序即可更改默认 次序(从小到大)的次序。
L.sort(myCompare); //指定规则,从大到小
bool myCompare(int val1 , int val2)
{
return val1 > val2;
}
案例描述:将NuiMa自定义数据类型进行排序,NuiMa中属性有姓名、身份排名、薪资水平
排序规则:按照身份排名进行升序,如果身份排名相同按照薪资水平进行升序
代码示例:
//.h
#pragma once
#include "string"
#include "list"
using namespace std;
//牛马类
class NiuMa
{
public:
NiuMa(string name,int salary,int status)
{
m_name = name;
m_status = status;
m_salary = salary;
};
public:
string m_name;
int m_salary;
int m_status;
};
class list_sort_niuma
{
public:
list m_NM;
};
//.cpp
#include "list_sort_niuma.h"
#include "iostream"
bool sort_relu(NiuMa &nm1 , NiuMa &nm2)
{
if (nm1.m_status == nm2.m_status)
{
return nm1.m_salary > nm2.m_salary;
}
return nm1.m_status < nm2.m_status;
}
int main()
{
NiuMa nm1("小牛马1",5,1);
NiuMa nm2("小牛马2", 50, 2);
NiuMa nm3("小牛马3", 50, 2);
NiuMa nm4("小牛马4", 500, 3);
NiuMa nm5("小牛马5", 500, 1);
NiuMa nm6("小牛马6", 5000, 1);
list_sort_niuma lsn;
lsn.m_NM.push_back(nm1);
lsn.m_NM.push_back(nm2);
lsn.m_NM.push_back(nm3);
lsn.m_NM.push_back(nm4);
lsn.m_NM.push_back(nm5);
lsn.m_NM.push_back(nm6);
cout << "排序前:" << endl;
for (list::iterator it = lsn.m_NM.begin(); it != lsn.m_NM.end(); it++)
{
cout << "姓名: " << it->m_name << " 社会地位排名: " << it->m_status
<< " 薪资水平: " << it->m_salary << endl;
}
lsn.m_NM.sort(sort_relu);
cout << "排序后:" << endl;
for (list::iterator it = lsn.m_NM.begin(); it != lsn.m_NM.end(); it++)
{
cout << "姓名: " << it->m_name << " 社会地位排名: " << it->m_status
<< " 薪资水平: " << it->m_salary << endl;
}
system("pause");
return 0;
}
运行结果:
简介所有的元素会被插入后自动进行排序
本质:关联式容器,底层二叉树实现
set与multiset区别:
注:两个包含头文件,只需包含set即可,即#include ”set“;
set
//默认构造函数:
set(const set &st);
//拷贝构造函数
set& operator=(const set &st);
//重载等号操作符
size();
//返回容器中元素的数目
empty();
//判断容器是否为空
swap(st);
//交换两个集合容器
insert(elem);
//在容器中插入元素。
clear();
//清除所有元素
erase(pos);
//删除pos迭代器所指的元素,返回下一个元素的迭代器。
erase(beg, end);
//删除区间[beg,end)的所有元素 ,返回下一个元素的迭代器。
erase(elem);
//删除容器中值为elem的元素。
find(key);
//查找key是否存在,若存在,返回该键的元素的迭代器;若不存在,返回set.end();
count(key);
//统计key的元素个数
set不可以插入重复数据,而multiset可以
set插入数据的同时会返回插入结果,表示插入是否成功
multiset不会检测数据,因此可以插入重复数据
成对出现的数据,利用对组可返回两个数据
对组创建方式:
pair
pair
代码示例:
pair
p(string("Tom"), 20); pair
p2 = make_pair("Jerry", 10);
主要技术点:
利用仿函数,可以改变排序规则
注意:一定在插入之前就利用仿函数进行指定排序顺序
代码示例:
#include "set"
class MyCompare
{
public:
bool operator()(int v1, int v2) {
return v1 > v2;
}
};
void test01()
{
set s1;
s1.insert(10);
s1.insert(40);
s1.insert(20);
s1.insert(30);
s1.insert(50);
//默认从小到大
for (set::iterator it = s1.begin(); it != s1.end(); it++) {
cout << *it << " ";
}
cout << endl;
//指定排序规则
set s2;
s2.insert(10);
s2.insert(40);
s2.insert(20);
s2.insert(30);
s2.insert(50);
for (set::iterator it = s2.begin(); it != s2.end(); it++) {
cout << *it << " ";
}
cout << endl;
}
int main() {
test01();
system("pause");
return 0;
}
对于自定义数据类型,set必须指定排序规则才可以插入数据
代码示例:
#include
#include
class Person
{
public:
Person(string name, int age)
{
this->m_Name = name;
this->m_Age = age;
}
string m_Name;
int m_Age;
};
class comparePerson
{
public:
bool operator()(const Person& p1, const Person &p2)
{
//按照年龄进行排序 降序
return p1.m_Age > p2.m_Age;
}
};
void test01()
{
set s;
Person p1("刘备", 23);
Person p2("关羽", 27);
Person p3("张飞", 25);
Person p4("赵云", 21);
s.insert(p1);
s.insert(p2);
s.insert(p3);
s.insert(p4);
for (set::iterator it = s.begin(); it != s.end(); it++)
{
cout << "姓名: " << it->m_Name << " 年龄: " << it->m_Age << endl;
}
}
int main() {
test01();
system("pause");
return 0;
}
简介:
本质:
map/multimap属于关联式容器,底层结构是用二叉树实现
优点:
可以根据key值快速找到value值
map和multimap区别:
map不允许容器中有重复key值元素
multimap允许容器中有重复key值元素
map
//map默认构造函数:
map(const map &mp);
//拷贝构造函数
map& operator=(const map &mp);
//重载等号操作符
void test01()
{
mapm; //默认构造
m.insert(pair(1, 10));
m.insert(pair(2, 20));
m.insert(pair(3, 30));
printMap(m);
mapm2(m); //拷贝构造
printMap(m2);
mapm3;
m3 = m2; //赋值
printMap(m3);
}
size();
//返回容器中元素的数目
empty();
//判断容器是否为空
swap(st);
//交换两个集合容器
insert(elem);
//在容器中插入元素。
clear();
//清除所有元素
erase(pos);
//删除pos迭代器所指的元素,返回下一个元素的迭代器。
erase(beg, end);
//删除区间[beg,end)的所有元素 ,返回下一个元素的迭代器。
erase(key);
//删除容器中值为key的元素。
void test01()
{
//插入
map m;
//第一种插入方式-对组方式一
m.insert(pair(1, 10));
//第二种插入方式-对组方式二
m.insert(make_pair(2, 20));
//第三种插入方式,不常用
m.insert(map::value_type(3, 30));
//第四种插入方式
//若key不存在则,会创建一个key为该值,value为默认参数的数据,不好
//所以[]常用于根据key获取value
m[4] = 40;
printMap(m);
//删除
m.erase(m.begin());
printMap(m);
//按照key值删除
m.erase(3);
printMap(m);
//清空
m.erase(m.begin(),m.end());
m.clear();
printMap(m);
}
find(key);
//查找key是否存在,若存在,返回该键的元素的迭代器;若不存在,返回set.end();
count(key);
//统计key的元素个数
注意:
查找 --- find (返回的是迭代器)
统计 --- count (对于map,结果为0或者1)由于map不允许有重复的key对组!multimap而言就是具体的个数。
map容器默认排序规则为 按照key值进行 从小到大排序,掌握如何改变排序规则
主要技术点:
利用仿函数,可以改变排序规则
代码示例:
#include
总结:
利用仿函数可以指定map容器的排序规则
对于自定义数据类型,map必须要指定排序规则,同set容器
案例描述:
公司今天招聘了10个员工(ABCDEFGHIJ),10名员工进入公司之后,需要指派员工在那个部门工作
员工信息有: 姓名 工资组成;部门分为:策划、美术、研发
随机给10名员工分配部门和工资
通过multimap进行信息的插入 key(部门编号) value(员工)
分部门显示员工信息
代码示例:
//.h
#pragma once
#include
#include
#include "string"
#include "vector"
#include "map"
using namespace std;
class employer
{
public:
string m_Name;
int m_DepId;
float m_Salary;
public:
employer(string name)
{
m_Name = name;
m_DepId = rand() % 3;
// 创建一个随机数引擎
std::random_device rd;
std::mt19937 gen(rd());
// 定义浮点数范围
float lower_bound = 0.0f;
float upper_bound = 100.0f;
// 创建一个均匀分布的随机数生成器
std::uniform_real_distribution dist(lower_bound, upper_bound);
// 生成随机浮点数
m_Salary = dist(gen);
}
};
class exp_map
{
public:
vector m_emp;
multimap m_DepMap;
};
//.cpp
#include "exp_map.h"
#include "iostream"
using namespace std;
#define CEHUA 0
#define MEISHU 1
#define YANFA 2
void insert_exp(exp_map &em)
{
employer e1("A");
employer e2("B");
employer e3("C");
employer e4("D");
employer e5("E");
employer e6("F");
employer e7("G");
employer e8("H");
employer e9("I");
employer e10("J");
em.m_emp.push_back(e1);
em.m_emp.push_back(e2);
em.m_emp.push_back(e3);
em.m_emp.push_back(e4);
em.m_emp.push_back(e5);
em.m_emp.push_back(e6);
em.m_emp.push_back(e7);
em.m_emp.push_back(e8);
em.m_emp.push_back(e9);
em.m_emp.push_back(e10);
}
void insert_multimap(exp_map& em)
{
for (vector::iterator it = em.m_emp.begin(); it != em.m_emp.end(); it++)
{
em.m_DepMap.insert(pair((*it).m_DepId,*it));
}
}
void show_dep_emp(multimap &m)
{
//map会按照key进行排序,因此返回pos即第一个符合的位置,其后count个均为其满足条件的结果
cout << "策划部门:" << endl;
multimap::iterator pos = m.find(CEHUA);
int count = m.count(CEHUA);
int index = 0;
for (; pos != m.end() && index < count; pos++, index++)
{
cout << "姓名: " << pos->second.m_Name << " 工资: " << pos->second.m_Salary << endl;
}
cout << "----------------------" << endl;
cout << "美术部门: " << endl;
pos = m.find(MEISHU);
count = m.count(MEISHU); // 统计具体人数
index = 0;
for (; pos != m.end() && index < count; pos++, index++)
{
cout << "姓名: " << pos->second.m_Name << " 工资: " << pos->second.m_Salary << endl;
}
cout << "----------------------" << endl;
cout << "研发部门: " << endl;
//range是一个符合find条件的迭代器集合
auto range = m.equal_range(YANFA);
//range.first 指向范围的开始(第一个匹配元素),而 range.second 则指向范围的末尾(最后一个匹配元素的下一个位置)
//auto 用于自动推导变量的类型。使用 auto 可以使编译器自动推断变量的类型,而不需要手动指定
for (auto pos = range.first; pos != range.second; ++pos) {
cout << "姓名: " << pos->second.m_Name << " 工资: " << pos->second.m_Salary << endl;
}
}
int main()
{
exp_map em;
insert_exp(em);
insert_multimap(em);
show_dep_emp(em.m_DepMap);
system("pause");
return 0;
}
运行结果:
概念:
重载函数调用操作符的类,其对象常称为函数对象
函数对象使用重载的()时,行为类似函数调用,也叫仿函数
本质:
函数对象(仿函数)是一个类,不是一个函数
特点:
函数对象在使用时,可以像普通函数那样调用, 可以有参数,可以有返回值
函数对象超出普通函数的概念,函数对象可以有自己的状态
函数对象可以作为参数传递
1、函数对象在使用时,可以像普通函数那样调用, 可以有参数,可以有返回值
其实就是仿函数,本质是一个类重载了()运算符,然后通过匿名对象调用()。
2、函数对象可以有自己的状态
其实就是因为其本质是类,所以可以拥有成员变量即“自己的状态标识”
3、函数对象可以作为参数传递
其实就是因为其本质是类,则参数即为该类的对象实例!
目前看与仿函数挂钩
STL内建了一些函数对象
注意:
需要引入头文件 #include
仿函数原型:
template
//加法仿函数
template
//减法仿函数
template
//乘法仿函数
template
//除法仿函数
template
//取模仿函数
template
//取反仿函数-一元仿函数,其余均为二元仿函数
//negate
void test01()
{
negate n;
cout << n(50) << endl;
}
//plus
void test02()
{
plus p;
cout << p(10, 20) << endl;
}
template
//等于
template
//不等于
template
//大于
template
//大于等于
template
//小于
template
//小于等于
//伪代码
class MyCompare
{
public:
bool operator()(int v1,int v2)
{
return v1 > v2;
}
};
//自己实现仿函数
//sort(v.begin(), v.end(), MyCompare());
//STL内建仿函数 大于仿函数
sort(v.begin(), v.end(), greater());
template
//逻辑与
template
//逻辑或
template
//逻辑非
逻辑仿函数实际应用较少,了解即可
算法主要是由头文件
组成。
是所有STL头文件中最大的一个,范围涉及到比较、 交换、查找、遍历操作、复制、修改等等
体积很小,只包括几个在序列上面进行简单数学运算的模板函数
定义了一些模板类,用以声明函数对象。
功能:遍历容器元素
for_each(iterator beg, iterator end, _func);
// beg 开始迭代器
// end 结束迭代器
// _func 函数或者函数对象
功能:搬运容器到另一个容器中
transform(iterator beg1, iterator end1, iterator beg2, _func);
//beg1 源容器开始迭代器
//end1 源容器结束迭代器
//beg2 目标容器开始迭代器
//_func 函数或者函数对象,这可以对搬运的数据进行一些运算,实现在仿函数中
//仿函数,不对搬运数据进行处理,直接返回
class TransForm
{
public:
int operator()(int val)
{
return val;
}
};
功能:查找指定元素(内置类型、自定义类型),找到返回指定元素的迭代器,找不到返回结束迭代器end()
find(iterator beg, iterator end, value);
// 按值查找元素,找到返回指定位置迭代器,找不到返回结束迭代器位置
// beg 开始迭代器
// end 结束迭代器
// value 查找的元素
注意:利用find可以在容器中找指定的元素,返回值是迭代器
对于自定义数据类型应该重载operator==,告诉如何对比查找。
//重载==
bool operator==(const Person& p)
{
if (this->m_Name == p.m_Name && this->m_Age == p.m_Age)
{
return true;
}
功能:按照条件查找元素
find_if(iterator beg, iterator end, _Pred);
// 按值查找元素,找到返回指定位置迭代器,找不到返回结束迭代器位置
// beg 开始迭代器
// end 结束迭代器
// _Pred 函数或者谓词(返回bool类型的仿函数)
功能:查找相邻重复元素
adjacent_find(iterator beg, iterator end);
// 查找相邻重复元素,返回相邻元素的第一个位置的迭代器
// beg 开始迭代器
// end 结束迭代器
功能:统计元素个数
count(iterator beg, iterator end, value);
// 统计元素出现次数
// beg 开始迭代器
// end 结束迭代器
// value 统计的元素
注意:value也可以是自定义数据类型,需要在自定义数据类型重载operator==
bool operator==(const Person & p)
{
if (this->m_Age == p.m_Age)
{
return true;
}
else
{
return false;
}
}
功能:按条件统计元素个数
count_if(iterator beg, iterator end, _Pred);
// 按条件统计元素出现次数
// beg 开始迭代器
// end 结束迭代器
// _Pred 谓词
功能:查找指定元素是否存在
bool binary_search(iterator beg, iterator end, value);
// 查找指定的元素,查到 返回true 否则false
// 注意: 在无序序列中不可用,因为底层是二分查找
// beg 开始迭代器
// end 结束迭代器
// value 查找的元素
功能:对容器内元素进行排序
sort(iterator beg, iterator end, _Pred);
// 按值查找元素,找到返回指定位置迭代器,找不到返回结束迭代器位置
// beg 开始迭代器
// end 结束迭代器
// _Pred 谓词
功能:洗牌、指定范围的元素打乱次序
random_shuffle(iterator beg, iterator end);
// 指定范围内的元素随机调整次序
// beg 开始迭代器
// end 结束迭代器
注意:用之前需要加种子,才能真实随机。
随机种子:srand((unsigned int) time(NULL));
功能:两个容器元素合并,并存储到另一个容器中
merge(iterator beg1, iterator end1, iterator beg2, iterator end2, iterator dest);
// 容器元素合并,并存储到另一容器中
// 注意: 两个容器必须是有序的,记得给放入的容器resize扩容一下。
// beg1 容器1开始迭代器
// end1 容器1结束迭代器
// beg2 容器2开始迭代器
// end2 容器2结束迭代器
// dest 目标容器开始迭代器
功能:容器内元素进行反转
reverse(iterator beg, iterator end);
// 反转指定范围的元素
// beg 开始迭代器
// end 结束迭代器
功能:容器内指定范围的元素拷贝到另一容器中
copy(iterator beg, iterator end, iterator dest);
// 按值查找元素,找到返回指定位置迭代器,找不到返回结束迭代器位置
// beg 开始迭代器
// end 结束迭代器
// dest 目标起始迭代器
功能:将容器内指定范围的旧元素替换为新的元素
replace(iterator beg, iterator end, oldvalue, newvalue);
// 将区间内旧元素 替换成 新元素
// beg 开始迭代器
// end 结束迭代器
// oldvalue 旧元素
// newvalue 新元素
功能:
将区间内满足条件的元素,替换成指定元素
replace_if(iterator beg, iterator end, _pred, newvalue);
// 按条件替换元素,满足条件的替换成指定元素
// beg 开始迭代器
// end 结束迭代器
// _pred 谓词
// newvalue 替换的新元素
功能:互换两个容器的元素
swap(container c1, container c2);
// 互换两个容器的元素
// c1容器1
// c2容器2
注意:两个容器数据类型必须相同
功能:计算区间内容器元素累计总和
accumulate(iterator beg, iterator end, value);
// 计算容器元素累计总和
// beg 开始迭代器
// end 结束迭代器
// value 起始值 一般为0
注意:accumulate使用时头文件注意是 numeric,这个算法很实用
功能:向容器中填充指定的元素
fill(iterator beg, iterator end, value);
// 向容器中填充元素
// beg 开始迭代器
// end 结束迭代器
// value 填充的值
功能:求两个容器的交集
set_intersection(iterator beg1, iterator end1, iterator beg2, iterator end2, iterator dest);
// 求两个集合的交集
// 注意:两个集合必须是有序序列
// beg1 容器1开始迭代器
// end1 容器1结束迭代器
// beg2 容器2开始迭代器
// end2 容器2结束迭代器
// dest 目标容器开始迭代器
注意:
求交集的两个集合必须的有序序列
目标容器开辟空间需要从两个容器中取小值
set_intersection返回值既是交集中最后一个元素的位置
遍历用返回的最后的迭代器itEnd.
set_intersection(v1.begin(), v1.end(), v2.begin(), v2.end(), vTarget.begin());
for_each(vTarget.begin(), itEnd, myPrint());
cout << endl;
功能:求并集
set_union(iterator beg1, iterator end1, iterator beg2, iterator end2, iterator dest);
// 求两个集合的并集
// 注意:两个集合必须是有序序列
// beg1 容器1开始迭代器
// end1 容器1结束迭代器
// beg2 容器2开始迭代器
// end2 容器2结束迭代器
// dest 目标容器开始迭代器
注意:
求并集的两个集合必须的有序序列
目标容器开辟空间需要两个容器相加
set_union返回值既是并集中最后一个元素的位置
功能:两个集合差集
set_difference(iterator beg1, iterator end1, iterator beg2, iterator end2, iterator dest);
// 求两个集合的差集
// 注意:两个集合必须是有序序列
// beg1 容器1开始迭代器
// end1 容器1结束迭代器
// beg2 容器2开始迭代器
// end2 容器2结束迭代器
// dest 目标容器开始迭代器
注意:
求差集的两个集合必须的有序序列
目标容器开辟空间需要从两个容器取较大值
set_difference返回值既是差集中最后一个元素的位置