STL从广义上分为容器(container),算法(algorithm),迭代器(iterator)
STL六大组件,容器,算法,迭代器,仿函数,适配器(配接器),空间配置器。
容器:各种数据结构,如vector,list,deque,set,map等,用来存放数据,从实现角度来看,STL是一种class template。
算法:各种常用的算法,如sort,find,copy,for_each。从实现角度来看,算法是一种function template。
迭代器:扮演了容器与算法之间的胶合剂,共有五种类型,从实现角度来看,迭代器是一种将operator* , operator-> , operator++,operator–等指针相关操作予以重载的class template. 所有STL容器都附带有自己专属的迭代器,只有容器的设计者才知道如何遍历自己的元素。原生指针(native pointer)也是一种迭代器。
仿函数:行为类似函数,可作为算法的某种策略。从实现角度来看,仿函数是一种重载了operator()的class 或者class template
适配器:一种用来修饰容器或者仿函数或迭代器接口的东西。
空间配置器:负责空间的配置与管理。从实现角度看,配置器是一个实现了动态空间配置、空间管理、空间释放的class tempalte.
STL六大组件的交互关系,容器通过空间配置器取得数据存储空间,算法通过迭代器存储容器中的内容,仿函数可以协助算法完成不同的策略的变化,适配器可以修饰仿函数。
一、容器
一般来说,可以分为序列式容器和关联式容器,(就是顺序存储和键值对的区别)。
1、string
char * 是一个指针,但是string是一个类,string封装了char *,
string封装了很多成员方法,find,copy,delete,replace,insert。
不用考虑内存和越界。
#include <iostream>
#include<string>
using namespace std;
//string
/*
构造函数
string();//创建一个空的字符串,例如string str;
string(const string& str);//使用一个string对象初始化另一个string对象;
string(const char*s);//使用字符串s初始化
string(int n,char c);//使用n个字符c初始化
基本赋值操作
string& operator=(const char*s);//char*类型字符串,赋值给当前的字符串
string& operator=(const string &s);//把字符串s赋给当前的字符串
string& assign(const char *s);//把字符串s赋给当前的字符串
string& assign(const chat *s,int n);//把字符串s的前n个字符赋给当前的字符串
string& assign(int n,char c);//用n个字符c赋给当前字符串
string& assign(const string &s,int start,int n);//将s从start开始n个字符赋值给字符串
*/
void test01()
{
string s1="cccc";
string s2(s1);
string s3("aaa");
string s4(5, 'a');
cout << s1 << endl;
cout << s2 << endl;
cout << s3 << endl;
cout << s4 << endl;
string s5;
s5.assign("sdfsdfds", 5);
cout << s5 << endl;
string s6;
s6.assign("sfddssdfs", 3, 5);
cout << s6 << endl;
string s7 = "Hello World";
for (int i = 0; i < s7.size(); i++)
{
cout << s7[i] << endl;
cout << s7.at(i) << endl;
//区别:[]越界直接报错退出,at越界会抛出,显示out_of_range
}
string s8="aaaa";
s8 += s7;
for (int i = 0; i < s8.size(); i++)
{
cout << s8[i]<<endl;
}
string s9 = "qwertyuiop";
int temp = s9.find("ty");
cout << temp;//如果找不到返回-1;find从左向右,rfind从右向左;再加一个参数是从哪个开始找
s9.replace(1, 3, "mmmm");//注意这里3换4,3换5,都可以
cout << s9;
//比较是compare
}
void test02()
{
string s1 = "qwertyuiop";
string s2 = s1.substr(1, 3);
cout << s2 << endl;
//插入操作
s2.insert(1, "111");
cout << s2 << endl;
s2.insert(4,3,'2');
cout << s2 << endl;
s2.erase(1, 6);
cout << s2 << endl;
}
void test03()
{
char a[6] = "hello";
//char * str = 'hello';这里的空间不负责啊
char str[] = "sdfsf";
char* str1 = (char*)malloc(sizeof("hello"));
string s1(str);//char*->string
const char* s2 = s1.c_str();//将string转为s_string(const char*)
//编译器可以将const char*隐式转换为string,但是不会将string 隐式转换为const char*;
//string会自动分配一块内存,但是当内存重新分配后,会换一个地方
//str[i] = toupper(str[i]);小写转大写,大写转小写是tolower()
}
int main()
{
cout << "Hello World!\n";
test02();
}
2、vector
#include <iostream>
#include<string>
#include<vector>
using namespace std;
void printVector(vector<int>&v)
{
for (vector<int>::iterator it = v.begin(); it != v.end(); it++)
{
cout << *it;
}
cout << endl;
}
void test01()
{
vector<int>v;
for (int i = 0; i < 10; i++)
{
v.push_back(i);
cout << v.capacity() << endl;//容量
}
}
void test04()
{
}
void test02()//
{
//构造函数
vector<int> v;
vector<int> v2(5, 100);
printVector(v2);
v.push_back(1);
v.push_back(2);
v.push_back(3);
v.push_back(4);
v.push_back(5);
printVector(v);
vector<int> v3(v.begin(), v.end()); printVector(v3);
vector<int>v4;
v4.assign(v3.begin(), v3.end());
printVector(v4);
vector<int>v5;
v5.assign(v4[2], v3[4]);
printVector(v5);
v5.swap(v4);
}
void test03()
{
vector<int> v;
v.push_back(1);
v.push_back(2);
v.push_back(3);
v.push_back(4);
v.push_back(5);
printVector(v);
cout << "v.size" << v.size();
//v1.empty()是否为空
v.resize(10);
printVector(v);
v.resize(3);
printVector(v);//resize(大小,默认值);
cout << v.front() << endl;
cout << v.back() << endl;
v.insert(v.begin(), 1000);//这的第一个参数是迭代器
printVector(v);
v.insert(v.begin()+1, 999);
printVector(v);
v.pop_back();//尾删
v.erase(v.begin(), v.end());//输入迭代器
}
void test04()
{
//巧用swap()节省空间,因为vector容量只能自己变大,不能变小,但是自己新建一个自己,再交换就可以。
//vector<int> v.swap(v);
//利用v.reserve()预留空间
}
int main()
{
cout << "Hello World!\n";
test03();
}
3、deque
可以在常数项时间内对头部进行操作,优于vector
分段的连续空间
大部分操作和vector一样,所以下面的代码仅仅写了一点
#include <iostream>
#include<string>
#include<vector>
#include<deque>
using namespace std;
void printDeque(const deque<int>& v)
{
for (deque<int>::const_iterator it = v.begin(); it != v.end(); it++)
{
cout << *it;
}
//iterator普通迭代器
//reverse_iterator反转迭代器
//const_iterator只读迭代器
}
int main()
{
cout << "Hello World!\n";
}
4、stack栈(先进后出)
栈不允许被遍历,也不提供迭代器
#include <iostream>
#include<string>
#include<vector>
#include<deque>
#include<stack>
using namespace std;
void test01()
{
stack<int>s;
//入栈
s.push(1);
s.push(2);
s.push(3);
s.push(4);
s.push(5);
//出栈
while (!s.empty())
{
cout << s.top() << endl;
s.pop();
}
cout << s.size();
}
int main()
{
cout << "Hello World!\n";
test01();
}
5、queue队列(先进先出)
队也没有迭代器,不允许遍历
#include <iostream>
#include<string>
#include<vector>
#include<deque>
#include<stack>
#include<queue>
using namespace std;
class Person
{
public:
Person(int m_age, string m_name) :age(m_age), name(m_name)
{};
int age;
string name;
};
void test01()
{
stack<int>s;
//入栈
s.push(1);
s.push(2);
s.push(3);
s.push(4);
s.push(5);
//出栈
while (!s.empty())
{
cout << s.top() << endl;
s.pop();
}
cout << s.size();
}
void test02()
{
queue<Person>s1;
Person a(11,"aaa");
Person b(22, "bbb");
Person c(33, "ccc");
Person d(44, "ddd");
s1.push(a);
s1.push(b);
s1.push(c);
s1.push(d);
while (!s1.empty())
{
Person p1 = s1.front();
cout << p1.name << p1.age << endl;
Person p2 = s1.back();
cout << p2.name << p2.age << endl;
s1.pop();
}
}
int main()
{
cout << "Hello World!\n";
test02();
}
6、list链表
物理存储单元上非连续非顺序的存储单元,由指针连接一系列的节点构成。list每次插入或者删除一个元素,就是配置或者释放一个元素的空间。因此它对于空间的运用十分精准,绝不浪费,对于任何位置的元素的插入或者元素的移除,永远是常数项时间。list是一个循环的双向链表。
list迭代器是一个双向迭代器,支持前移后移就够了。增加和删除一个元素不会像vector一样,导致迭代器失效。
#include <iostream>
#include<string>
#include<vector>
#include<deque>
#include<stack>
#include<queue>
#include<list>
using namespace std;
void printList(list<int> &v)
{
for (list<int>::iterator it = v.begin(); it != v.end(); it++)
{
cout << *it ;
}
cout << endl;
}
void test01()
{
list<int>mylist;
const list<int>mylist2(10, 1);//mylist2.assign(10,1)一样,如果是.assign修改列表数据,会彻底修改,不是覆盖。
list<int>::const_iterator it = mylist2.begin();//注意迭代器的选择
//还要注意反向迭代器reverse_iterator,用的时候注意与rbegin,rend()搭配,小心错了
mylist.push_back(1);
mylist.push_back(2);
mylist.push_front(3);
mylist.push_front(4);
printList(mylist);
mylist.pop_back();
mylist.pop_front();
printList(mylist);
cout << mylist.size();
cout << mylist.max_size();
cout << mylist.empty();
int ar[] = {10,20,30,40,50};
list<int>mylist3(ar, ar + 5);
list<int>::iterator it3= mylist3.begin();
mylist3.insert(it3,100);
//删除用list.erase()或者clear();
//list1.splice(迭代器,list2)插入
//list1.merge(list2)拼接
}
int main()
{
cout << "Hello World!\n";
test01();
}
7、set容器
set的元素既是键值,又是实值,会根据键值的元素自动进行排序,因此set不允许有两个元素相同的键值。
set的迭代器不能改变set的值,也就是说set的迭代器是const_iterator
set和list有相同的性质,当增加或者删除某个值的时候,之前的迭代器依然有效。
multiset容器允许有相同的元素
set和multiset的底层都是红黑树,红黑树是平衡二叉树的一种。
#include <iostream>
#include<string>
#include<vector>
#include<deque>
#include<stack>
#include<queue>
#include<list>
#include<set>
using namespace std;
void printSet(set<int>&v)
{
for (set<int>::iterator it = v.begin(); it != v.end(); it++)
{
cout << *it<<" ";
}
cout << endl;
}
void test01()
{
set<int>s;
s.insert(10);
pair<set<int>::iterator, bool> ret = s.insert(11);//返回第一个
s.insert(20);
s.insert(40);
s.insert(30);
s.insert(50);
printSet(s);
s.erase(10);
s.erase(s.begin(), s.end());
set<int>::iterator it = s.find(30);//若存在,返回迭代器,若不存在,返回s.end()
// s.count(10);
// s.lower_bound(30);//返回第一个大于等于30的迭代器
//s.upper_bound(30);//返回第一个大于30的迭代器
//pair < set<int>::iterator, set<int>::iterator> it= s.equal_range(30);//用的时候是it.first和it.second
//equal_range是C++ STL中的一种二分查找的算法,lower_bound返回区间的第一个大于等于x的迭代器,
//upper_bound返回区间的第一个大于x的迭代器,而equal_range则是以pair的形式将两者都返回。
//可以用来查询有序区间数字 x 出现的次数。
}
//对组的声明
void test03()
{
//第一种
pair<string, int>p(string("sdfsf"), 18);
cout << "姓名是:" << p.first << "年龄是:" << p.second;
//第二种
pair<string, int>p2 = make_pair(string("sdfsf"), 18);
cout << "姓名是:" << p.first << "年龄是:" << p.second;
}
void test04()
{
//set默认是从小到大排序的,想改为从大到小需要仿函数
class Mycompare
{
bool operator()(int v1, int v2)
{
return v1 > v2;
}
};
set<int, Mycompare> s1;//注意这一步之后,set类型就不仅仅是<int>这么简单了,包括所有的迭代器都要使用set<int,Mycompare>.
}
class Person
{
public:
Person(string m_name,int m_age)
{
this->name = m_name;
this->age = m_age;
}
string name;
int age;
};
class MyComparePerson
{
public:
bool operator()(const Person &p11,const Person &p22)const//这一定要加
{
//升序
return p11.age < p22.age;
}
};
void test05()//自定义数据类型,需要自定义排序规则
{
set<Person,MyComparePerson> s1;
Person p1("aaa",10);
Person p2("bbb", 20);
Person p3("ccc", 30);
Person p4("ddd", 40);
Person p5("eee", 50);
s1.insert(p1);
s1.insert(p2);
s1.insert(p3);
s1.insert(p4);
s1.insert(p5);
for (set<Person, MyComparePerson>::const_iterator it = s1.begin(); it != s1.end(); ++it)
{
cout << "名字:" << (*it).name << " " << "年龄:" << (*it).age << endl;
}
}
int main()
{
cout << "Hello World!\n";
test05();
}
8、map容器
Map 的特性是,所有元素都会根据元素的键值自动排序。Map 所有的元素都是
pair同时拥有实值和键值,pair的第一元素被视为键值,第二元素被视为实值,map不允许两个元素有相同的键值。
map可以修改实值,不能修改键值
map经过增加或者删除元素时,迭代器依然有效。
map键值不可重复,multimap可以。
#include <iostream>
#include<string>
#include<vector>
#include<deque>
#include<stack>
#include<queue>
#include<list>
#include<set>
#include<map>
using namespace std;
void test01()
{
map<int, int>m;
//第一种
m.insert(pair<int,int>(1,10));
//第二种
m.insert(make_pair(2,20));
//第三种
m.insert(map<int, int>::value_type(3, 30));
//第四种,这个一般不用
m[4] = 40;
//m.clear();这个是全部删除
//m.erase(3);根据键值删除指定元素
//查找,返回的也是迭代器
//map<int, int>::iterator pos = m.find(3);
int num = m.count(4);//返回map中key为4的个数。但是map中只有0和1,multimap中存在多个。
//map<int, int>::iterator ret = m.lower_bound(3);//upper_bound()//equal_range()
}
void printMap(map<int,int>& m)
{
for (map<int, int>::iterator it = m.begin(); it != m.end(); it++)
{
cout << "key=" << it->first << " vlaue=" << (*it).second << endl;
}
}
void test01()
{
}
int main()
{
cout << "Hello World!\n";
test01();
}
二、STL容器什么时候用
1)vector的使用场景:只查看,而不频繁插入删除的,因为频繁插入删除会造成内存的不断搬家和删除。使用场景比如软件历史操作记录的存储,我们经常要查看历史记录,比如上一次的记录,上上次的记录,但却不会去删除记录。
2)deque的使用场景:比如排队购票系统,对排队者的存储可以采用deque,支持头端的快速移除,尾端的快速添加。如果采用vector,则头端移除时,会移动大量的数据,速度慢。
vector与deque的比较:
一:vector.at()比deque.at()效率高,比如vector.at(0)是固定的,deque的开始位置却是不固定的。
二:如果有大量释放操作的话,vector花的时间更少,这跟二者的内部实现有关。
三:deque支持头部的快速插入与快速移除,这是deque的优点。3)list的使用场景:频繁的插入删除的场景,或者头尾频繁插入删除,这时也可以使用queue和deque。使用场景比如公交车乘客的存储,随时可能有乘客下车,支持频繁的不确实位置元素的移除插入。
4)set的使用场景:只负责查找内容(当然也会有添加的操作才能有),具体到某个单位,区别于vector一般是某个范围。使用场景比如对手机游戏的个人得分记录的存储,存储要求从高分到低分的顺序排列。
5)map的使用场景:只负责查找内容(当然也会有添加的操作才能有),具体到某个单位,但这个某个单位是在比set更大的范围。使用场景比如按ID号存储十万个用户,想要快速要通过ID查找对应的用户。二叉树的查找效率,这时就体现出来了。如果是vector容器,最坏的情况下可能要遍历完整个容器才能找到该用户。
可能很多人不理解vector,set,map的使用场景。这里再简单举个例子。
当班里有100个人,我们需要不断查看这100个人的数据,这时我们使用vector最好。因为这就是相对于某个范围。
当班里仍有100个人,我们只需要查看某个人的数据,我们这时不使用vector,而应该使用set,这就是相对于具体某个人。
当班里有10000个人时,我们仍只需要查看某个人的数据,我们这时不使用set,而应该使用map,因为某个人在10000这个范围是更加大的,效率更快。
三、函数对象
重载函数调用操作符的类,其对象常称为函数对象( function object
),即它们是行为类似函数的对象,也叫仿函数(functor),其实就是重载“()”操作符,使得类对象可以像函数那样调用。 注意:
1.函数对象(仿函数)是一个线,不是一个函数。 ⒉函数对象(仿函数)重载了”0”操作符使得它可以像函数一样调用。 分类:假定某个类有一个重载的operator() ,而且重载的operator()要求获取一个参数,我们就将这个类称为“一元仿函数”(
unary functor );相反,如果重载的operator()要求获取两个参数,就将这个类称为“二元仿函数”( binary
functor )
函数对象的作用主要是什么?STL提供的算法往往都有两个版本,其中一个版本表现出最常用的某种运算另一版本则允许用户通过template参数的形式来指定所要采取的策略。
谓词:普通函数或者仿函数返回值是bool类型
#include <iostream>
using namespace std;
//函数对象,很像函数调用方式,因此称为仿函数
class MyPrint
{
public:
void operator()(int num)
{
cout << num << endl;
}
};
void test02()
{
MyPrint mp;
mp(11);
}
//2,函数对象,超出普通函数的概念,内部可以拥有自己的状态
class MyPrint
{
public:
void operator()(int num)
{
cout << num << endl;
num++;//状态
}
int num = 0;
};
void test01()
{
MyPrint mp;
mp(11);
}
//3,函数对象可以作为函数的参数传递
void dowork(MyPrint mp,int num1)
{
mp(num1);
}
void test03()
{
dowork(MyPrint(),1000);
}
int main()
{
cout << "Hello World!\n";
test01();
}
四、内建函数对象
STL内建了一些函数对象。分为:算数类函数对象,关系运算类函数对象,逻辑运算类仿函数。这些仿函数所产生的对象,用法和一般函数完全相同,当然我们还可以产生无名的临时对象来履行函数功能。使用内建函数对象,需要引入头文件#include<[functional>。
#include <iostream>
#include<functional>
#include<algorithm>
#include<vector>
using namespace std;
void test01()
{
negate<int>n;
cout << n(10)<<endl;
}
void test02()
{
plus<int>m;
cout << m(10,10) << endl;
}
void test03()
{
vector<int>v;
v.push_back(10);
v.push_back(30);
v.push_back(20);
v.push_back(70);
v.push_back(50);
sort(v.begin(), v.end(), greater<int>());
}
int main()
{
cout << "Hello World!\n";
test01();
test02();
}
五、适配器
#include <iostream>
#include<functional>
#include<algorithm>
#include<vector>
#include<ranges>
using namespace std;
//函数适配器
class myPrint :public binary_function<int, int, void>
{
public:
void operator()(int val, int start)const
{
cout << val + start << endl;
}
};
void test01()
{
vector<int>v;
for (int i = 0; i < 10; i++)
{
v.push_back(i);
}
cout << "请输入一个加的数";
int temp1=0;
cin >> temp1;
for_each (v.begin(), v.end(), bind2nd(myPrint(), temp1));
}
//1,将参数进行绑定 bind2nd
//2,做继承 binary_function<类型1,类型2,返回值类型>
//3,加const
//取反适配器
class Greaterthan5
{
public:
bool operator()(int val)
{
return val > 5;
}
};
void test02()
{
vector<int>v1;
for (int i = 0; i < 10; i++)
{
v1.push_back(i);
}
vector<int>::iterator pos=find_if(v1.begin(),v1.end(),Greaterthan5());
if (pos != v1.end())
{
cout << "找到了,数字是:" << (*pos);
}
else
{
cout << "没找到";
}
}
//下面是取反运算
//一元适配 not1
//继承 unary_function(类型1,返回值类型)
class Greaterthan6:public unary_function<int,bool>
{
public:
bool operator()(int val)const
{
return val > 5;
}
};
void test03()
{
vector<int>v1;
for (int i = 0; i < 10; i++)
{
v1.push_back(i);
}
vector<int>::iterator pos = find_if(v1.begin(), v1.end(),not1 (Greaterthan6()));
if (pos != v1.end())
{
cout << "找到了,数字是:" << (*pos);
}
else
{
cout << "没找到";
}
}
void test04()
{
vector<int>v1;
for (int i = 0; i < 10; i++)
{
v1.push_back(i);
}
int x = 0;
cin >> x;
vector<int>::iterator pos = find_if(v1.begin(), v1.end(), not1(bind2nd(greater<int>(),x)));//这个是内建函数对象,functional
if (pos != v1.end())
{
cout << "找到了,数字是:" << (*pos);
}
else
{
cout << "没找到";
}
}
//函数指针适配器
void myPrint1(int val,int start)
{
cout << val+start;
}
void test05()
{
vector<int>v2;
for (int i = 0; i < 10; i++)
{
v2.push_back(i);
}
int x1 = 0;
cin >> x1;
for_each(v2.begin(), v2.end(), bind2nd(ptr_fun(myPrint1), x1));
}
//成员函数适配器
class Person
{
public:
string s;
int age;
Person(string m_s, int m_age)
{
this->age = m_age;
this->s = m_s;
}
void myPrint1()
{
cout << "姓名:" << s << " 年龄是:" << age<<endl;
}
};
void test06()
{
vector<Person>v1;
Person p1("aaa",111);
Person p2("bbb", 222);
Person p3("ccc", 333);
Person p4("ddd", 444);
Person p5("eee", 555);
v1.push_back(p1);
v1.push_back(p2);
v1.push_back(p3);
v1.push_back(p4);
v1.push_back(p5);
for_each(v1.begin(), v1.end(), mem_fun_ref(&Person::myPrint1));//成员函数引用
}
int main()
{
cout << "Hello World!\n";
test06();
}
六、算法
质变和非质变,(运算过程中,元素内容会不会发生变化)。
算法主要是由头文件 组成。
是所有STL头文件中最大的一个,其中常用的功能涉及到比较,交换,查
找,遍历,复制,修改,反转,排序,合并等…
体积很小,只包括在几个序列容器上进行的简单运算的模板函数
定义了一些模板类,用以声明函数对象。
1、常用遍历算法
#include <iostream>
#include<functional>
#include<algorithm>
#include<vector>
#include<ranges>
using namespace std;
//for_each
void printMy(int v1)//回调函数
{
cout << v1;
}
class MyPrint
{
public:
void operator()(int v1)
{
cout << v1;
}
};
void test01()
{
vector<int>v;
v.push_back(1);
v.push_back(2);
v.push_back(3);
v.push_back(4);
v.push_back(5);
for_each(v.begin(),v.end(),printMy);
for_each(v.begin(), v.end(), MyPrint());
}
//for_each有返回值
class MyPrint1
{
public:
void operator()(int v1)
{
cout << v1;
num++;
}
int num = 0;
};
void test02()
{
vector<int>v;
v.push_back(1);
v.push_back(2);
v.push_back(3);
v.push_back(4);
v.push_back(5);
MyPrint1 mp = for_each(v.begin(), v.end(), MyPrint1());
cout << mp.num << endl;
}
//for_each可以绑定参数进行输出
class MyPrint3:public binary_function<int,int ,void>
{
public:
void operator()(int v1,int start)const
{
cout << v1+start<<endl;
}
};
void test03()
{
vector<int>v;
v.push_back(1);
v.push_back(2);
v.push_back(3);
v.push_back(4);
v.push_back(5);
for_each(v.begin(), v.end(), bind2nd(MyPrint3(),1000));
}
//transform算法将指定容器区间元素搬到另一容器中\
class MyTransform
{
public:
int operator()(int val)
{
return val;
}
};
void test04()
{
vector<int>v;
for (int i = 0; i < 10; i++)
{
v.push_back(i);
}
vector<int>targetv;
targetv.resize(v.size());
transform(v.begin(),v.end(),targetv.begin(),MyTransform());
for_each(targetv.begin(), targetv.end(), [](int val) {cout << val<<endl; });
}
int main()
{
test03();
cout << "Hello World!\n";
}
2、常用查找算法
#include <iostream>
#include<functional>
#include<algorithm>
#include<vector>
#include<ranges>
using namespace std;
//常用查找算法
void test01()
{
vector<int>v;
for (int i = 0; i < 10; i++)
{
v.push_back(i);
}
vector<int>::iterator it = find(v.begin(), v.end(), 5);
if (it != v.end())
{
cout << "找到了";
}
else
{
cout << "没找到";
}
}
class Person
{
public:
Person(string m_name,int m_age)
{
this->name = m_name;
this->age = m_age;
}
string name;
int age=0;
bool operator==(const Person&p)
{
return p.name == this->name && p.age == this->age;
}
};
void test02()
{
vector<Person>v;
Person p1("aaa", 10);
Person p2("bbb", 20);
Person p3("ccc", 30);
Person p4("ddd", 40);
Person p5("eee", 50);
v.push_back(p1);
v.push_back(p2);
v.push_back(p3);
v.push_back(p4);
v.push_back(p5);
vector<Person>::iterator it = find(v.begin(), v.end(), p3);
if (it != v.end())
{
cout << "找到了";
}
else
{
cout << "没找到";
}
}
class MyCompare:public binary_function<Person*,Person*,bool>
{
public:
bool operator()(Person *p1,Person*p2)const
{
return p1->age == p2->age && p1->name == p2->name;
}
};
void test03()
{
vector<Person*>v;
Person p1("aaa", 10);
Person p2("bbb", 20);
Person p3("ccc", 30);
Person p4("ddd", 40);
Person p5("eee", 50);
v.push_back(&p1);
v.push_back(&p2);
v.push_back(&p3);
v.push_back(&p4);
v.push_back(&p5);
find_if(v.begin(),v.end(), bind2nd(MyCompare(),&p3));
}
//查找相邻重复
void test04()
{
vector<int>v;
v.push_back(1);
v.push_back(3);
v.push_back(6);
v.push_back(6);
v.push_back(5);
v.push_back(7);
v.push_back(1);
v.push_back(17);
vector<int>::iterator it = adjacent_find(v.begin(), v.end());
if (it != v.end())
{
cout << "找到了是" << *it<<endl;
}
}
//二分查找法查找某元素是否存在,但是注意必须有序数列
void test05()
{
vector<int>v;
for (int i = 0; i < 10; i++)
{
v.push_back(i);
}
bool ret = binary_search(v.begin(), v.end(),2);
if (ret)
{
cout << "找到了";
}
}
int main()
{
test05();
cout << "Hello World!\n";
}
3、常用排序算法
#include <iostream>
#include<functional>
#include<algorithm>
#include<vector>
#include<ranges>
using namespace std;
//常用排序算法
//合并,但是注意只能合并有顺序的
void test01()
{
vector<int>v1, v2;
for (int i = 0; i < 10; i++)
{
v1.push_back(i);
v2.push_back(i + 1);
}
vector<int>v3;
v3.resize(20);
merge(v1.begin(), v1.end(), v2.begin(), v2.end(), v3.begin());
for_each(v3.begin(), v3.end(), [](int val) {cout << val; });
}
//排序
void test02()
{
vector<int>v1;
for (int i = 0; i < 10; i++)
{
v1.push_back(i);
}
sort(v1.begin(),v1.end(),greater<int>());
for_each(v1.begin(), v1.end(), [](int val) {cout << val; });
}
//随机调整顺序
void test03()
{
vector<int>v1;
for (int i = 0; i < 10; i++)
{
v1.push_back(i);
}
random_shuffle(v1.begin(), v1.end());
for_each(v1.begin(), v1.end(), [](int val) {cout << val; });
}
//反转算法
void test04()
{
vector<int>v1;
for (int i = 0; i < 10; i++)
{
v1.push_back(i);
}
reverse(v1.begin(), v1.end());
for_each(v1.begin(), v1.end(), [](int val) {cout << val; });
}
int main()
{
test04();
cout << "Hello World!\n";
}
4、常用的拷贝和替算算法
#include <iostream>
#include<functional>
#include<algorithm>
#include<vector>
#include<ranges>
using namespace std;
//常用的拷贝和替换算法
class Mycompare
{
public:
bool operator()(int val)
{
return val > 3;
}
};
void test01()
{
vector<int>v;
for (int i = 0; i < 10; i++)
{
v.push_back(i);
}
vector<int>v1;
v1.resize(v.size());
copy(v.begin(),v.end(),v1.begin());
for_each(v1.begin(), v1.end(), [](int val) {cout << val << " " << endl; });
//提升
copy(v1.begin(), v1.end(), ostream_iterator<int>(cout, " "));
//替换
replace(v1.begin(),v1.end(),3,300);
copy(v1.begin(), v1.end(), ostream_iterator<int>(cout, " "));
//按条件进行替换
replace_if(v1.begin(), v1.end(), Mycompare(), 300);
copy(v1.begin(), v1.end(), ostream_iterator<int>(cout, " "));
//交换简单,就是swap(v1,v2);
}
int main()
{
test01();
cout << "Hello World!\n";
}
5、常用算数生成算法
#include <iostream>
#include<functional>
#include<algorithm>
#include<vector>
#include<ranges>
#include<numeric>
using namespace std;
//常用算法生成函数
void test01()
{
vector<int>v;
for (int i = 0; i < 10; i++)
{
v.push_back(i);
}
int num = accumulate(v.begin(), v.end(), 0);//第三个参数是起始累加值
cout << num;
}
//fill算法,向容器中添加元素
void test02()
{
vector<int>v1;
v1.resize(10);
fill(v1.begin(), v1.end(), 100);
copy(v1.begin(), v1.end(), ostream_iterator<int> (cout," "));
}
int main()
{
test02();
cout << "Hello World!\n";
}