当前位置: 首页>后端>正文

C++笔记(基础版)

数据类型:
short 2位 int 4位,long 8位 double 8位
32位系统下指针4位,64位系统下指针8位

空对象占用内存空间1字节
指针:
const修饰指针,即常量指针, 指针指向的值不可修改,但指针的指向可以修改
const int *p = &a; 
*p = 20;  ->error
p = &b;   ->success

const修饰常量,即指针常量,指针指向的值可以修改,但指针的指向不可修改
 int * const p = &a;
*p = 20; ->success;
p = &b; ->error

const 即修饰指针又修饰常量,  指针指向的值不可修改,指针的指向不可修改
const int * const p = &a;

程序基础:

程序编译后,生成exe可执行程序,未执行程序前分为两个区域:

  1. 代码区:存放二进制的机器指令; 它是共享的,只读的
  2. 全局区:存放全局变量、静态变量(static)、字符串常量、const修饰的全局变量
    • 该区域的数据在程序结束后,由操作系统释放

程序运行后,增加了 堆区和栈区

  1. 栈区: 由编译器自动分配和释放,包括:局部变量
    • 注意:不要返回局部变量的地址
  2. 堆区:由程序员管理, 程序结束后操作系统会回收
    • c++利用new 将数据开辟到堆区; 利用delete释放,被释放的堆区空间不可再访问
C++中的引用:
不要返回局部变量的引用,函数结束后局部变量会被释放
int& test01() {
   int a = 10;//局部变量存放在栈区,结束后会被释放
   return a;
}
 int& test02() {
   static int a = 10;
   return a;
}
如果函数调用返回的是引用,可以作为左值
test02() = 1000;

引用的本质:在c++内部,它就是个指针常量  
int a = 10;
int &ref = a; -> 编译器自动转换为: int * const ref = &a; 
ref = 20; ->编译器自动转换为:  *ref = 20;

产量引用:
const int &ref = 20; -> 编译器自动转换为: int temp = 20; const int &ref = temp;
ref = 20;//错误,加入const后变为只读,不可修改
类和对象:
c++中struct和class的区别,
struct的默认权限是public
class的默认权限是private
class可以有模板参数,struct没有
构造函数与析构函数:
class TestAlloc {
public:
    TestAlloc() {
        cout << "默认(无参)构造函数" << endl;
    }
    TestAlloc(int a) {
        cout << "有参构造函数" << endl;
    }
    TestAlloc(const TestAlloc &tt) { //使用const修饰比较规范
        ...赋值操作
        cout << "拷贝构造函数" << endl;
    }
    ~TestAlloc() {
        cout << "dealloc" << endl;
    }
};

注意:
1 调用默认构造函数,不要加()
TestAlloc tt();  -> 会被编译器认为是一个函数的声明,不会认为在创建对象
2 匿名对象不应该单独写
TestAlloc();  ->匿名对象,当前执行结束后系统立即回收匿名对象
3 不要利用拷贝构造方法初始化匿名对象
TestAlloc(tt) -> 编译器会转化为 TestAlloc tt,导致重定义

构造函数的三种写法:
1 括号法
TestAlloc tt(10);
2 显示法
TestAlloc tt = TestAlloc(10);
3 隐式法
TestAlloc tt = 10; ->相当于 TestAlloc tt = TestAlloc(10);
拷贝构造函数的调用时机:
1 用一个已经初始化的对象来初始化一个新对象
TestAlloc t1; 
TestAlloc t2(t1);
2 值传递的方式,给函数参数传值
void make(TestAlloc tt){ 
}
TestAlloc t1; 
make(t1);
3 以值返回方式返回局部对象
TestAlloc make() {
  TestAlloc tt;
  return tt; 
}
TestAlloc t1 =  make();
构造函数的调用规则:
默认情况下,创建一个类,c++编译器会默认给该类添加至少3个函数:默认构造函数、拷贝构造函数、析构函数

