ICode9

精准搜索请尝试: 精确搜索
首页 > 编程语言> 文章详细

C++基础知识

2021-09-27 20:00:30  阅读:97  来源: 互联网

标签:容器 end int back C++ 基础知识 push include


浅拷贝和深拷贝

浅拷贝:简单的赋值拷贝操作;会出现堆区内存重复释放的问题;

深拷贝:在堆区中重新申请内存空间,进行操作;

深拷贝语句:

 Person(const Person &p)
    {
        cout << "拷贝构造函数" << endl;
        age = p.age;
        // 深拷贝
        height = new int(*p.height); // 核心部分
    }

    ~Person()
    {
        // 析构函数将堆区开辟的数据做释放操作
        if (height != NULL)
        {
            delete height;
            height = NULL; // 防止野指针
        }
        cout << "析构函数" << endl;
    }

加号运算符重载

class Person
{
public:
    // 成员函数
    Person operator+(Person &p)
    {
        Person temp;
        temp.a = this->a + p.a;
        temp.b = this->b + p.b;
        return temp;
    }
    int a;
    int b;
};

void test01()
{
    Person p1;
    p1.a = 10;
    p1.b = 10;

    Person p2;
    p2.a = 10;
    p2.b = 10;

    Person p3 = p1 + p2;
    cout << p3.a << p3.b << endl;
}

左移运算符重载

左移运算符重载只能时全局函数,千万不要写成成员函数,如果想访问私有的数据成员,可以将重载函数声明为该类的友元函数

不会利用成员函数重载<<运算符,因为无法实现cout在左侧

// 全局函数
// 返回值时引用类型的
ostream &operator<<(ostream &cout, Person &p) // 做成友元函数即可
{
    cout << "a=" << p.a << " b=" << p.b;
    return cout; // 使用了链式编程思想
}

递增运算符重载(++)

前置++

// 成员函数 
// 重载前置++运算符
    MyInteger operator++()
    {
        // 先++
        m++;
        // 再返回
        return *this;
    }

后置++

// 重载后置++运算符
    //这个int代表一个占位参数,用于区分前置和后置递增
    MyInteger operator++(int)
    {
        // 先记录当时的结果
        MyInteger temp = *this;
        // 再++
        m++;
        // 最后将记录结果返回
        return temp;
    }

赋值运算符的重载

c++编译器至少给一个类提供4个函数

1.默认的构造函数(无参,函数体为空)

2.默认的析构函数(无参,函数体为空)

3.默认的拷贝构造函数,对属性进行值拷贝

4.赋值运算符operator=,对属性进行值拷贝

// 成员函数

Person &operator=(Person &p)
    {
        // 判断是否有属性在堆区,然后再释放,然后再拷贝
        if (age != NULL)
        {
            delete age;
            age = NULL;
        }
        age = new int(*p.age);
        return *this;
    // *解引用
    }

int *age;

关系运算符的重载

// 成员函数
bool operator==(Person &p)
    {
        if (this->name == p.name && this->age == p.age)
        {
            return true;
        }
        return false;
    }
    bool operator!=(Person &p)
    {
        if (this->name != p.name && this->age != p.age)
        {
            return true;
        }
        return false;
    }




函数调用运算符重载

  • 函数调用运算符()也可以重载
  • 由于重载后使用的方式非常像函数的调用,因此称为仿函数
  • 仿函数没有固定的方法,非常灵活
class MyPrint
{
public:
    void operator()(string test) // 类似于函数的使用,称为仿函数
    {
        cout << test << endl;
    }
};

void MyPrint02(string test)
{
    cout << test << endl;
}

// Example2
class myAdd
{
public:
    int operator()(int a, int b)
    {
        return a + b;
    }
};
void test02()
{
    myAdd add;
    add(10, 20);
    cout << myAdd()(10, 10); // 匿名(函数)对象 
}
void MyPrint02(string test)
{
    cout << test << endl;
}

查看对象模型

  1. 打开Developer Command Prompt for vs 2019
  2. 盘符名称加:跳转至文件位置
  3. cd[sapce] 文件名进入文件
  4. dir显示文件夹中的所有文件
  5. 使用命令cl /d1 reportSingleClassLayout[类名][space][文件名]

继承的同名成员处理

子类对象加作用域可以访问到父类同名成员;

如果子类中出现了和父类同名的成员函数,子类的同名成员会隐藏掉父类中所有同名成员函数;

如果想访问到父类被隐藏的同名成员函数,需要加作用域;

#include <iostream>
using namespace std;
class Base
{
public:
    Base()
    {
        a = 100;
        cout << "b构造函数" << endl;
    }
    void func()
    {
        cout << "base " << endl;
    }
    void func(int a)
    {
        cout << "1000000" << endl;
    }
    int a;
};

class Son : public Base
{
public:
    Son()
    {
        a = 200;
        cout << "s构造函数" << endl;
    }
    void func()
    {
        cout << "son " << endl;
    }

    int a;
};
void test01()
{
    // Base b;
    Son s;
    cout << s.Base::a;
}
void test02()
{
    Son s;
    s.Base::func(100);
}
int main()
{
    test02();
}

继承同名静态成员处理方式

  1. 处理方式和继承同名成员处理方式相同;

  2. 可以直接通过类名的方式直接访问,不需要创建对象;

  3. cout << Son::Base::a;
    //第一个::代表通过类名的方式访问 第二个::代表访问父类的作用域下
    

静态多态和动态多态的区别:

静态多态的函数地址早绑定 - 编译阶段确定函数地址;

动态多态的函数地址晚绑定 - 运行阶段确定函数地址;

动态多态的满足条件

  1. 有继承的关系;
  2. 重写父类中的基函数;

动态多态的使用

父类的指针或引用 ,执行子类对象;


纯虚函数和抽象类

只要有一个纯虚函数,这个类称为抽象类

抽象类特点:

  1. 无法实现实例化对象;

  2. 抽象类的子类,必须重写父类中的纯虚函数,否则也属于抽象类也无法实例化对象;


虚析构和纯虚析构

问题:

多态使用时,如果子类中有属性开辟到堆区,那么父类指针在释放时无法调用到子类的析构代码;

解决方式:

将父类中的析构函数改为虚析构或者是纯虚析构;

共性:

可以解决父类指针释放子类对象;

都需要有具体的函数实现;

区别:

如果是纯虚析构,该类属于抽象类,无法实例化对象;

// 虚析构
virtual ~类名(){}

// 纯虚析构
virtual ~类名()=0;

例子:

#include <iostream>
#include <string>
using namespace std;

class Animal
{
public:
    virtual void speak() = 0;
    Animal()
    {
        cout << "Animal构造函数" << endl;
    }
    // 虚析构可以解决,父类指针释放子类对象是不干净的问题

    virtual ~Animal() = 0;
};
// 需要声明,也需要实现;
// 有了纯虚析构函数,也个类也是抽象类,无法实现对象实例化
Animal::~Animal()
{
    cout << "Animal纯需构造函数" << endl;
}

