数据类型:
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可执行程序,未执行程序前分为两个区域:
- 代码区:存放二进制的机器指令; 它是共享的,只读的
- 全局区:存放全局变量、静态变量(static)、字符串常量、const修饰的全局变量
- 该区域的数据在程序结束后,由操作系统释放
程序运行后,增加了 堆区和栈区
- 栈区: 由编译器自动分配和释放,包括:局部变量
- 注意:不要返回局部变量的地址
- 堆区:由程序员管理, 程序结束后操作系统会回收
- 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); //匿名函数重载了()运算符
继承
继承方式:
公共继承
保护继承
私有继承
子类父类同名成员处理
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 {
}
多态
静态多态:函数重载、运算符重载属于静态多态,复用函数名;编译阶段确定函数地址
动态多态:派生类、虚函数实现运行时多态;运行阶段确定函数地址
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 子类重写父类的虚函数 (注意重写和重载不一样,重写是返回值类型、函数名、参数完全一致为重写)
//动态多态的使用
父类的指针或者引用,执行子类对象
多态优点:
代码组织结构清晰,可读性强
利于扩展与维护
纯虚函数和抽象类
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;