手动添加有参构造函数后,编译器将不生成默认构造函数,但仍会生成拷贝构造函数
手动添加拷贝构造函数后,编译器将不生成默认构造函数
深拷贝和浅拷贝:
浅拷贝:简单的赋值拷贝操作
深拷贝:在堆区重新申请空间,进行拷贝操作

浅拷贝带了来的潜在问题:对于有成员变量中有使用了堆区空间,会导致堆区空间被多次释放而奔溃
class Person {
  int age;
  int *value;
  Person(int a, int v) {
    age = a;
    value = new int(v); //开辟了堆区空间
  }
  ~Person() {
    if (value != NULL) {
      delete value;//释放堆区空间
      value = NULL;
    }
  }
}

  Person(const Person &p) {
    age = p.age;
    //value = p.value; -> 浅拷贝默认实现,对于指针类型 这样后续就非常容易出错
    value = new int(*p.value);  -> 手动实现深拷贝
  
  }
};
类的初始化列表
Person(int a, int b int c) :m_A(a), m_B(b), m_C(c) {
}
Person(10 , 20 , 30)
静态成员变量:
1所有对象共享的同一份数据
2编译阶段就分配内存
3类内声明,类外初始化

静态成员函数:
1 函数体内可以访问静态成员变量,不可访问普通成员变量

class Person {
public:
  static int m_a;
  static void func() {
  }
}
int Person::m_a = 200;

1 通过对象进行访问
Person pp;
cout << pp.m_a << endl;;
pp.func();
2 通过类名进行访问
cout << Person::m_a << endl;;
Person::func();
*成员变量、成员函数分开存储:
普通成员变量,属于类的对象上;
普通成员方法,不属于类的对象上;
静态成员变量,不属于类的对象上;
静态普通成员方法,不属于类的对象上;

*this指针:
每一个非静态成员函数只会诞生一份实例,也就是说多个同类型的对象会公用一块代码;
而this指针可以区分 这一块公用的代码是哪个对象进行调用的;
this指针指向被调用的成员函数所属的对象上
class Person {
  int age;
  Persion& addAge(Person &p) { //返回引用也是链式编程思想
    this->age += p.age;
    return *this;
  }
}
Person a(10);
Peron b(10);
a.addAge(b).addAge(b).addAge(b); -> a.age == 40 

*c++中空指针可以调用成员函数,但注意有没有用到this指针;
若函数中使用了this指针,需要保证健壮性
void showAge() {
  if (this == NULL) {//通过判断空指针增加健壮性
    return;
  }
  cout << age << endl;
}
常函数
tip: this指针的本质是指针常量,指针常量不可以修改指针的指向
void showPerson() const   ->在成员函数后面加const,本质修饰的是this指针,让指向的值也不可以修改
{
  age = 1000; -> 出错,无法修改
}
若常函数中还是想修改某一成员变量,则需要声明为multable
multable int age; 

常对象:
const Person A ;  ->常对象,不允许修改成员变量; 故只能调用常函数。
友元
在程序里,有些私有函数 也想让类外特殊的一些函数或类进行访问,则可以用到友元的技术
class Building 
{
   //全局函数作为友元,该函数可以访问Building类的私有成员
  friend void goodGay(Building &b);
  //该类作为友元,该类既可以访问Building类的私有成员
  friend class GodGay; 
  //该类的成员函数访问Building类的私有成员
  friend void GodGay::visit();
}
运算符重载:
对已有的运算符进行定义,赋予其另一种功能,以适应不同的数据类型;
但对于内置的数据类型则不可以使用;
两种方式:成员函数重载、全局函数重载