class Cat : public Animal
{
public:
    Cat(string name)
    {
        cout << "Cat构造函数" << endl;

        this->name = new string(name);
    }
    void speak()
    {
        cout << *name << ": 喵喵喵~~~~~" << endl;
    }
    string *name;
    ~Cat()
    {
        cout << "Cat析构函数" << endl;

        if (name != NULL)
        {
            delete name;
            name = NULL;
        }
    }
};

void test01()
{
    Animal *a = new Cat("Tom");
    a->speak();
    // 父类的指针在析构时候,不会调用子类中的析构函数,导致子类如果没有堆区属性,出现内存泄漏

    delete a;
}

int main()
{
    test01();
}

总结:

  1. 虚析构或纯虚析构就是用来解决通过父类指针释放子类对象;
  2. 如果子类中没有堆区数据,可以不写为虚析构或纯虚析构;
  3. 拥有纯虚析构的类也属于抽象类;

文件操作

C++中对文件操作需要包含头文件<fstream>

<ofstream>:写操作

<ifstream>:读操作

<fstream>:读写操作

写文件步骤:

  1. 包含头文件

    #iclude <fstream>

  2. 创建流对象

    ofstream ofs;

  3. 打开文件

    ofs.open(“文件路径”,打开方式);

  4. 写数据

    ofs<<“写入数据”:

  5. 关闭文件

    ofs.close();

文件的打开方式:

打开方式解释
ios::in为读文件而打开文件
ios::out为写文件而打开文件
ios::ate初始位置:文件末尾
ios::app追加方式写文件
ios::trunc如果文件存在先删除,在创建
ios::binary二进制方式

注意:文件的打开方式可以配合使用,利用|操作符;


文件读入的四种方式

利用is_open函数可以判断文件是否打开;

第一种:

 char buf[1024] = {0};

     while (fin >> buf)
     {
        cout << buf << endl;
     }

第二种:

   char buf[1024] = {0};
     while (fin.getline(buf, sizeof(buf)))
     {
         cout << buf << endl;
     }

第三种:

  string buf;
     while (getline(fin, buf))
     {
         cout << buf << endl;
     }

第四种:

 char c;
    while ((c = fin.get()) != EOF) 
    {
        cout << c;
    }
fin.close(); // 读完文件要关闭文件

EOF: End Of File;


普通函数与函数模板调用规则

  1. 如果函数模板和普通函数都可以调用,要先调用普通函数
  2. 可以通过空模板参数列表强制调用函数模板
  3. 函数模板可以发生函数重载
  4. 如果函数模板可以更好的匹配,优先调用函数模板

模板具体化

#include <iostream>
using namespace std;

class Person
{
public:
    Person(string name, int age)
    {
        m_name = name;
        m_age = age;
    }
    string m_name;
    int m_age;
};
template <typename T>
bool myCompare(T &a, T &b)
{
    if (a == b)
    {
        return true;
    }
    else
    {
        return false;
    }
}
// 利用具体化的Person的版本来实现代码具体化会优先调用
template <>
bool myCompare(Person &a, Person &b)
{
    if (a.m_name == b.m_name && a.m_age == b.m_age)
    {
        return true;
    }
    return false;
}

void test01()
{
    int a = 10;
    int b = 20;
    bool result = myCompare(a, b);
    if (result)
    {
        cout << "a==b" << endl;
    }
    else
    {
        cout << "a!=b" << endl;
    }
}
void test02()
{
    Person p1("Tom", 10);
    Person p2("Tom", 10);
    bool result = myCompare<Person>(p1, p2);
    if (result)
    {
        cout << "p1==p2" << endl;
    }
    else
    {
        cout << "p1!=p2" << endl;
    }
}
int main()
{
    test02();
}

类模板和函数模板的区别

  1. 类模板没有自动类型推导的使用方式;
  2. 类模板在模板参数列表中可以有默认参数;

类模板中成员函数创建时机

  • 普通类中的成员函数一开始就创建了;
  • 类模板中的成员函数在调用时才创建;

类模板对象做函数参数

  1. 指定传入的类型 – 直接显示对象的数据类型
  2. 参数模板化 – 将对象中的参数变为模板进行传递
  3. 整个类模板化 – 将这个对象类型模板化进行传递

类模板与继承

  • 当子类继承的父类是一个类模板时,子类在声明的时候,要指定出父类中T的类型
  • 如果不指定,编译器无法给子类分配内存
  • 如果想灵活指定出父类中T的类型,子类也要变为类模板

类模板成员函数类外实现

#include <iostream>
using namespace std;

template <class T1, class T2>
class Person
{
public:
    Person(T1 name, T2 age)
    {
        // this->m_name = name;
        // this->m_age = age;
    }
    T1 m_name;
    T2 m_age;
    void showPerson()
    {
        cout << this->m_name << this->m_age << endl;
    }
};
template <class T1, class T2>
void Person<T1, T2>::showPerson()
{
}

template <class T1, class T2>
Person<T1, T2>::Person(T1 name, T2 age)
{
    this->m_name = name;
    this->m_age = age;
}

Vector

数据类型vector<数据类型> 变量名

使用的头文件:

#include <vector>

#include <algorithm> // 标准算法的头文件

方法:

变量名.push_back(数据) // 尾插法
变量名.begin() // 迭代器的第一个元素
变量名.end() // 迭代器的最后一个元素的下一个位置

三种遍历方法:

#include <iostream>
#include <vector>
#include <algorithm> // 标准算法的头文件
using namespace std;

void test01()
{
    vector<int> v;

    // 向容器中插入数据
    v.push_back(10);
    v.push_back(20);
    v.push_back(30);
    v.push_back(40);
    v.push_back(50);

    // 通过迭代器访问容器中的数据
    // 起始迭代器,指向容器中的第一个元素
    
    vector<int>::iterator itBegin = v.begin();
    // 指向最后一个元素的下一个位置
    vector<int>::iterator itEnd = v.end();
    while (itBegin != itEnd)
    {
        cout << *itBegin << endl;
        itBegin++;
    }
    for (vector<int>::iterator it = v.begin(); it != v.end(); it++)
    {
        cout << *it << endl;
    }
    // 起始 终止 函数
    for_each(v.begin(), v.end(), myPrint); // for_each使用头文件#include <algorithm>
}

void myPrint(int val)
{
    cout << val << endl;
}
int main()
{
    test01();
    return 0;
}

vector存储自定义数据类型:

void test02()
{
    vector<Person *> v; // 存储指针 一般数据类型是去掉指针

    Person p1("aa", 18);
    Person p2("bb", 18);
    Person p3("cc", 18);
    Person p4("dd", 18);
    Person p5("ee", 18);

    v.push_back(&p1);
    v.push_back(&p2);
    v.push_back(&p3);
    v.push_back(&p4);
    v.push_back(&p5);

    for (vector<Person *>::iterator it = v.begin(); it != v.end(); it++)
    {
        // it的数据类型取决于<>中的数据类型
        cout << "name = " << (*it)->m_name << "; age = " << (*it)->m_age << endl;
        // cout << "name = " << it->m_name << "; age = " << it->m_age << endl;
    }
}


