巩义便宜网站建设公司,旅游网站如何建设,企业网站项目的流程,零基础自学网站建设1、STL简介
1.1基本概念
可复用利用的东西#xff01;
面向对象和泛型编程#xff08;模板#xff09;的 目的-提升复用性
为了建立数据结构和算法的一套标准-STL横空出世
STL(Standard Template Liberary)标准模板库广义分#xff1a;容器、算法、迭代器容器…1、STL简介
1.1基本概念
可复用利用的东西
面向对象和泛型编程模板的 目的-提升复用性
为了建立数据结构和算法的一套标准-STL横空出世
STL(Standard Template Liberary)标准模板库广义分容器、算法、迭代器容器和算法之间通过迭代器连接、STL几乎所有的代码均采用函数模板和类模板
1.2六大组件
容器各种数据结构如vector、list、deque、map、set等由于数据存储。 序列式排序强调值的排序序列式容器中的每个元素均有固定的位置。 关联式排序二叉树结构各元素之间没有严格的物理的顺序关系。
算法各种算法如sort、find、copy、for_each等。迭代器容器和算法连接桥梁。 提供一种方法使之间能够依次序访问某个容器所含的各个元素而又无需暴露该容器的内部表示方式。每个容器都有自己专属的迭代器。类似于指针可简单理解为指针。
迭代器种类
种类功能支持运算输入迭代器对数据的只读访问只读支持、、输出迭代器对数据的只写访问只写支持前向迭代器读写操作并能向前推进迭代器读写支持、、双向迭代器读写操作并能向前和向后操作读写支持、--随机访问迭代器读写操作可以以跳跃的方式访问任意数据功能最强的迭代器读写支持、--、[n]、-n、、、、
常用的容器中迭代器种类为双向迭代器和随机访问迭代器
仿函数作为算法的某种策略。适配器配接器一种用来修饰容器或者仿函数或迭代接口的东西。空间配置器负责空间的配置与管理。
1.3容器、算法、迭代器案例Vector
创建、插入、遍历
1.3.1vector存放内置数据类型
案例代码
//.h
#pragma once
#include iostream
#includevector
#include algorithm
class STL_Vector
{
public:void test_exp();
};//.cpp
#include STL_Vector.husing namespace std;
void func(int val)
{cout val endl;
}
void STL_Vector::test_exp()
{//创建vector int 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);//遍历vectorint::iterator it_begin v.begin();vectorint::iterator it_end v.end();//方式一while (it_begin ! it_end){cout *it_begin endl;it_begin;}//方式二for (vectorint::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.hint main()
{STL_Vector sv STL_Vector();sv.test_exp();system(pause);return 0;
} 运行结果 1.3.2vector存放自定义数据类型及自定义对象指针
代码示例
//.h
#pragma once
#include iostream
#includevector
#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()
{//创建vectorAnimalv_p;vectorAnimal *v_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 (vectorAnimal::iterator it v_p.begin(); it ! v_p.end(); it){cout 年龄 it-m_age 姓名 (*it).m_name endl;}for (vectorAnimal *::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.hint main()
{STL_Vector sv STL_Vector();sv.test_exp();system(pause);return 0;
}
运行结果 1.3.3容器嵌套-有点二维数组的意思
代码示例
//.h
#pragma once
#include iostream
#includevector
#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()
{//创建vectorvectorstring v_nest;vectorstring v_nest1;vectorstring v_nest2;vectorstring v_nest3;vectorstring 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 (vectorvectorstring::iterator it v_nest.begin(); it ! v_nest.end(); it){for (vectorstring::iterator itt (*it).begin(); itt ! (*it).end(); itt){cout (*itt) ;}cout endl;}
}
//mian
#include iostream
using namespace std;
#include STL_Vector.hint main()
{STL_Vector sv STL_Vector();sv.test_exp();system(pause);return 0;
} 2、常用容器
2.1string
本质string是C风格的字符串string是一个类。
char *是一个指针是C风格的字符串
string是一个类封装了char*管理和维护char*的容器
2.1.1string构造函数
无参构造string();构造语句 string str;字符串初始化string(const char * str);拷贝构造string(const string str);n个字符构造string(int n,char c);
代码示例
//.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;
}运行结果 2.1.2string的赋值操作 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;
}运行结果 2.1.3string字符串拼接 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;
}运行结果 2.1.4string查找和替换 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在替换时要指定从哪个位置起多少个字符替换成什么样的字符串全换进去
2.1.5string比较 字符串比较是按字符的ASCII码进行对比 返回 0 返回 1 返回 -1
函数原型 int compare(const string s) const; //与字符串s比较 int compare(const char *s) const; //与字符串s比较
2.1.6string插入和删除 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开始
2.1.7string截取子串
函数原型
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: substrendl;//截取信息string str1 rwerwefgewf1313163.cn;int pos str1.find();cout emial str1 endl;string substr_email str1.substr(0, pos);cout substr_email: substr_email;
}
运行结果 2.1.8string字符中字符获取与修改
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
2.2vector容器
2.2.1vector基本概念
又称单端数组
与数组的最大区别数组静态的vector可动态申请空间采用的方式是动态扩展
即复制原数据到新开辟空间的上并释放原空间
常用函数及迭代器 vector容器是支持随机访问的迭代器 2.2.2vector构造函数 vectorT v; //采用模板实现类实现默认构造函数 vector(v.begin(), v.end()); //将v[begin(), end())前闭后开区间中的元素拷贝给本身。 vector(n, elem); //构造函数将n个elem拷贝给本身。 vector(const vector vec); //拷贝构造函数。
2.2.3vector赋值操作 vector operator(const vector vec);//重载等号操作符 assign(beg, end); //将[beg, end)区间中的数据拷贝赋值给本身。 assign(n, elem); //将n个elem拷贝赋值给本身。
2.2.4vector容量 empty(); //判断容器是否为空空返回为true,否则为false capacity(); //容器的容量capacity size; size(); //返回容器中元素的个数 resize(int num); //重新指定容器的长度为num若容器变长则以默认值(0)填充新位置。 //如果容器变短则末尾超出容器长度的元素被删除。 resize(int num, elem); //重新指定容器的长度为num若容器变长则以elem值填充新位置。 //如果容器变短则末尾超出容器长度的元素被删除
2.2.5 vector插入和删除 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(); //删除容器中所有元素
2.2.6vector数据获取 at(int idx); //返回索引idx所指的数据 operator[]; //返回索引idx所指的数据 front(); //返回容器中第一个数据元素 back(); //返回容器中最后一个数据元素
注意是迭代器参数
2.2.7vector互换
功能描述 实现两个容器内元素进行互换
函数原型 swap(vec); // 将vec与本身的元素互换
实际用途收缩内存空间
v.swap(v);
v的申请空间很大但实际用的很少内存浪费于是vectorT (v).swap(v);
vectorT (v)为匿名对象其占用内存和v一样但申请空间和占用空间一致最后再换给v使得空间压缩不浪费了
2.2.8vector预留空间
功能描述 减少vector在动态扩展容量时的扩展次数
函数原型 reserve(int len);//容器预留len个元素长度预留位置不初始化元素不可访问。
2.3deque容器
2.3.1deque基本概念和原理
功能 双端数组可以对头端进行插入删除操作
deque与vector区别 vector对于头部的插入删除效率低数据量越大效率越低 deque相对而言对头部的插入删除速度回比vector快 vector访问元素时的速度会比deque快,这和两者内部实现有关
常用迭代器和函数 deque内部工作原理:
deque内部有个中控器维护每段缓冲区中的内容缓冲区中存放真实数据
中控器维护的是每个缓冲区的地址使得使用deque时像一片连续的内存空间
deque容器的迭代器也是支持随机访问的。 2.3.2deque构造函数 dequeT deqT; //默认构造形式 deque(beg, end); //构造函数将[beg, end)区间中的元素拷贝给本身。 deque(n, elem); //构造函数将n个elem拷贝给本身。 deque(const deque deq); //拷贝构造函数
注意 //参数是const只读模式则迭代器也应该变为只读迭代器 void printDeque(const dequeint d) { for (dequeint::const_iterator it d.begin(); it ! d.end(); it) { cout *it ; } cout endl; } 2.3.4 deque赋值 deque operator(const deque deq); //重载等号操作符 assign(beg, end); //将[beg, end)区间中的数据拷贝赋值给本身。 assign(n, elem); //将n个elem拷贝赋值给本身。 2.3.4deque大小获取、大小更改、判空 deque.empty(); //判断容器是否为空 deque.size(); //返回容器中元素的个数 deque.resize(num); //重新指定容器的长度为num,若容器变长则以默认值0填充新位置。 //如果容器变短则末尾超出容器长度的元素被删除。 deque.resize(num, elem); //重新指定容器的长度为num,若容器变长则以elem值填充新位置。 //如果容器变短则末尾超出容器长度的元素被删除。
注意
deque没有capacity属性
2.3.5deque插入与删除 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位置的数据返回下一个数据的位置。
2.3.6数据获取 at(int idx); //返回索引idx所指的数据 operator[]; //返回索引idx所指的数据 front(); //返回容器中第一个数据元素 back(); //返回容器中最后一个数据元素
2.3.7排序 sort(iterator beg, iterator end) //对beg和end区间内元素进行排序
注意#include ”algorithm“;
2.4容器案例
有5名选手10个评委分别对每一名选手打分去除最高分去除评委中最低分取平均分。
代码示例
//.h
#pragma once
#include vector
#include deque
#include string
using namespace std;
class player
{
public:string m_name;dequefloat m_scores;
};
class Exa_evaluate_score
{
public:Exa_evaluate_score();void eval(int index);void summarizing(int index);
public:vectorplayer m_p;
};//.cpp
#include Exa_evaluate_score.h
#include string
#include deque
#include iostream
#include algorithm
using namespace std;Exa_evaluate_score::Exa_evaluate_score()
{m_p.resize(10);
}
void Exa_evaluate_score::eval(int index)
{cout 请输入第 index1 位选手得分 endl;cout 输入姓名 ;string name;getline(cin, name);m_p[index].m_name name;for (int j 0; j 10; j){cout 第 j 1 位评委请对 index1 位选手打分: 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 (dequefloat::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;
}
运行结果 2.5stack 容器
2.5.1基本概念
FILO(First In Last Out)
2.5.2stack构造函数 stackT stk; //stack采用模板类实现 stack对象的默认构造形式 stack(const stack stk); //拷贝构造函数
2.5.3stack赋值函数 stack operator(const stack stk); //重载等号操作符
2.5.4stack出栈、入栈、取栈顶 push(elem); //向栈顶添加元素 pop(); //从栈顶移除第一个元素 top(); //返回栈顶元素
2.5.5stack判空、获取大小 empty(); //判断堆栈是否为空 size(); //返回栈的大小
2.6queue容器
2.6.1queue基本概念
FIFO(First In First Out)
常用函数尾入头出 2.6.2queue构造函数 queueT que; //queue采用模板类实现queue对象的默认构造形式 queue(const queue que); //拷贝构造函数
2.6.7queue赋值操作 queue operator(const queue que); //重载等号操作符
2.6.8queue入队、出队、获取队尾对头元素 push(elem); //往队尾添加元素 pop(); //从队头移除第一个元素 back(); //返回最后一个元素 front(); //返回第一个元素
2.6.9queue判空、获取大小 empty(); //判断堆栈是否为空 size(); //返回栈的大小 2.7list容器
2.7.1list基本概念
双向循环链表list容器的迭代器是双向迭代器不支持随机访问 由于链表的存储方式并不是连续的内存空间因此链表list中的迭代器只支持前移和后移属于双向迭代器
list的优点 采用动态存储分配不会造成内存浪费和溢出 链表执行插入和删除操作十分方便修改指针即可不需要移动大量元素
list的缺点 链表灵活但是空间(指针域) 和 时间遍历额外耗费较大
STL中List和vector是两个最常被使用的容器各有优缺点
2.7.2 list构造函数 listT lst; //list采用采用模板类实现,对象的默认构造形式 list(beg,end); //构造函数将[beg, end)区间中的元素拷贝给本身。 list(n,elem); //构造函数将n个elem拷贝给本身。 list(const list lst); //拷贝构造函数。
2.7.3 list赋值操作 assign(beg, end); //将迭代器[beg, end)区间中的数据拷贝赋值给本身。 assign(n, elem); //将n个elem拷贝赋值给本身。 list operator(const list lst); //重载等号操作符
2.7.4 list交换操作
swap(lst); //将lst与本身的元素互换。
注不要求两个交换的list的数据个数相同
2.7.5 list获取大小、判空、更改容量 size(); //返回容器中元素的个数 empty(); //判断容器是否为空 resize(num); //重新指定容器的长度为num若容器变长则以默认值填充新位置。 //如果容器变短则末尾超出容器长度的元素被删除。 resize(num, elem); //重新指定容器的长度为num若容器变长则以elem值填充新位置。 //如果容器变短则末尾超出容器长度的元素被删除。
2.7.6 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();//移除容器的所有数据 erase(beg,end);//删除[beg,end)区间的数据返回下一个数据的位置。 erase(pos);//删除pos位置的数据返回下一个数据的位置。 remove(elem);//删除容器中所有与elem值匹配的元素。
2.7.7 list 获取第一个元素、最后一个元素
list不支持随机访问即无 [] ,at等随机访问的方法 front(); //返回第一个元素。 back(); //返回最后一个元素。 2.7.8 list反转和排序 reverse(); //反转链表 sort(); //链表排序 参数为一个回调函数其中声明了排序次序即可更改默认 次序从小到大的次序。 L.sort(myCompare); //指定规则从大到小 bool myCompare(int val1 , int val2) { return val1 val2; } 2.7.9 list排序案例
案例描述将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:listNiuMa m_NM;
};//.cpp
#include list_sort_niuma.h
#include iostreambool 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 (listNiuMa::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 (listNiuMa::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;
}运行结果 2.8set、multiset 容器
2.8.1set及multiset的基本概念和区别
简介所有的元素会被插入后自动进行排序
本质关联式容器底层二叉树实现
set与multiset区别
set不允许有重复元素multiset允许有重复元素
注两个包含头文件只需包含set即可即#include ”set“;
2.8.2set构造函数 setT st; //默认构造函数 set(const set st); //拷贝构造函数
2.8.3set赋值操作 set operator(const set st); //重载等号操作符
2.8.4set判空、获取大小、交换 size(); //返回容器中元素的数目 empty(); //判断容器是否为空 swap(st); //交换两个集合容器
2.8.5set插入与删除 insert(elem); //在容器中插入元素。 clear(); //清除所有元素 erase(pos); //删除pos迭代器所指的元素返回下一个元素的迭代器。 erase(beg, end); //删除区间[beg,end)的所有元素 返回下一个元素的迭代器。 erase(elem); //删除容器中值为elem的元素。
2.8.6set查找与统计 find(key); //查找key是否存在,若存在返回该键的元素的迭代器若不存在返回set.end(); count(key); //统计key的元素个数
2.8.7set、multiset的区别 set不可以插入重复数据而multiset可以 set插入数据的同时会返回插入结果表示插入是否成功 multiset不会检测数据因此可以插入重复数据
2.8.8pair对组创建
成对出现的数据利用对组可返回两个数据
对组创建方式
pairtype,type p (val1,val2);
pairtype,type p make_pair(val1,val2);
代码示例 pairstring, int p(string(Tom), 20); pairstring, int p2 make_pair(Jerry, 10); 2.8.9set排序
2.8.9.1内置数据类型排序
主要技术点 利用仿函数可以改变排序规则 注意一定在插入之前就利用仿函数进行指定排序顺序
代码示例
#include set
class MyCompare
{
public:bool operator()(int v1, int v2) {return v1 v2;}
};
void test01()
{ setint s1;s1.insert(10);s1.insert(40);s1.insert(20);s1.insert(30);s1.insert(50);//默认从小到大for (setint::iterator it s1.begin(); it ! s1.end(); it) {cout *it ;}cout endl;//指定排序规则setint,MyCompare s2;s2.insert(10);s2.insert(40);s2.insert(20);s2.insert(30);s2.insert(50);for (setint, MyCompare::iterator it s2.begin(); it ! s2.end(); it) {cout *it ;}cout endl;
}int main() {test01();system(pause);return 0;
}
2.8.9.2自定义数据类型排序
对于自定义数据类型set必须指定排序规则才可以插入数据
代码示例
#include set
#include stringclass 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()
{setPerson, comparePerson 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 (setPerson, comparePerson::iterator it s.begin(); it ! s.end(); it){cout 姓名 it-m_Name 年龄 it-m_Age endl;}
}
int main() {test01();system(pause);return 0;
}
2.9map、multimap容器
2.9.1map基本概念
简介 map中所有的元素都是pairpair中第一个元素为key起到索引作用第二个元素为value所有的元素会根据元素key自动排序
本质 map/multimap属于关联式容器底层结构是用二叉树实现
优点 可以根据key值快速找到value值
map和multimap区别 map不允许容器中有重复key值元素 multimap允许容器中有重复key值元素
2.9.2map的构造和赋值 mapT1, T2 mp; //map默认构造函数: map(const map mp); //拷贝构造函数 map operator(const map mp); //重载等号操作符
void test01()
{mapint,intm; //默认构造m.insert(pairint, int(1, 10));m.insert(pairint, int(2, 20));m.insert(pairint, int(3, 30));printMap(m);mapint, intm2(m); //拷贝构造printMap(m2);mapint, intm3;m3 m2; //赋值printMap(m3);
}
2.9.3map判空、获取大小、交换 size(); //返回容器中元素的数目 empty(); //判断容器是否为空 swap(st); //交换两个集合容器
2.9.4map插入、删除 insert(elem); //在容器中插入元素。 clear(); //清除所有元素 erase(pos); //删除pos迭代器所指的元素返回下一个元素的迭代器。 erase(beg, end); //删除区间[beg,end)的所有元素 返回下一个元素的迭代器。 erase(key); //删除容器中值为key的元素。
void test01()
{//插入mapint, int m;//第一种插入方式-对组方式一m.insert(pairint, int(1, 10));//第二种插入方式-对组方式二m.insert(make_pair(2, 20));//第三种插入方式不常用m.insert(mapint, int::value_type(3, 30));//第四种插入方式//若key不存在则会创建一个key为该值value为默认参数的数据不好//所以[]常用于根据key获取valuem[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);
}
2.9.5 map查找与统计 find(key); //查找key是否存在,若存在返回该键的元素的迭代器若不存在返回set.end(); count(key); //统计key的元素个数
注意 查找 --- find 返回的是迭代器 统计 --- count 对于map结果为0或者1由于map不允许有重复的key对组multimap而言就是具体的个数。
2.9.6map排序 map容器默认排序规则为 按照key值进行 从小到大排序掌握如何改变排序规则
主要技术点: 利用仿函数可以改变排序规则
代码示例
#include map
class MyCompare {
public:bool operator()(int v1, int v2) {return v1 v2;}
};
void test01()
{//默认从小到大排序//利用仿函数实现从大到小排序mapint, int, MyCompare m;
m.insert(make_pair(1, 10));m.insert(make_pair(2, 20));m.insert(make_pair(3, 30));m.insert(make_pair(4, 40));m.insert(make_pair(5, 50));
for (mapint, int, MyCompare::iterator it m.begin(); it ! m.end(); it) {cout key: it-first value: it-second endl;}
}
int main() {
test01();
system(pause);
return 0;
}
总结 利用仿函数可以指定map容器的排序规则 对于自定义数据类型map必须要指定排序规则,同set容器
2.9.7map案例
案例描述 公司今天招聘了10个员工ABCDEFGHIJ10名员工进入公司之后需要指派员工在那个部门工作 员工信息有: 姓名 工资组成部门分为策划、美术、研发 随机给10名员工分配部门和工资 通过multimap进行信息的插入 key(部门编号) value(员工) 分部门显示员工信息
代码示例
//.h
#pragma once#include iostream
#include random
#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_distributionfloat dist(lower_bound, upper_bound);// 生成随机浮点数m_Salary dist(gen);}
};
class exp_map
{
public:vectoremployer m_emp;multimapint, employer 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 (vectoremployer::iterator it em.m_emp.begin(); it ! em.m_emp.end(); it){em.m_DepMap.insert(pairint,employer((*it).m_DepId,*it));}
}void show_dep_emp(multimapint, employer m)
{//map会按照key进行排序因此返回pos即第一个符合的位置其后count个均为其满足条件的结果cout 策划部门 endl;multimapint, employer::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;
}
运行结果 3、函数对象
3.1函数对象概念
概念 重载函数调用操作符的类其对象常称为函数对象 函数对象使用重载的()时行为类似函数调用也叫仿函数
本质
函数对象(仿函数)是一个类不是一个函数
特点 函数对象在使用时可以像普通函数那样调用, 可以有参数可以有返回值 函数对象超出普通函数的概念函数对象可以有自己的状态 函数对象可以作为参数传递
3.2函数对象的使用
1、函数对象在使用时可以像普通函数那样调用, 可以有参数可以有返回值
其实就是仿函数本质是一个类重载了()运算符然后通过匿名对象调用()。
2、函数对象可以有自己的状态
其实就是因为其本质是类所以可以拥有成员变量即“自己的状态标识”
3、函数对象可以作为参数传递
其实就是因为其本质是类则参数即为该类的对象实例
3.3谓词
3.3.1谓词概念
返回bool类型的仿函数被称为谓词operator()重载()运算符接受一个参数那么叫一元谓词operator()重载()运算符接受两个参数那么叫二元谓词
目前看与仿函数挂钩
3.4内建函数对象-可直接拿来用的仿函数
3.4.1概念
STL内建了一些函数对象
算术仿函数关系仿函数逻辑仿函数
注意
需要引入头文件 #includefunctional
3.4.2算术仿函数
仿函数原型 templateclass T T plusT //加法仿函数 templateclass T T minusT //减法仿函数 templateclass T T multipliesT //乘法仿函数 templateclass T T dividesT //除法仿函数 templateclass T T modulusT //取模仿函数 templateclass T T negateT //取反仿函数-一元仿函数其余均为二元仿函数
//negate
void test01()
{negateint n;cout n(50) endl;
}//plus
void test02()
{plusint p;cout p(10, 20) endl;
} 3.4.3关系仿函数 templateclass T bool equal_toT //等于 templateclass T bool not_equal_toT //不等于 templateclass T bool greaterT //大于 templateclass T bool greater_equalT //大于等于 templateclass T bool lessT //小于 templateclass T bool less_equalT //小于等于
//伪代码
class MyCompare
{
public:bool operator()(int v1,int v2){return v1 v2;}
};
//自己实现仿函数
//sort(v.begin(), v.end(), MyCompare());
//STL内建仿函数 大于仿函数
sort(v.begin(), v.end(), greaterint());
3.4.5逻辑仿函数 templateclass T bool logical_andT //逻辑与 templateclass T bool logical_orT //逻辑或 templateclass T bool logical_notT //逻辑非
逻辑仿函数实际应用较少了解即可
4、STL-常用算法
4.1常用头文件 算法主要是由头文件algorithm functional numeric组成。 algorithm是所有STL头文件中最大的一个范围涉及到比较、 交换、查找、遍历操作、复制、修改等等 numeric体积很小只包括几个在序列上面进行简单数学运算的模板函数 functional定义了一些模板类,用以声明函数对象。
4.2常用遍历算法
4.2.1for_each 很常用
功能遍历容器元素
for_each(iterator beg, iterator end, _func);
// beg 开始迭代器
// end 结束迭代器
// _func 函数或者函数对象
4.2.2transform
功能搬运容器到另一个容器中
transform(iterator beg1, iterator end1, iterator beg2, _func);
//beg1 源容器开始迭代器
//end1 源容器结束迭代器
//beg2 目标容器开始迭代器
//_func 函数或者函数对象,这可以对搬运的数据进行一些运算实现在仿函数中
//仿函数不对搬运数据进行处理直接返回
class TransForm
{
public:int operator()(int val){return val;}};
4.3常用查找算法
4.3.1find
功能查找指定元素内置类型、自定义类型找到返回指定元素的迭代器找不到返回结束迭代器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;}
4.3.2find_if
功能按照条件查找元素
find_if(iterator beg, iterator end, _Pred);
// 按值查找元素找到返回指定位置迭代器找不到返回结束迭代器位置
// beg 开始迭代器
// end 结束迭代器
// _Pred 函数或者谓词返回bool类型的仿函数
4.3.3adjacent_find
功能查找相邻重复元素
adjacent_find(iterator beg, iterator end);
// 查找相邻重复元素,返回相邻元素的第一个位置的迭代器
// beg 开始迭代器
// end 结束迭代器
4.3.4count
功能统计元素个数
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;}}
4.3.5count_if
功能按条件统计元素个数
count_if(iterator beg, iterator end, _Pred);
// 按条件统计元素出现次数
// beg 开始迭代器
// end 结束迭代器
// _Pred 谓词
4.3.6binary_search
功能查找指定元素是否存在
bool binary_search(iterator beg, iterator end, value);
// 查找指定的元素查到 返回true 否则false
// 注意: 在无序序列中不可用因为底层是二分查找
// beg 开始迭代器
// end 结束迭代器
// value 查找的元素
4.4常用排序算法
4.4.1sort 常用
功能对容器内元素进行排序
sort(iterator beg, iterator end, _Pred);
// 按值查找元素找到返回指定位置迭代器找不到返回结束迭代器位置
// beg 开始迭代器
// end 结束迭代器
// _Pred 谓词
4.4.2random_shuffle
功能洗牌、指定范围的元素打乱次序
random_shuffle(iterator beg, iterator end);
// 指定范围内的元素随机调整次序
// beg 开始迭代器
// end 结束迭代器
注意用之前需要加种子才能真实随机。
随机种子srand((unsigned int) time(NULL));
4.4.3merge
功能两个容器元素合并并存储到另一个容器中
merge(iterator beg1, iterator end1, iterator beg2, iterator end2, iterator dest);
// 容器元素合并并存储到另一容器中
// 注意: 两个容器必须是有序的记得给放入的容器resize扩容一下。
// beg1 容器1开始迭代器
// end1 容器1结束迭代器
// beg2 容器2开始迭代器
// end2 容器2结束迭代器
// dest 目标容器开始迭代器
4.4.4reverse
功能容器内元素进行反转
reverse(iterator beg, iterator end);
// 反转指定范围的元素
// beg 开始迭代器
// end 结束迭代器
4.5常用拷贝喝替换函数
4.5.1copy
功能容器内指定范围的元素拷贝到另一容器中
copy(iterator beg, iterator end, iterator dest);
// 按值查找元素找到返回指定位置迭代器找不到返回结束迭代器位置
// beg 开始迭代器
// end 结束迭代器
// dest 目标起始迭代器
4.5.2replace
功能将容器内指定范围的旧元素替换为新的元素
replace(iterator beg, iterator end, oldvalue, newvalue);
// 将区间内旧元素 替换成 新元素
// beg 开始迭代器
// end 结束迭代器
// oldvalue 旧元素
// newvalue 新元素
4.5.3replace_if
功能
将区间内满足条件的元素替换成指定元素
replace_if(iterator beg, iterator end, _pred, newvalue);
// 按条件替换元素满足条件的替换成指定元素
// beg 开始迭代器
// end 结束迭代器
// _pred 谓词
// newvalue 替换的新元素
4.5.4swap
功能互换两个容器的元素
swap(container c1, container c2);
// 互换两个容器的元素
// c1容器1
// c2容器2
注意两个容器数据类型必须相同
4.6常用算术生成算法
4.6.1accumulate
功能计算区间内容器元素累计总和
accumulate(iterator beg, iterator end, value);
// 计算容器元素累计总和
// beg 开始迭代器
// end 结束迭代器
// value 起始值 一般为0
注意accumulate使用时头文件注意是 numeric这个算法很实用
4.6.2fill
功能向容器中填充指定的元素
fill(iterator beg, iterator end, value);
// 向容器中填充元素
// beg 开始迭代器
// end 结束迭代器
// value 填充的值
4.7常用集合算法-交并差集
4.7.1set_intersectionn
功能:求两个容器的交集
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;
4.7.2set_union
功能求并集
set_union(iterator beg1, iterator end1, iterator beg2, iterator end2, iterator dest);
// 求两个集合的并集
// 注意:两个集合必须是有序序列
// beg1 容器1开始迭代器
// end1 容器1结束迭代器
// beg2 容器2开始迭代器
// end2 容器2结束迭代器
// dest 目标容器开始迭代器
注意 求并集的两个集合必须的有序序列 目标容器开辟空间需要两个容器相加 set_union返回值既是并集中最后一个元素的位置
4.7.3set_difference
功能两个集合差集
set_difference(iterator beg1, iterator end1, iterator beg2, iterator end2, iterator dest);
// 求两个集合的差集
// 注意:两个集合必须是有序序列
// beg1 容器1开始迭代器
// end1 容器1结束迭代器
// beg2 容器2开始迭代器
// end2 容器2结束迭代器
// dest 目标容器开始迭代器
注意 求差集的两个集合必须的有序序列 目标容器开辟空间需要从两个容器取较大值 set_difference返回值既是差集中最后一个元素的位置