+号运算符重载
Person operator+ (Person &a, Person &b) {
  Person temp;
  temp.age = a.age + b.age;
  return temp;
}
<<运算符重载 (全局函数)
ostream& operator<<(ostream& out, Person &p) {
  out << "age=" << p.age;
  return out;
}
++运算符重载
class MyInt {
  int m_num;
  MyInt& operator++() {
    m_num++;
    return *this;
  }
  MyInt operator++(int) { //int为占位参数,可以区分为后置递增
    MyInt temp = *this; //这里其实是执行了拷贝构造函数,跟oc不一样的
    this.m_num++;
    return temp;
  }
}
()运算符重载(仿函数)-- 使用方式非常灵活多变
class MyAdd {
  int operator()(int a, int b) {
    return a + b;
  }
}
MyAdd()(100, 200); //匿名函数重载了()运算符

继承
继承方式:
公共继承
保护继承
私有继承
C++笔记(基础版),第1张
c++继承方式.png
子类父类同名成员处理
class Base {
public:
  int m_A;
  void func() {
  }
  void func(int a) {
  }
  static int m_B;
}
int Base::m_B = 1;
class Son: public Base {
public:
  int m_A;
  void func() { 
  }
}
void test() {
  Son sonA;
  cout << sonA.m_A << endl;  ->访问子类的同名成员变量
  cout << sonA.Base::m_A << endl; ->访问父类的同名成员变量
  son.func();
  son.Base::func();
  //son.func(10); ->error,子类出现和父类同名的成员函数,子类会隐藏父类中全部的同名成员函数,包括重载的
  son.Base::func(10);
  Son::Base::m_B; //通过子类取到父类,再访问父类的静态成员变量
}
虚继承
class Son: virtual public Base {

}
C++笔记(基础版),第2张
虚继承原理.png
多态
静态多态:函数重载、运算符重载属于静态多态,复用函数名;编译阶段确定函数地址
动态多态:派生类、虚函数实现运行时多态;运行阶段确定函数地址
class Animal {
public:
  virtual void speak() {  ->加virtual关键字,成为虚函数,编译器在编译阶段不确定执行函数调用了
    cout << "动物speak" << endl;
  }
}
void doSpeak(Animal &ani) {
  ani.speak();
}
class Cat: public Animal {
public:
  void speak() {
        cout << "cat speak" << endl;
  }
}
//动态多态的满足条件
1 有继承关系
2 子类重写父类的虚函数 (注意重写和重载不一样,重写是返回值类型、函数名、参数完全一致为重写)
//动态多态的使用
父类的指针或者引用,执行子类对象

多态优点:
代码组织结构清晰,可读性强
利于扩展与维护
C++笔记(基础版),第3张
多态原理.png
纯虚函数和抽象类
class Base {
public:
  virtual void func() = 0; ->纯虚函数
}
只要有一个纯虚函数,这个类就成为抽象类
抽象类无法实例化对象
抽象类的子类必须重写父类中的纯虚函数,否则也属于抽象类
虚析构和纯虚析构
多态使用时,如果子类中有属性开辟到堆区,那么父类指针在释放时无法调用到子类的析构代码
解决办法:将父类中的析构函数改为虚析构或纯虚析构;(注意使用了纯虚析构,那么该类也会改为抽象类)
virtual ~Base() {  //虚析构
}
virtual ~Base() = 0; //纯虚析构
Base::~Base() { //纯虚析构需要实现
}

文件操作:
通过文件可以将数据持久化

c++中对文件操作需要包含头文件<fstream>
文件类型分为两种:
1. 文本文件 - 以ASCII码存储在计算机中
2. 二进制文件 - 以二进制形式存储

操作文件的三大类:
1. ofstream 写操作
2. ifstream 读操作
3. fstream 读写操作 
模板
c++的泛型编程 主要使用的技术就是模板
c++模板机制:函数模板和类模板
template<typename T> //声明一个模板,告诉编译器后面代码中紧跟着的T不要报错
void mySwap(T &a, T &b) {
    T temp = a;
    a = b;
    b = temp;
}
void  test() {
    string a = "10";
    string b = "20";
    //1 自动推导: 不会发生隐式类型替换
    mySwap(a, b);
    //2 显示指定类型
    mySwap<String>(a,b);
}