Control typeIDCaptionfunction
CDialongDemo
CStaticIDC_TXTI am Waiting….
CButtonBTN_GENClickgen

DLL:Dynamic Linked library


容器嵌套容器

void test01()
{
    vector<vector<int> > v;

    vector<int> v1;
    vector<int> v2;
    vector<int> v3;
    vector<int> v4;

    for (int i = 0; i < 4; i++)
    {
        v1.push_back(i + 1);
        v2.push_back(i + 2);
        v3.push_back(i + 3);
        v4.push_back(i + 4);
    }

    v.push_back(v1);
    v.push_back(v2);
    v.push_back(v3);
    v.push_back(v4);
    for (vector<vector<int> > ::iterator it = v.begin(); it != v.end(); it++)
    {
        for (vector<int>::iterator it2 = (*it).begin(); it2 != (*it).end(); it2++)
        {
            cout << *it2;
        }
        cout << endl;
    }
}

String容器

string构造函数

string(); //创建一个空的字符串
string(const char* s); // 使用字符串s初始化
string(const string& str); // 使用一个string对象初始化另一个string对象
string(int n, char c); // 使用n个字符c初始化

string 赋值操作

string& operator=(const char* s); //char*类型字符串赋值当前的字符串
string& operator=(const string &s); // 把字符串s赋值给当前的字符串
string& operator=(char c); // 字符赋值给当前的字符串

string& assign(const char* s); // 把字符串s赋值给当前的字符串
string& assign(const char* s, int n); // 把字符串s的前n个字符赋值给当前的字符串
string& assign(const string &s); // 把字符串s赋值给当前字符串
string& assign(int n,char c); // 把n个字符c赋给当前字符串

string字符串拼接

string& operator+=(const char* s); // 重载+=操作符
string& operator+=(const string &s); // 重载+=操作符
string& operator+=(const char c); // 重载+=操作符

string& append(const char* s); // 把字符串s连接到当前字符串结尾
string& append(const char* s, int n); // 把字符串s的前n个字符连接到当前字符串结尾
string& append(const string &s); // 同operator+=(const string &str)
string& append(const string &s,int pos,int n); // 字符串s中从pos开始的n个字符连接到字符串结尾

string查找和替换

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 s,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) const; // 替换从pos开始n个字符为字符串str
string& replace(int pos, int n, const char* c) const; // 替换从pos开始的n个字符为字符串s

string比较

比较方式:

字符串比较是按字符的ASCLL码进行对比

相等:返回0;

大于:返回1;

小于:返回-1;

int compare(const string &s) const;
int compare(const char* s) const;

string字符存取

char& operator[](int n); // 通过[]方式取字符
char& at(int n); // 通过at方法获取字符

string插入和删除

string& insert(int pos, const char* s); // 从pos插入字符串
string& insert(int pos, const string* str); // 从pos插入字符串
string& insert(int pos, int n, char c); // 在指定位置插入n个字符c
string& erase(int pos, int n = npos); // 删除从Pos开始的n个字符

string子串

string substr(int pos = 0, int n = npos) const; // 返回由pos开始的n个字符组成的字符串

vector容器

使用时包含头文件:#include <vector>

vector与普通数组区别:

数组是静态的,而vector可以动态扩展;

动态扩展:

并不是在原有空间之后续接新空间,而是找更大的内存空间,然后将原数据拷贝到新空间,释放原空间;

vector容器的迭代器是支持随机访问的迭代器;

vector构造函数

vector<T> v; // 采用模板实现类实现,默认构造函数
vector(v.begin(), v.end()); // 将v[begin(), end()]区间中的元素拷贝给本身
vector(n, elem);  // 构造函数将n个elem拷贝给本身
vector(const vector &vec); // 拷贝构造函数

vector赋值操作

vector& operator=(const vector &vec); // 重载赋值运算符
assign(beg, end);  // 将[beg, end] 区间中的数据拷贝赋值给本身
assign(n, elem); // 将n个elem拷贝赋值给本身

vector容量和大小

empty(); // 判断容器是否为空
capacity(); // 容器的容量
size(); // 返回容器中的元素个数
resize(int num); // 重新指定容器的长度为num,若容器变长,则以默认值(0)填充新位置,如果容器变短,则末尾超出容器长度的元素被删除
resize(int num,elem); // 重新指定容器的长度为num,若容器变长,则以elem值填充新位置,如果容器变短,则末尾超出容器长度的元素被删除

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(); // 删除容器中所有元素

vector数据存取

at(int idx); // 返回索引idx所指的数据
operator[]; // 返回索引idx所指的数据
front();  // 返回容器中第一个数据元素
back();  // 返回容器中最后一个数据元素

vector互换容器

swap(vec); // 将vec与本身的元素互换

内存收缩:

vector<int>(v).swap(v); // 匿名对象分配的内存空间,系统会在该语句执行完自动给释放

vector预留空间

可以减少在动态扩展容量时的扩展次数

reserve(int len); // 容器预留len个元素长度,预留位置不初始化,元素不可访问

统计开辟内存次数:

void test01()
{
    vector<int> v;
    int num;
    int *p = NULL;
    for (int i = 0; i < 100000; i++)
    {
        v.push_back(i);
        if (p != &v[0])
        {
            p = &v[0];
            num++;
        }
    }
    cout << num;
}

deque容器

使用时包含头文件:#include <deque>

双端数组,可以对头端进行插入删除操作;

dequevector区别:

  • vector对于头部的插入删除效率低,数据量越大,效率越低;

  • deque相对而言,对头部的插入删除速度会比vector快;

  • vector访问元素时的速度会比deque快,这和两者内部实现有关;

deque构造函数

deque<T> deqT; // 默认构造形式
deque(beg, end); // 构造函数将[beg, end]区间中的元素拷贝给本身
deque(n, elem); // 构造函数将n个elem拷贝给本身
deque(const deque &dep); // 拷贝构造函数

deque赋值操作

deque& operator=(const deque &deq); // 重载赋值运算符
assign(beg, end); // 将[beg, end]区间中的数据拷贝赋值给本身
assign(n, elem); // 将n个elem拷贝赋值给本身

deque大小操作

deque.empty(); // 判断容器是否为空
deque.size(); // 返回容器中元素的个数
deque.resize(num); // 重新指定容器的长度为num,若容器变长,则以默认值(0)填充新位置,如果容器变短,则末尾超出容器长度的元素被删除
deque.resize(num, elem); // 重新指定容器的长度为num,若容器变长,则以elem值填充新位置,如果容器变短,则末尾超出容器长度的元素被删除

deque插入和删除

push_bakc(elem); // 在容器尾部添加一个数据
push_front(elem); // 在容器头部插入一个数据
pop_back(); // 删除容器中最后一个数据
pop_front(); // 删除容器中第一个数据

insert(pos, elem); // 在pos位置插入一个elem元素的拷贝,返回新数据的位置
insert(pos, n, elem); // 在pos位置插入n个elem数据,无返回值
insert(pos, beg, end); // 在pos位置插入[beg, end)区间的数据,无返回值
clear(); // 清空容器的所有数据
arase(beg, end); // 删除[beg, end)区间的数据,返回下一个数据位置
erase(pos); // 删除pos位置的数据,返回下一个数据的位置

