STL学习笔记

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";
}

七、迭代器

在这里插入图片描述

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值