//利用具体化的类去实现代码,具体化优先调用
template<> bool myCompare(Person &a, Person &b) {
  if (a.m_age == b.m_age) {
    return true;  
  } else {
    return false;
  }
}
普通函数与函数模板的调用规则
1 如果函数模板和普通函数都可以调用,优先调用普通函数
2 可以通过空模板参数列表强制调用函数模板 
3 函数模板可以发生函数重载
4 如果函数模板可以产生更好的匹配,优先调用函数模板
类模板
template<class NameType, class AgeType>
class Person {
public:
  Person(NameType name, AgeType age) {
    this->m_name = name;
    this->m_age = age;
  }
  NameType m_name;·
  AgeType m_age;
  void showPerson();
}
void test() {
  Person<string, int>p1("lic", 21);
  
}
//成员函数的类外实现写法
template<class T1, class T2>
void Person<T1, T2>::showPerson() {

}
类模板和函数模板的区别:
1 类模板没有自动类型推导的使用方式
2 类模板在模板参数列表中可以有默认参数
template<class NameType, class AgeType = int>

类模板中成员函数和普通类中成员函数创建时机是有区别:
普通类中成员函数一开始就可以创建
类模板中的成员在调用时才创建
类模板对象作为参数
1 指定传入类型 (广泛使用)
void printPerson1(Person<string, int>&p) {
}
2 参数模板化
template<class T1, classT2>
void printPerson2(Person<T1,T2>&p) {
}
3 整个类模板化
template<class T>
void printPerson3(T &p) {
}

STL
STL:标准模板库
从广义上分为:容器(container)、算法(algorithm)、迭代器(iterator)
容器和算法之间通过迭代器进行无缝连接
STL几乎所有的代码都采用了模板类和模板函数

大体分为六大组件:
容器:各种数据结构 vector list deque set map
       (序列式容器、关联式容器)
算法:各种常用的算法 sort find copy for_each
       (质变算法、非质变算法)
迭代器:扮演了容器和算法之间的胶合剂
       (每个容器都有专属的迭代器,类似指针)
仿函数:行为类似函数,可作为算法的某种策略
适配器:一种用来修饰容器或者仿函数或迭代器接口的东西
空间配置器:负责空间的配置与管理
vector

void func(int val) {
    cout << val << endl;
}

void test_vector() {
    vector<int> v;
    v.push_back(10);
    v.push_back(20);
    v.push_back(30);
    v.push_back(40);

    // vector<int>::iterator 拿到vector<int>这种容器的迭代器类型
    vector<int>::iterator pBegin = v.begin();
    vector<int>::iterator pEnd = v.end();

    //第一种遍历方式
    while (pBegin != pEnd) {
        pBegin++;
    }
    //第二种遍历方式
    for(vector<int>::iterator it = v.begin(); it != v.end(); it++) {
        cout << *it << endl;
    }
    //第三种遍历方式
    for_each(v.begin(), v.end(), func);
}


string
string和char*区别:
char*是一个指针
string是一个类,类内部封装了char*,管理这个字符串,是一个char*的容器
string内部还封装了很多成员方法,例如find copy delete insert等
string管理char*所分配的内存

构造函数
string();
string(const char* s);
string(const string& str);
string(int n, char c);//使用n个字符c初始化

赋值
string& assign(const char&s);
string& assign(const char&s, int n);//取前n个字符

字符串拼接
+=(const char*s);
+=(const char c);
+=(const string& str);
string& append(const char *s);
string& append(const char *s, int n);//取前n个字符
string& append(const string &s);
string& append(const string &s, int pos, int n); 取从pos开始的n个字符