deque数据存取

at(int idx); // 返回索引idx所指的数据
operator[]; // 返回索引idx所指的数据
front(); // 返回容器中第一个数据元素
back(); // 返回容器中最后一个数据元素

deque排序

使用时包含头文件#include <algorithm>

sort(iterator beg, iterator end); // 对beg和end区间内元素进行排序 默认从小到大

随机数种子

#include <ctime>
srand((unsigned int)time (NULL);

stack容器

概念:stack是一种先进后出的数据结构;

栈中只有栈顶的元素才可以被外界使用,因此栈不允许有遍历行为;

stack构造函数

stack<T> stk; // stack采用模板类实现,stack对象的默认构造形式
stack(const stack &stk); // 拷贝构造函数

stack赋值操作

stack& operator=(const stack &stk); // 重载等号操作符

stack 数据存取

push(elem); // 向栈顶添加元素
pop(); // 从栈顶移除第一个元素
top(); // 返回栈顶元素

stack大小操作

empty(); // 判断堆栈是否为空
size(); // 返回栈的大小

queue容器

概念:queue是一种先进先出的数据结构,他有两个出口;

队列容器允许从一端新增元素,从另一端移除元素;

队列中只有对头和队尾可以被外界使用,因此队列不允许有遍历行为;

queue构造函数

queue<T> que; // que采用模板类实现,que对象的默认构造形式
queue(const queue &que); // 拷贝构造函数

queue赋值操作

queue& operator=(const queue &que); // 重载等号操作符

queue数据存取

push(elem); // 向队尾添加元素
pop(); // 从队头移除第一个元素
back(); // 返回最后一个元素
front(); // 返回第一个元素

queue大小操作

empty(); // 判断堆栈是否为空
size(); // 返回栈的大小

list容器

使用头文件#include <list>

由于链表的存储方式并不是连续的内存空间,因此链表list中的迭代器只支持前移和后移,属于双向迭代器;

list的优点:

采用动态存储分配,不会造成内存浪费和溢出;

链表执行插入和删除操作十分方便,修改指针即可,不需要移动大量元素;

list的缺点:

链表灵活,但是空间(指针域)和时间(遍历)额外耗费较大;

List有一个重要的性质,插入操作和删除操作都不会造成原有list迭代器的失效,这在vector是不成立的;

总结:STLListvector是两个最常被使用的容器,各有优缺点;

list构造函数

list<T> lst; // list采用模板类实现,对象的默认构造形式
list(beg, end); // 构造函数将[beg, end)区间中的元素拷贝给本身
list(n, elem); // 构造函数将n个elem拷贝给本身
list(const list &lst); // 拷贝构造函数

list赋值和交换

assign(beg, end); // 将[beg, end)区间中的数据拷贝赋值给本身
assign(n, elem); // 将n个elem拷贝赋值给本身
list& operator=(const list &lst); // 重载等号操作符
swap(lst); // 将lst与本身的元素互换

list大小操作

empty(); // 判断容器是否为空
size(); // 返回容器中元素的个数
resize(num); // 重新指定容器的长度为num,若容器变长,则以默认值(0)填充新位置,如果容器变短,则末尾超出容器长度的元素被删除
resize(num, elem); // 重新指定容器的长度为num,若容器变长,则以elem值填充新位置,如果容器变短,则末尾超出容器长度的元素被删除

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值匹配的元素。

list数据存取

front(); // 返回第一个元素
back(); // 返回最后一个元素

list容器不可以通过[]或at方式访问数据;

list反转和排序

reverse(); // 反转链表
sort(); // 链表排序 (从小到大)成员函数

// 改变sort的排序规则
bool myCompare(int v1, int v2)
{
 	   return v1 > v2;
}
sort(myCompare)

所有不支持随机访问迭代器的容器,不可以使用标准算法;

不支持随机访问迭代器的容器,内部会提供对应的一些算法;

list自定义数据高级排序

自定义数据类型,必须要指定排序规则,否则编译器不知道如何进行排序

#include <iostream>
using namespace std;
#include <list>
#include <string>

class Person
{
public:
    Person(string name, int age, int height)
    {
        this->m_name = name;
        this->m_age = age;
        this->m_height = height;
    }
    string m_name;
    int m_age;
    int m_height;
};
bool comparePerson(Person &p1, Person &p2)
{
    if (p1.m_age == p2.m_age)
    {
        return p1.m_height > p2.m_height;
    }
    return p1.m_age > p2.m_age;
}
void test01()
{
    list<Person> l;
    Person p1("A", 34, 189);
    Person p2("b", 34, 19);
    Person p3("c", 35, 159);
    Person p4("d", 30, 149);
    Person p5("e", 24, 199);
    Person p6("f", 64, 119);

    l.push_back(p1);
    l.push_back(p2);
    l.push_back(p3);
    l.push_back(p4);
    l.push_back(p5);
    l.push_back(p6);
    for (list<Person>::iterator it = l.begin(); it != l.end(); it++)
    {
        cout << it->m_age << it->m_name << it->m_height << endl;
    }
    cout << "排序后" << endl;
    l.sort(comparePerson);
    for (list<Person>::iterator it = l.begin(); it != l.end(); it++)
    {
        cout << it->m_age << it->m_name << it->m_height << endl;
    }
}

int main()
{
    test01();
}

验证迭代器是否支持随机访问:

list<int>::iterator it = l1.begin();
it++; // 支持双向
it--;
it = it + 1; // 不支持随机访问

set/multiset容器

使用时包含头文件#include <set>

所有元素都会再插入时自动排序

set/multiset属于关联式容器,底层结构使用二叉数实现;

setmultiset区别:

set不允许容器中有重复的元素

multiset允许容器中由重复元素

set插入数据的同时会返回插入结果,表示插入是否成功;

multiset不会检测数据,因此可以插入重复数据;

set构造和赋值

set<T> st; // 默认构造函数
set(const set &st); // 拷贝构造函数

set& operator=(const set &st); // 重载等号操作符

set大小和交换

size(); // 返回容器中元素的数目
empty(); // 判断容器是否为空
swap(st); // 交换两个集合容器

set插入和删除

insert(elem); // 在容器中插入元素
clear(); // 清楚所有元素
erase(); // 删除pos迭代器所指的元素,返回下一个元素的迭代器
arase(beg, end); // 删除区间[beg, end)的所有元素,返回下一个元素的迭代器
arase(elem); // 删除容器中值为eleme的元素

set查找和统计

find(key); // 查找key是否存在,若存在,返回该键的迭代器;若不存在,返回set.end()
count(key); // 统计key的元素个数

pair队组创建

成对出现的数据,利用队组可以返回两个数据;

pair<type, type> p (value1, value2);
pair<type, type> p = make_pair(value1, value2);

// value1调用方式:p.first
// value2调用方式:p.second

set容器排序

自定义数据类型排序必须指定排序规则

利用仿函数,可以改变排序规则

#include <iostream>
using namespace std;
#include <set>
class MyCompare
{
public:
    bool operator()(int v1, int v2)
    {
        return v1 > v2;
    }
};
void test01()
{
 
    set<int, MyCompare> s2;

    s2.insert(1);
    s2.insert(2);
    s2.insert(3);
    s2.insert(4);
    s2.insert(6);
    s2.insert(5);
    for (set<int>::iterator it = s2.begin(); it != s2.end(); it++)
    {
        cout << *it << endl;
    }
}

int main()
{
    test01();
}

自定义数据类型排序:

#include <iostream>
#include <set>
using namespace std;
#include <string>

class Person
{
public:
    Person(string name, int age)
    {
        this->m_name = name;
        this->m_age = age;
    }
    string m_name;
    int m_age;
};
class MyCompare
{
public:
    bool operator()(const Person &p, const Person &p2)
    {
        return p.m_age > p2.m_age;
    }
};

void test01()
{
    set<Person, MyCompare> s;
    Person p1("a", 13);
    Person p2("b", 1123);
    Person p3("c", 103);
    Person p4("d", 100);
    Person p5("e", 90);

    s.insert(p1);
    s.insert(p2);
    s.insert(p3);
    s.insert(p4);
    s.insert(p5);
    for (set<Person>::iterator it = s.begin(); it != s.end(); it++)
    {
        cout << it->m_age << it->m_name << endl;
    }
}
int main()
{
    test01();
}


map/multimap容器

简介:
map中所有元素都是pair;
pair中第一个元素为key (键值),起到索引作用,第二个元素为value(实值);
所有元素都会根据元素的键值自动排序;

本质:
map/multimap属于关联式容器,底层结构是用二叉树实现;

优点:
可以根据key值快速找到value值;

map和multimap区别:
map不允许容器中有重复key值元素;
multimap允许容器中有重复key值元素;

使用时包含头文件#include <map>


map构造和赋值

map<T1, T2> mp; // map默认构造函数
map(const map &mp); // 拷贝构造函数

map& operator=(const map &mp); // 重载等号运算符

map大小和交换

size(); // 返回容器中元素的数目
empty(); // 判断容器是否为空
swap(); // 交换两个结合容器

map插入和删除

insert(elem); // 在容器中插入元素
clear(); // 清楚所有元素
erase(pos); // 删除pos迭代器所指的元素,返回下一个元素的迭代器
erase(beg, end); // 删除区间[beg, end)的所有元素,返回下一个元素的迭代器
erase(key); // 删除容器中值为key的元素

插入例子:

m.insert(pair<type1, type2>(value1, value2));
m.insert(make_pair(value1, value2));
m.insert(map<type1, type2>::value_type(value1, value2));
m[key]=value; // 不建议用来插入数据,最好用来访问数据

map查找和统计

find(key); // 查找key是否存在,若存在,返回该键的元素的迭代器;若不存在,返回set.end()
count(key); // 统计key的元素的个数 

map容器排序

利用仿函数,可以改变排序规则

#include <iostream>
#include <map>
using namespace std;
class MyCompare
{
public:
    bool operator()(int v1, int v2)
    {
        return v1 > v2;
    }
};
void test()
{
    map<int, 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 (map<int, int>::iterator it = m.begin(); it != m.end(); it++)
    {
        cout << it->first << " " << it->second << endl;
    }
}
int main()
{
    test();
}

对于自定义类型数据,map必须指定排序规则;


STL-函数对象

概念:

重载函数调用操作符的类,其对象常称为函数对象;

函数对象使用重载的()时,行为类似函数调用,也叫仿函数;

本质:

函数对象(仿函数)是一个类,不是一个函数;

特点:

函数对象在使用时,可以像普通函数那样调用,可以有参数,可以有返回值;

函数对象超出普通函数的概念,函数对象可以有自己的状态;

函数对象可以作为参数传递;

#include <iostream>
using namespace std;
#include <string>
class MyAdd
{
public:
    int operator()(int v1, int v2)
    {
        return v1 + v2;
    }
};
void test()
{
    MyAdd myAdd;
    cout << myAdd(10, 10);
}

class MyPrint
{
public:
    void operator()(string test)
    {
        cout << test << endl;
        this->count++;
    }
    int count;
    MyPrint()
    {
        this->count = 0;
    }
};
void doPrint(MyPrint &mp, string test)
{
    mp(test);
}
void test02()
{
    MyPrint myPrint;
    doPrint(myPrint, "ehllo ");
}
void test01()
{
    MyPrint myPrint;
    myPrint("hwllowe");
    myPrint("hwllowe");
    myPrint("hwllowe");
    myPrint("hwllowe");
    cout << myPrint.count;
}
int main()
{
    test02();
}

谓词

返回bool类型的仿函数称为谓词

如果operator()接受一个参数,那么叫一元谓词;

如果operator()接受两个参数,那么叫二元谓词;

一元谓词

#include <iostream>
#include <vector>
using namespace std;
#include <algorithm>
class GreaterFive
{
public:
    bool operator()(int val)
    {
        return val > 5;
    }
};
void test01()
{
    vector<int> v;
    for (int i = 0; i < 10; i++)
    {
        v.push_back(i);
    }

    vector<int>::iterator it = find_if(v.begin(), v.end(), GreaterFive()); // 使用了匿名的函数对象
    if (it == v.end())
    {
        cout << "未找到" << endl;
    }
    else
    {
        cout << "找到" << endl;
    }
}
int main()
{
    test01();
}

二元谓词

#include <iostream>
#include <vector>
using namespace std;
#include <algorithm>
class GreaterFive
{
public:
    bool operator()(int val, int val1)
    {
        return val > val1;
    }
};
void test01()
{
    vector<int> v;
    v.push_back(15550);
    v.push_back(30);
    v.push_back(1310);
    v.push_back(1310);
    v.push_back(1311230);
    sort(v.begin(), v.end(), GreaterFive());

    for (vector<int>::iterator it = v.begin(); it != v.end(); it++)
    {
        cout << *it << endl;
    }
}
int main()
{
    test01();
}

内建函数对象

这些仿函数所产生的对象,用法和一般函数完全相同;

使用内建函数对象,需要引入头文件#include <functional>

算数仿函数

实现四则运算

其中negate是一元运算,其他都是二元运算;

template<class T> T plus<T>    // 加法仿函数
template<class T> T minus<T>     // 减法仿函数
template<class T> T multiplies<T>     // 乘法仿函数
template<class T> T divides<T>     // 除法仿函数
template<class T> T modulus<T>     // 取模仿函数
template<class T> T negate<T>     // 取反仿函数
#include <iostream>
#include <functional>
using namespace std;

void test()
{
    negate<int> n;
    cout << n(50);
}
void test01()
{
    plus<int> n;
    cout << n(1, 2) << endl;
}

// 其它的用法有一样
int main()
{
    test01();
    system("pause");
}

关系仿函数

实现关系对比

template<class T> bool equal_to<T> // 等于
template<class T> bool not_equal_to<T>     // 不等于 
template<class T> bool greater<T>     // 大于
template<class T> bool greater_equal<T>     // 大于等于
template<class T> bool less<T>     // 小于
template<class T> bool less_equal<T>     // 小于等于
#include <iostream>
#include <functional>
#include <vector>
#include <algorithm>

using namespace std;
class My
{
public:
    bool operator()(int val1, int val2)
    {
        return val1 > val2;
    }
};
void test()
{
    vector<int> v;
    v.push_back(1);
    v.push_back(4);
    v.push_back(6);
    v.push_back(2);
    v.push_back(9);
    for (vector<int>::iterator it = v.begin(); it != v.end(); it++)
    {
        cout << *it << " ";
    }
    cout << endl;
    sort(v.begin(), v.end(), greater<int>());  //  内建函数对象
    for (vector<int>::iterator it = v.begin(); it != v.end(); it++)
    {
        cout << *it << " ";
    }
}
int main()
{
    test();
}

逻辑仿函数

template<class T> bool logical_and<T> // 逻辑与
template<class T> bool logical_or<T> // 逻辑或
template<class T> bool logical_not<T> // 逻辑非
#include <iostream>
#include <vector>
#include <functional>
#include <algorithm>
using namespace std;

void test()
{
    vector<bool> v;
    v.push_back(false);
    v.push_back(true);
    v.push_back(false);
    v.push_back(true);
    v.push_back(false);
    for (vector<bool>::iterator it = v.begin(); it != v.end(); it++)
    {
        cout << *it << " ";
    }

    vector<bool> v2;
    v2.resize(v.size());
    transform(v.begin(), v.end(), v2.begin(), logical_not<bool>());
    for (vector<bool>::iterator it = v.begin(); it != v.end(); it++)
    {
        cout << *it << " ";
    }
}
int main()
{
    test();
}

STL-常用算法

算法主要是由头文件<algorithm>,<functional>,<numeric>组成;

<algorithm>是所有STL头文件中最大的一个,范围涉及到比较、交换、查找、遍历操作、赋值、修改等等;

<functional>体积很小,只包括了在序列上面进行简单数学运算的模块函数;

<numeric>定义了一些模板类,用以声明函数对象;

常用遍历算法

for_each()

for_each(iterator beg, iterator end, _func) //遍历容器
    /*
    beg 开始迭代器;
   	end 结束迭代器
   	_func 函数或者函数对象
   	*/

#include <iostream>
#include <vector>
#include <algorithm>
using namespace std;
void print01(int val)
{
    cout << val << " ";
}
class print02 
{
public:
    void operator()(int val)
    {
        cout << val << " ";
    }
};
void test()
{
    vector<int> v;
    for (int i = 0; i < 10; i++)
    {
        v.push_back(i);
    }
    // for_each(v.begin(), v.end(), print01);
    for_each(v.begin(), v.end(), print02());
}
int main()
{
    test();
}

transform()

transform(iterator beg1, iterator end1, iterator beg2, _func) // 搬运容器到另一个容器中
    /*
    beg1 原容器开始迭代器;
   	end1 原容器结束迭代器
   	beg2 目标容器开始迭代器  使用时目标容器要提前开辟空间(resize())
   	_func 函数或者函数对象
   	*/
    

常用查找算法

find

查找元素,找到返回指定元素的迭代器,找不到返回结束迭代器end();

find(iterator beg, iterator end, value);
// beg 开始迭代器
// end 结束迭代器
// value 查找的元素
#include <iostream>
#include <vector>
#include <algorithm>
using namespace std;
class Person
{
public:
    Person(string name, int age)
    {
        this->m_name = name;
        this->m_age = age;
    }
    bool operator==(const Person &a)
    {
        if (this->m_name == a.m_name && this->m_age == a.m_age)
        {
            return true;
        }
        return false;
    }
    string m_name;
    int m_age;
};
void test01()
{
    vector<Person> v;
    Person p1("aa", 410);
    Person p2("bb", 10);
    Person p3("cc", 120);
    Person p4("dd", 130);
    Person p5("ee", 510);
    v.push_back(p1);
    v.push_back(p2);
    v.push_back(p3);
    v.push_back(p4);
    v.push_back(p5);
    Person pp("bb", 10);
    vector<Person>::iterator i = find(v.begin(), v.end(), pp);
    if (i == v.end())
    {
        cout << "not found" << endl;
    }
    else
    {
        cout << "found it" << endl;
        cout << i->m_name << i->m_age << endl;
    }
}
void test()
{
    vector<int> v;
    for (int i = 0; i < 10; i++)
    {
        v.push_back(i);
    }
    vector<int>::iterator it = find(v.begin(), v.end(), 41);
    if (it == v.end())
    {
        cout << "not found" << endl;
    }
    else
    {
        cout << "found it" << endl;
    }
}
int main()
{
    test01();
}

find_if

按条件查找元素,找到返回指定位置迭代器,找不到返回结束迭代器位置;

find_if(iterator beg, iterator end, _Pred);
// beg 开始迭代器
// end 结束迭代器
// _Pred 函数或者谓词(返回bool类型的仿函数)
#include <iostream>
#include <vector>
#include <string>
#include <algorithm>
using namespace std;

class Person
{
public:
    Person(string name, int age)
    {
        this->m_name = name;
        this->m_age = age;
    }
    bool operator==(const Person &a)
    {
        if (this->m_name == a.m_name && this->m_age == a.m_age)
        {
            return true;
        }
        return false;
    }
    string m_name;
    int m_age;
};
class GreaterFive
{
public:
    bool operator()(int val)
    {
        return val > 5;
    }
};
class GreaterFive01
{
public:
    bool operator()(const Person &val)
    {
        return val.m_age > 5;
    }
};
void test01()
{
    vector<Person> v;
    Person p1("aa", 410);
    Person p2("bb", 10);
    Person p3("cc", 120);
    Person p4("dd", 130);
    Person p5("ee", 510);
    v.push_back(p1);
    v.push_back(p2);
    v.push_back(p3);
    v.push_back(p4);
    v.push_back(p5);
    Person pp("bb", 10);
    vector<Person>::iterator i = find_if(v.begin(), v.end(), GreaterFive01());
    if (i == v.end())
    {
        cout << "not found" << endl;
    }
    else
    {
        cout << "found it" << endl;
        cout << i->m_name << i->m_age << endl;
    }
}
void test()
{
    vector<int> v;
    for (int i = 0; i < 10; i++)
    {
        v.push_back(i);
    }
    vector<int>::iterator i = find_if(v.begin(), v.end(), GreaterFive());

    if (i == v.end())
    {
        cout << "not found" << endl;
    }
    else
    {
        cout << "found it" << endl;
    }
}
int main()
{
    test01();
}

adjacent_find

查找相邻重复元素,返回相邻元素的第一个位置的迭代器;

adjacent_find(iterator beg, iterator end);
// beg 开始迭代器
// end 结束迭代器
#include <iostream>
#include <vector>
#include <algorithm>
using namespace std;

void test()
{
    vector<int> v;
    v.push_back(0);
    for (int i = 0; i < 10; i++)
    {
        v.push_back(i);
    }
    v.push_back(9);

    vector<int>::iterator it = adjacent_find(v.begin(), v.end());
    if (it == v.end())
    {
        cout << "not found" << endl;
    }
    else
    {
        cout << "found it" << endl;
    }
}
int main()
{
    test();
}

binary_search

二分法查找,查找指定的元素,找到返回ture,否则返回false;

注意:无序序列不可用;

bool binary_search(iterator beg, iterator end, value);
// beg 开始迭代器
// end 结束迭代器
// value 查找的元素
#include <iostream>
#include <vector>
#include <algorithm>
using namespace std;

void test()
{
    vector<int> v;
    for (int i = 0; i < 10; i++)
    {
        v.push_back(i);
    }
    bool it = binary_search(v.begin(), v.end(), 4);
    if (!it)
    {
        cout << "not found" << endl;
    }
    else
    {
        cout << "found it" << endl;
    }
}
int main()
{
    test();
}

count

统计元素个数

统计自定义数据类型时,需要配合重载operator==

count(iterator beg, iterator end, value);
// beg 开始迭代器
// end 结束迭代器
// value 统计的元素
#include <iostream>
#include <vector>
#include <algorithm>
#include <string>
using namespace std;
class Person
{
public:
    Person(string name, int age)
    {
        this->m_name = name;
        this->m_age = age;
    }
    bool operator==(const Person &a)
    {
        if (this->m_name == a.m_name && this->m_age == a.m_age)
        {
            return true;
        }
        return false;
    }
    string m_name;
    int m_age;
};
void test01()
{
    vector<Person> v;
    Person p1("aa", 10);
    Person p2("bb", 10);
    Person p3("aa", 10);
    Person p4("dd", 130);
    Person p5("ee", 510);
    v.push_back(p1);
    v.push_back(p2);
    v.push_back(p3);
    v.push_back(p4);
    v.push_back(p5);
    Person p("aa", 10);
    int i = count(v.begin(), v.end(), p);
    cout << i;
}
void test()
{
    vector<int> v;

    v.push_back(40);
    v.push_back(20);
    v.push_back(40);
    v.push_back(50);
    v.push_back(40);

    int it = count(v.begin(), v.end(), 40);
    cout << it << endl;
}
int main()
{
    test01();
}

count_if

按条件统计元素个数

count_if(iterator beg,iterator end, _Pred);
// beg 开始迭代器
// end 结束迭代器
// _Pred 谓词
#include <iostream>
#include <vector>
#include <string>
#include <algorithm>
using namespace std;

class Person
{
public:
    Person(string name, int age)
    {
        this->m_name = name;
        this->m_age = age;
    }

    string m_name;
    int m_age;
};
class GreaterFive
{
public:
    bool operator()(int val)
    {
        return val > 50;
    }
};
class GreaterFive01
{
public:
    bool operator()(const Person &val)
    {
        return val.m_age > 51000;
    }
};
void test01()
{
    vector<Person> v;
    Person p1("aa", 410);
    Person p2("bb", 10);
    Person p3("cc", 120);
    Person p4("dd", 130);
    Person p5("ee", 510);
    v.push_back(p1);
    v.push_back(p2);
    v.push_back(p3);
    v.push_back(p4);
    v.push_back(p5);
    Person pp("bb", 10);
    int i = count_if(v.begin(), v.end(), GreaterFive01());
    cout << i << endl;
}
void test()
{
    vector<int> v;
    for (int i = 0; i < 10; i++)
    {
        v.push_back(i);
    }
    int i = count_if(v.begin(), v.end(), GreaterFive());
    cout << i << endl;
}
int main()
{
    test01();
}

常用排序算法

sort

按值查找元素,找到返回指定位置迭代器,找不到返回结束位置迭代器位置

sort(iterator beg, iterator end, _Pred);
// beg 开始迭代器
// end 结束迭代器
// _Pred 谓词
#include <iostream>
#include <algorithm>
#include <vector>
using namespace std;
void myPrint(int val)
{
    cout << val << " ";
}

void test01()
{
    vector<int> v;
    v.push_back(1);
    v.push_back(4);
    v.push_back(5);
    v.push_back(2);
    v.push_back(9);
    v.push_back(10);
    sort(v.begin(), v.end());
    for_each(v.begin(), v.end(), myPrint);
    sort(v.begin(), v.end(), greater<int>());
    for_each(v.begin(), v.end(), myPrint);
}
int main()
{
    test01();
}

random_shuffle

指定范围内的元素随机调整次序

random_shuffle(iterator beg, iterator end);
// beg 开始迭代器
// end 结束迭代器
#include <iostream>
#include <vector>
#include <algorithm>
#include <ctime>
using namespace std;
void myPrint(int val)
{
    cout << val << " ";
}
void test01()
{
    srand((unsigned int)time(NULL));
    vector<int> v;
    for (int i = 0; i < 10; i++)
    {
        v.push_back(i);
    }
    random_shuffle(v.begin(), v.end());
    for_each(v.begin(), v.end(), myPrint);
}

int main()
{
    test01();
}

merge

两个容器元素合并,并存储到里一个容器中

新的容器要提前分配空间;

merge(iterator beg1, interator end1, iterator beg2, iterator end2, iterator dest);
// 注意:两个容器必须都是有序的
// beg1 容器1开始迭代器
// end1 容器1结束迭代器
// beg2 容器2开始迭代器
// end2 容器2结束迭代器
// dest 目标容器开始迭代器
#include <iostream>
#include <vector>
#include <algorithm>
using namespace std;
void myPrint(int val)
{
    cout << val << " ";
}
void test01()
{
    vector<int> v;
    vector<int> v2;
    for (int i = 0; i < 10; i++)
    {
        v.push_back(i);
        v.push_back(i + 1);
    }
    vector<int> v3;
    v3.resize(v.size() + v2.size());
    merge(v.begin(), v.end(), v2.begin(), v2.end(), v3.begin());
    for_each(v3.begin(), v3.end(), myPrint);
}

int main()
{
    test01();
}

reverse

将容器内元素进行反转

reverse(iterator beg, iterator end);
// beg 开始迭代器
// end 结束迭代器
#include <iostream>
#include <vector>
#include <algorithm>
using namespace std;
void myPrint(int val)
{
    cout << val << " ";
}
void test01()
{
    vector<int> v;
    for (int i = 0; i < 10; i++)
    {
        v.push_back(i);
    }
    reverse(v.begin(), v.end());
    for_each(v.begin(), v.end(), myPrint);
}

int main()
{
    test01();
}

常用拷贝和替换算法

copy

容器中指定范围的元素拷贝到另一个容器中;

目标容器要提前开辟空间;

copy(iterator beg, iterator end, iterator dest);
// beg 开始迭代器
// end 结束迭代器
// dest 目标起始迭代器
#include <iostream>
#include <vector>
#include <algorithm>
using namespace std;
void myPrint(int val)
{
    cout << val << " ";
}
void test01()
{
    vector<int> v;
    for (int i = 0; i < 10; i++)
    {
        v.push_back(i);
    }
    vector<int> v2;
    v2.resize(v.size());
    copy(v.begin(), v.end(), v2.begin());
    for_each(v.begin(), v.end(), myPrint);
    cout << endl;
    for_each(v2.begin(), v2.end(), myPrint);
}

int main()
{
    test01();
}

replace

将容器中指定范围的旧元素修改为新元素

replace(iterator beg, iterator end, oldvalue, newvalue);
// beg 开始迭代器
// end 结束迭代器
// oldvalue 旧元素
// newvalue 新元素
#include <iostream>
#include <vector>
#include <algorithm>
using namespace std;
class MyPrint
{
public:
    void operator()(int val)
    {
        cout << val << " ";
    }
};
void test01()
{
    vector<int> v;
    v.push_back(1);
    v.push_back(2);
    v.push_back(1);
    v.push_back(2);
    v.push_back(1);
    v.push_back(1);
    v.push_back(2);
    v.push_back(1);
    replace(v.begin(), v.end(), 1, 200);
    for_each(v.begin(), v.end(), MyPrint());
}

int main()
{
    test01();
}

replace_if

将区间内满足条件的元素,替换成指定元素

replace(iterator beg, iterator end, _Pred, newvalue);
// beg 开始迭代器
// end 结束迭代器
// _Pred 谓词
// 替换的新元素
#include <iostream>
#include <vector>
#include <algorithm>
using namespace std;
class MyPrint
{
public:
    void operator()(int val)
    {
        cout << val << " ";
    }
};
class Greater
{
public:
    bool operator()(int val)
    {
        return val > 1;
    }
};
void test01()
{
    vector<int> v;
    v.push_back(1);
    v.push_back(20);
    v.push_back(1);
    v.push_back(2);
    v.push_back(1);
    v.push_back(10);
    v.push_back(2);
    v.push_back(11);
    replace_if(v.begin(), v.end(), Greater(), 200);
    for_each(v.begin(), v.end(), MyPrint());
}

int main()
{
    test01();
}

swap

互换两个容器中的元素

swap(container c1, container c2);
// c1 容器1
// c2 容器2
#include <iostream>
#include <vector>
#include <algorithm>
using namespace std;
class MyPrint
{
public:
    void operator()(int val)
    {
        cout << val << " ";
    }
};

void test01()
{
    vector<int> v;

    vector<int> v1;
    for (int i = 0; i < 10; i++)
    {
        v.push_back(i);
        v1.push_back(i + 100);
    }
    v.push_back(999);
    swap(v, v1);
    for_each(v.begin(), v.end(), MyPrint());
    cout << endl;
    for_each(v1.begin(), v1.end(), MyPrint());
}

int main()
{
    test01();
}


常用算数生成算法

使用头文件#include <numeric>

accumulate

计算区间内容器元素累计总和;

accumulate(iterator beg, iterator end, value);
// beg 开始迭代器
// end 结束迭代器
// value 起始值
#include <iostream>
#include <vector>
#include <algorithm>
#include <numeric>
using namespace std;
class MyPrint
{
public:
    void operator()(int val)
    {
        cout << val << " ";
    }
};

void test01()
{
    vector<int> v;

    for (int i = 0; i < 10; i++)
    {
        v.push_back(i);
    }
    int sum = accumulate(v.begin(), v.end(), 0);
    cout << sum << endl;

    for_each(v.begin(), v.end(), MyPrint());
}

int main()
{
    test01();
}

fill

向容器化中填充指定的元素

fill(iterator beg, iterator end, value);
// beg 开始迭代器
// end 结束迭代器
// value 填充的值
#include <iostream>
#include <vector>
#include <algorithm>
#include <numeric>
using namespace std;
class MyPrint
{
public:
    void operator()(int val)
    {
        cout << val << " ";
    }
};

void test01()
{
    vector<int> v;
    v.resize(10);

    fill(v.begin(), v.end(), 1);

    for_each(v.begin(), v.end(), MyPrint());
}

int main()
{
    test01();
}


常用集合算法

set_intersection

求两个容器的交集

注意:

求交集的两个集合必须是有序列的;

目标容器开辟空间需要从两个容器中取最小;

set_intersection返回值既是交集中最后一个元素;

set_intersection(iterator beg1, iterator end1, iterator beg2, iterator end2, iterator dest);
// beg1 容器1开始迭代器
// end1 容器1结束迭代器
// beg2 容器2开始迭代器
// end2 容器2结束迭代器
// dest 目标容器开始迭代器
#include <iostream>
#include <vector>
#include <algorithm>

using namespace std;

void myPrint(int val)
{
    cout << val << " ";
}

void test01()
{
    vector<int> v;
    vector<int> v1;
    for (int i = 0; i < 10; i++)
    {
        v.push_back(i);
        v1.push_back(i + 5);
    }
    vector<int> v2;

    v2.resize(min(v1.size(), v.size()));

    vector<int>::iterator it = set_intersection(v.begin(), v.end(), v1.begin(), v1.end(), v2.begin());

    for_each(v2.begin(), it, myPrint);
}

int main()
{
    test01();
}

set_union

求两个容器的并集

注意:

求交集的两个集合必须是有序列的;

目标容器开辟空间需要从两个容器中之和;

set_union返回值既是交集中最后一个元素;

set_union(iterator beg1, iterator end1, iterator beg2, iterator end2, iterator dest);
// beg1 容器1开始迭代器
// end1 容器1结束迭代器
// beg2 容器2开始迭代器
// end2 容器2结束迭代器
// dest 目标容器开始迭代器
#include <iostream>
#include <vector>
#include <algorithm>

using namespace std;

void myPrint(int val)
{
    cout << val << " ";
}

void test01()
{
    vector<int> v;
    vector<int> v1;
    for (int i = 0; i < 10; i++)
    {
        v.push_back(i);
        v1.push_back(i + 5);
    }
    vector<int> v2;

    v2.resize(v1.size() + v.size());

    vector<int>::iterator it = set_union(v.begin(), v.end(), v1.begin(), v1.end(), v2.begin());

    for_each(v2.begin(), it, myPrint);
}

int main()
{
    test01();
}

set_difference

求两个容器的差集

注意:

求交集的两个集合必须是有序列的;

目标容器开辟空间需要从两个容器中取最大;

set_difference返回值既是交集中最后一个元素;

set_difference(iterator beg1, iterator end1, iterator beg2, iterator end2, iterator dest);
// beg1 容器1开始迭代器
// end1 容器1结束迭代器
// beg2 容器2开始迭代器
// end2 容器2结束迭代器
// dest 目标容器开始迭代器
#include <iostream>
#include <vector>
#include <algorithm>

using namespace std;

void myPrint(int val)
{
    cout << val << " ";
}

void test01()
{
    vector<int> v;
    vector<int> v1;
    for (int i = 0; i < 10; i++)
    {
        v.push_back(i);
        v1.push_back(i + 5);
    }
    vector<int> v2;

    v2.resize(max(v1.size(), v.size()));

    vector<int>::iterator it = set_difference(v1.begin(), v1.end(), v.begin(), v.end(), v2.begin());

    for_each(v2.begin(), it, myPrint);
}

int main()
{
    test01();
}

标签:容器,end,int,back,C++,基础知识,push,include
来源: https://blog.csdn.net/AA209935/article/details/120515974

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有