查询和替换
int find(const string& str, int pos = 0) const;//查找str第一次出现的位置,从pos开始查找
int find(const char* s, int pos = 0) const;
int find(const char* s, int pos, int n) const;
int find(const char  c, int pos=0) const;

int rfind(const string& str, int pos = 0) const;//查找str最后一次出现的位置,从pos开始查找 (rfind本质是从右往左查)
int rfind(const char* s, int pos = 0) const;
int rfind(const char* s, int pos, int n) const;
int rfind(const char  c, int pos=0) const;

string& replace(int pos, int n, const string& str);
string& replace(int pos, int n, const char*s);

字符串比较
//int: 0:=   1:>  -1:<
int compare(const string&str) const;
int compare(const char *s) const;

字符存取
char& operator[](int n);
char& at(int n);

字符插入和删除
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个字符

子串获取
string substr(int pos = 0; int n = npos)const;//返回从pos开始的n个字符组成的字符串
vector
vector与普通数组的区别:
不同在于数组是静态空间,而vector可以动态扩展
动态扩展:
并不是在原空间之后续新空间,而是找更大的内存空间,然后将原数据拷贝新空间,释放原空间

构造函数:
#include <vector>
#include <algorithm>
vector<int>v1;
vector<int>v2(v1.begin(), v1.end()); //使用v1的区间构造v2
vector<int>v3(10, 100); //使用10个100构造v3
vector<int>v4(v3);  //使用v3拷贝构造v4

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

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

插入和删除
push_back(ele);  //尾部插入元素
pop_back();    //删除最后一个元素
insert(const_iterator pos, ele);  //迭代器指向位置pos插入元素ele, pos是迭代器
insert(const_iterator pos, int count, ele);  //迭代器指向位置pos插入count个元素ele
erase(const_iterator pos); //删除迭代器指向的元素
erase(const_iterator start, const_iterator end);  //删除迭代器从start到end之间的元素
clear();    //删除容器中所有元素

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

互换容器
swap:可以使两个容器互换
利用巧妙收缩内存
vector<int>(v).swap(v);

预留空间
reserve:预留空间,减少vector在动态扩展容量时的扩展次数
v.reserve(10000); 
deque
双端数组,可以对头端进行插入删除操作

deque与vector区别:
vector对于头部的插入删除效率低,数据量越大,效率越低
deque相对而言,对头部的插入删除速度比vector快
vector访问元素时的速度会比deque快

deque实现原理:
内部维护一个中控器,维护每段缓冲区的内容,缓冲区存放真实数据
中控器维护的是每个缓冲区的地址,使得使用deque时像是一片连续的内存空间

void printDeque(const deque<int>&d) {
  for (deque<int>::const_iterator it = d.begin(); it != d.end(); it++) {
  }
}

deque没有容量的概念

插入和删除
push_back(elem);
push_front(elem);
pop_back();
pop_front();
其他操作跟vector基本一致

数据存取
front();  //返回第一个元素
back(); //返回最后一个元素
跟vector基本一致

排序操作 
sort(iterator beg, iterator end);//对beg和end区间的元素进行升序排序

stack
stack是一种先进后出的数据结构,它只有一个出口
只能访问到最后一个元素,不允许有遍历行为

构造函数
stack<T>stk;
stack(const stack &stk);

数据存取
push(elem);//入栈
pop();//出栈
top();//访问栈顶元素

其他操作
empty();
size();//获取栈的元素个数

queue
队列是一种先进先出的数据结构
队列容器允许从一端新增元素,另一端移除元素
只有队头可以被外界访问,不允许有遍历行为
list
链表是一种物理存储单元上非连续的存储结构 ,数据元素的逻辑顺序是通过链表中的指针链接实现的

链表由一系列的结点组成,每个结点分为 数据域和指针域;

STL中的链表是一个双向循环链表:第一个结点的prev指向最后一个结点,最后一个结点的next指向第一个结点

优点:
可以对任意位置进行快速插入或删除元素,修改指针即可,不需要移动大量元素
采取动态存储分配,不会造成内存的浪费和溢出

缺点:
对于容器的遍历速度,没有数组快(数组的内存地址是连续的)
占用的空间比数组大

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

总结,STL中List和vector是两个最常使用的容器


构造函数
list<T> lst;  
list(beg, end);  //通过区间的元素进行构造
list(n, elem);  //n个elem进行构造
list(const list &lst);  //拷贝构造

赋值与交换
assign(beg, end);
assign(n, elem);
list& operator=(const list &list);
swap(lst);

大小操作
size();
empty();
resize(num);
resize(num,elem);

插入和删除
push_back(elem);
pop_back();
push_front(elem);
pop_front();
insert(pos, elem);//在pos位置插入n个elem元素
insert(pos, n, elem);
insert(pos, beg, end);
clear();
erase(beg, end);
erase(pos);
remove(elem);//删除容器中所有与elem值匹配的元素

数据存取
front();
back();

list<int>::iterator it = L1.begin();
it++;//支持双向,但不支持跳跃
it--;
//it = it + 2;  不支持

反转和排序
reverse();//反转
sort(); //排序
//sort(L1.begin(), L1.end()); -> error: 所有不支持随机访问的迭代器容器,不可以用标准算法
//自定义排序
bool myCompare(Person &p1, Person &p2) {
    return p1.m_score > p2.m_score;
}
lst.sort(myCompare);
set/multiset
所有元素都会在插入时自动被排序(默认从小到大)
set/multiset属于关联式容器,底层结构是用二叉树实现

set和multiset区别:
set不允许容器中有重复的元素
multiset则允许

操作
insert(elem);
clear();
erase(pos);
erase(beg, end);
erase(elem);

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

//插入返回pair(对组)
pair<set<int>::iterator, bool> ret = s.insert(0);
if (ret.second) {
  cout<<"成功"<<endl;
}

//通过仿函数可以指定set容易的排序规则
class MyCompare {
public:
  bool operator()(int v1, int v2) {
    return v1 > v2;
  }
}
set<int, MyCompare> set; //需要插入之前设置规则

对于自定义的数据类型,都必须先指定排序规则
对组
pair<type, type> p (value1, value2);
pair<type, type> p = make_pair(value1, value2);

map/multimap
map中所有元素都是pair (key,value)
map所有元素会根据元素的键值自动排序

map/multimap属于关联式容器,底层结构是二叉树实现的

map不允许容器中有重复的key值,multimap则允许

构造
map<int, int> m;
m.insert(pair<int,int> (1,10));

大小和交换
empty();
size();
swap(s);

插入和删除
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;//不建议,可以利用key访问value

erase(m.begin());
erase(elem); //取key
erase(m.begin(), m.end());
clear();

查找和统计
find(key);//返回迭代器,找不到返回end()
count(key);

map<int,int>::iterator pos = m.find(3);
if (pos != m.end()) {
  //找到
}

排序
利用仿函数,修改排序规则; 跟set类似
函数对象
概念:
重载函数调用操作符的类,其对象常称为函数对象
函数对象使用重载的()时,行为类似函数调用,也叫仿函数
本质:
函数对象是一个类,不是一个函数
特点:
函数对象在使用时,可以像普通函数那样调用,可以有参数,可以有返回值
函数对象超出普通函数的概念,函数对象可以有自己的状态
函数对象可以作为参数传递
谓词
概念:
返回bool类型的仿函数称为谓词
如何operator()接收一个参数,则称为一元谓词
如何operator()接收两个参数,则称为二元谓词


内建函数对象
STL提供的函数对象
#include<functional>

算数仿函数
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>

ex:
  negate<int>n;//取反仿函数
  n(50);//对50取消 得出-50
  plus<int>p;
  p(20,30); //20+30 

关系仿函数
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>

ex:
  sort(v.begin(), v.end(), greater<int>()); //通过内建的关系仿函数,调整vector的排序

逻辑仿函数
template<class T> bool logical_and<T>
template<class T> bool logical_or<T>
template<class T> bool logical_not<T>

ex:
  vector<bool> v1;
  v1.push_back(true);
  v1.push_back(false);
  v1.push_back(true);
  v1.push_back(false);

  vector<bool>v2;
  v2.resize(v1.size()); //transform(搬运)前,必须先开辟空间  
  transform(v1.begin(), v1.end(), v2.begin(), logical_not<bool>());
  //使用transform将v1的数组,经过转换,搬运到v2中
STL常用算法
#include<algorithm>
for_each
遍历数组
  ex: for_each(v.begin(), v.end(), function);//function可以为普通函数/仿函数
transform
搬运容器
  ex: transform(v1.begin(), v1.end(), v2.begin(), function);
find
查找元素
  ex: vector<int>::iterator it = find(v.begin(), v.end(), 5); 

  vector<Person>::iterator it = find(v.begin(), v.end(), p);
  //对于自定义数据类型, 需要先重装==
  class Person {
  public:
    bool operator==(const Person& p) {
      return p.age == this->age;  
    }
  }
find_if
按条件查找元素
ex:
class GreaterFive
{
public:
  bool operator()(int a) {
   return a > 5; 
  }
}
vector<int>::iterator it = find_if(v.begin(), v.end(), GreaterFive());//传入谓词

adjacent_find
查找相邻重复元素
ex: vector<int>::iterator it = adjacent(v.begin(), v.end());

binary_search
二分查找:查找指定元素是否存在
bool binary_search(iterator beg, iterator end, value);
查询速度快,但只能在有序的列表中查找

count
统计元素个数
ex: count(v.begin(), v.end(), 50);
对于自定义数据类型,需要先重置==

count_if
按条件统计元素个数
count_if(iterator beg, iterator end, _Pred); 

常用排序算法
sort
对容器内元素进行排序
sort(iterator beg, iterator end, _Pred);

random_shffle
洗牌,指定范围内的元素随机调整次序
random_shuffle(iterator beg, iterator end);
ex:
  srand((unsigned int)time(NULL));//加入随机因子才会真实随机
  random_shuffle(v.begin(), v.end()):

merge
容器元素合并,并存储到另一容器中
原容器必须要是有序的(同样都是升序或降序)

reverse
反转指定范围的元素
首尾对调
拷贝和替换算法
copy
容器内指定范围的元素拷贝到另一容器中
copy(iterator beg, iterator end, iterator dest);
ex:
  vector<int>v1;
  ...
  vector<int>v2;
  v2.resize(v1.size()); //注意提前开辟空间
  copy(v1.begin(), v1.end(), v2.begin());

replace
将区间范围内的旧元素改为新元素
replace(iterator beg, iterator end, oldValue, newvalue);

replace_if
将区间范围内的满足条件的旧元素改为新元素
replace_if(iterator beg, iterator end, _Pred, newvalue);

swap
互换两个容器的元素

常用算术生成算法
#include<numeric>

accumulate
累加区间内的元素

fill
向容器内填充元素
ex: fill(v.begin(), v.end(), 100)
常用的集合算法
set_intersection
获取交集
注意:两个集合必须是有序序列
ex:
vector<int> v1;
vector<int> v2;
...
vector<int> vTarget;
vtarget.resize(min(v1.size(), v2.size());//分配内存
vector<int>::iterator itEnd = set_intersection(v1.begin(), v1.end(), v2.begin(), v2.end(), vTarget.begin()); //返回交集结束的迭代器
for_each(vTarget.begin(), itEnd, myPrint());


set_union
获取并集

set_difference
获取差集
Tool:
获取随机数
srand((unsigned int)time(NULL));
int d = rand()%100+1;

https://www.xamrdz.com/backend/3hs1944472.html

相关文章: