C++ STL 常用总结

STL初始

STL基本概念

  • STL(Standard Template Library)标准模板库

  • STL从广义上分,容器(container)、算法(algorithm)、迭代器(iterator)

  • 容器和算法之间通过迭代器进行无缝连接

  • STL几乎所有代码都采用了模板类或者模板函数

函数参数范围都是左闭右开区间

STL六大组件

  1. 容器:各种数据结构,如vector、list、deque、set、map等,用来存放数据

  2. 算法:各种常用算法,如sort、find、copy、for_each等

  3. 迭代器:扮演了容器与算法之间的胶合剂

  4. 仿函数:行为类似函数,可作为算法的某种策略

  5. 适配器:一种用来修饰容器或者仿函数或迭代器接口的东西

  6. 空间适配器:负责空间的配置与管理

STL中的容器、算法、迭代器

容器:置物之所也 就是将运用最广泛的一些数据结构实现出来 常用的数据结构:数组,链表,树,栈,队列,集合,映射表等 这些容器分为序列式容器和关联式容器 序列式容器:强调值的排序,序列式容器中的每个元素均有固定的位置 关联式容器:二叉树结构,各元素之间没有严格的物理上的顺序关系

算法:问题之解也 有限的步骤,解决逻辑或数学上的问题,这一门学科叫算法 算法分为:质变算法和非质变算法 质变算法:是指运算过程中会更改区间内的元素的内容。如拷贝,替换,删除等 非质变算法:是指运算过程中不会更改区间内的元素内容,例如查找,计数遍历,找极值等

迭代器:提供一种方法,能够依序寻访某个容器所含的各个元素,而又无需暴露该容器的内部方式 每个容器都有自己专属的迭代器 迭代器使用非常类似于指针

image.png

常用的容器中迭代器种类为双向迭代器,和随机访问迭代器

容器算法迭代器初识

vector存放内置数据类型

容器:vector 算法:for_each 迭代器:vector<int>::iterator

#include<iostream>
#include<vector>
#include<algorithm>
using namespace std;
​
void MyPrint(int _val)
{
    cout << _val << endl;
}
​
void Test01()
{
    vector<int> v;
​
    v.push_back(10);
    v.push_back(20);
​
    vector<int>::iterator pb = v.begin();
    vector<int>::iterator pe = v.end();
​
    //第一种遍历
    while(pb != pe)
    {
        cout << *pb << endl;
        pb++;
    }
​
    //第二种
    for(vector<int>::iterator it = v.begin(); it != v.end(); it++)
    {
       cout << *it << endl; 
    }
​
    //第三种,#include<algorithm>
    for_each(v.begin(), v.end(), MyPrint);
}
​
int main()
{
    Test01();
}
​
​

vector存放自定义数据类型

#include<iostream>
#include<vector>
#include<string>
using namespace std;
​
class Person()
{
public:
    Preson(string _name, int _age)
    {
        mName = _name;
        mAge = _age;
    }
public:
    string mName;
    int mAge;
}
​
void Test01()
{
    vector<Preson> v;
​
    Preson p1("a", 1);
    Preson p2("b", 2);
​
    v.push_back(p1);
    v.push_back(p2);
    
    for(vector<Preson>::iterator it = v.begin(); it != v.end(); it++)
    {
       cout << (*it).mName << (*it).mAge <<endl; 
    }
}
void Test02()
{
    vector<*Preson> v;
​
    Preson p1("a", 1);
    Preson p2("b", 2);
​
    v.push_back(p1);
    v.push_back(p2);
    
    for(vector<*Preson>::iterator it = v.begin(); it != v.end(); it++)
    {
       cout << (**it).mName << (**it).mAge <<endl; 
    }
}
int main()
{
    Test01();
    Test02();
}

vector容器嵌套容器

vector<vector<int>> v;
vector<int> v1;
vector<int> v2;
for(int i = 0; i < 2; i++)
{
    v1.push_back(i + 1);
    v2.push_back(i + 2);
}
​
for(vector<vector<int>>::iterator it = v.begin(); it != v.end(); it++)
{
    for(vector<int>::iterator vit = (*it).begin(); vit != (*it).end(); vit++)
    {
        cout << *vit << " ";
    }
}

STL常用容器

string容器

构造函数

image.png

  • string(); 创建一个空字符串

  • string(const char* s); 使用字符串s初始化

  • string(const string& s); 使用string对象初始化另一个string对象

  • string(int n, char c); 使用n个字符c初始化

#include<string>
​
string s1;
​
string s2("aaa");
​
 char* str = "bbb";
string s3(str);
​
string s4(10, 'a');

赋值=, assign

image.png

string str1.assign("aaa");
string str2.assign("bbbbbb", 3);
string str3.assign(str1);
string str4.assign(5, "a"
    );

拼接+, append

image.png

image.png

查找和替换find,replace

image.png

rfind从右往左查,find从左往右查。下标位置都是从左开始 替换,会将整个字符串替换进去

string s1 = "111111111";
s1.replace(0, 3, "222");
​
//222111111111

字符串比较compare

字符串比较是按字符的ASCII码进行对比 =返回0

返回1 <返回-1

image.png

有第一个不同的就会结束比较,一般用来判断两个字符串是否相等

字符存取[],at

image.png

字符串插入和删除insert,erase

起始下标从0开始

image.png

子串获取substr

image.png

vector容器

构造函数

vector数据结构和数组非常相似,也称为单端数组 数组是静态空间,vector是动态空间 动态扩展:并不是在原空间之后续接新空间,而是找更大的空间,然后将原数据拷贝新空间,释放原空间 跟realloc有点像

image.png

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

image.png

vector<int> v1;
​
for(int i = 0; i < 10; i++)
{
    v1.push_back(i);
}
​
for(vector<int>::iterator it = v1.begin(); it != v1.end(); it++)
{
    cout << *it << " ";
}
​
vector<int> v2(v1.begin(), v1.end());
vector<int> v3(10, 100);
vector<int> v4(v1);

赋值操作=, assign

image.png

容量和大小empty, capacity, size, resize

image.png

缩小大小,容量不会变化

vector插入和删除insert, push_back, pop_back, erase, clear

image.png

数据存取[], at, front, back

image.png

互换容器swap

image.png

vecto<int> v1;
vector<int> v2;
v1.swap(v2);
​
//收缩内存
vector<int>(v1).swap(v1)
//匿名对象,执行完,系统会回收内存

预留空间reserve

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

image.png

vector<int> v;
int* p = NULL;
int num = 0;

//计算动态扩展了多少次空间
for(int i = 0; i < 100000; i++)
{
    v.push_back(i);
    if(p != &v[0])
    {
        p = &v[0];
        ++num;
    }
}

v.reserve(100000);

deque容器

构造函数

双端数组,可以对头端进行插入删除操作 deque与vector区别

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

  • deque,对头部的插入删除操作更快

  • vector访问元素时的速度更快,与两者的内部实现有关

image.png

内部工作原理:

image.png

deque的迭代器也是支持随机访问的

image.png

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

赋值=,assign

image.png

大小操作empty,size,resize

跟vector比没有容量的概念

image.png

插入和删除

image.png

数据存取at,[],front,back

image.png

deque排序sort

利用算法实现对deque容器进行排序0 需要头文件, algorithm 默认从小到大排序,升序

image.png

stack容器

基本概念

FILO,先进后出。栈中只有顶端元素才可以被外界使用,因此栈不允许有遍历行为

image.png

常用接口

image.png

queue容器

基本概念

先进先出,FIFO,有两个出口

image.png

image.png

常用接口

image.png

list容器

构造函数

将数据进行链式储存 链表是一种物理储存单元上非连续性的存储结构,数据元素的逻辑顺序是通过链表中的指针链接实现的 链表由一系列结点组成 结点:数据域和指针域 STL中的链表是双向循环链表

image.png

链表list中的迭代器只支持前移和后移,属于双向迭代器 优点:

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

  • 齿形插入和删除操作十分方便,修改指针即可,不需要移动大量元素

缺点:

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

list插入删除操作都不会造成原有list迭代器失效,这在vector是不成立的,vector会寻找新的空间

image.png

赋值和交换assign,=,swap

image.png

大小操作size,empty,rsize

image.png

插入和删除

可以直接删除某个值

image.png

数据存取front,back

image.png

image.png

反转和排序reverse,sort

image.png

bool MyCompare(int val1, int val2)
{
    return val1 > val2;
}

List<int> L;

L.reverse();
L.sort();	//默认从小到大
L.sort(MyCompare);	//设定为从大到小排序

set / multiset 容器(集合)

构造和赋值

所有元素插入时自动被排序 set/multiset属于关联式容器,底层结构二叉树实现 只用包含set头文件 set和multiset区别:

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

  • multise中允许容器中有重复元素

image.png

大小和交换size,empty,swap

image.png

插入和删除insert,clear,erase

插入只有insert! 可以直接删除某个值

image.png

查找和统计find,count

count对于set只会是0或1,对multiset不一定

image.png

set<int> s1;

set<int>::iterator pos = s1.find(30);

set和multiset的区别

image.png

set<int> s;
pair<set<int>::iterator, bool> ret = s.insert(10);
if(set.second)
{
    cout << "Successful insertion";
}

multiset<int> ms;
ms.insert(10);
ms.insert(10);

pair对组的创建

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

image.png

pair<string, int> p(string("Tom"), 20);
cout << p.first << p.second;

pair<string, int> p2 = make_pair("Jerry", 10);
cout << p2.first << p2.second;

内置类型指定排序规则

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

class MyCompare()
{
public:
    bool operator()(int v1, int v2)
    {
        return v1 > v2;
    }
};

set<int, MyCompare> s;
s.insert(10);
s.insert(220);
s.insert(50);

for(set<int, MyCompare>::iterator it = s.begin(); it != s.end(); it++)
{
    cout << *it << " ";
}

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

class Person
{
public:
	Person(string _name, int _age)
	{
        name = _name;
        age = _age;
    }

	string name;
	int age;
};

class MyCompare()
{
public: 
    bool operator()(const Person& p1, const Person& p2)
    {
        return p1.age > p2.age;
    }
};

set<Person, MyCompare> s;
s.insert("鲁路修", 16);
s.insert("C.C.", 500);

for(set<Person, MyCompare>::iterator it = s.begin(); it != s.end(); it++)
{
    cout << *it.name << *it.age;
}

map / multimap容器

构造和赋值

高性能,高效率 简介:

  • map中所有元素都是pair

  • pair中第一个元素为key(键值),起到索引作用,第二个元素为value(实值)

  • 所有元素都会根据元素的键值自动排序

本质:

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

优点:

  • 可以根据key值快速找到value值

map和multimap的区别:

  • map不允许容器中有重复key值元素

  • multimap允许容器中有重复key值元素

image.png

大小和交换size,empty,swap

image.png

插入和删除insert,erase,clear

image.png

map<int, int> m;
m.insert(pair<int, int>(1, 10));
m.insert(make_pair(3, 10));
m.insert(map<int, int>::value_type(3, 30));
m[4] = 40;

m.erase(m.begin());
m.erase(3);

通过[]访问不存在的键值,会创建新的键值对,键值为该访问的键值,实值为0

查找和统计find,count

函数原型:

  • find(key); //查找key是否存在,若存在,返回该键的元素的迭代器;若不存在,返回map.end();

  • count(key); //统计key的元素个数

map<int, int> m;
m.insert(pair<int, int>(1, 10));
m.insert(pair<int, int>(2, 10));
m.insert(pair<int, int>(3, 10));

map<int, int>::iteraror pos = m.find(3);
if(pos != m.end())
{
    cout << "yes";
}
else
{
    cout << "no";
}

排序

依旧利用仿函数,更改为自动排序为从大到小排序

class MyCompare()
{
public:
    bool operator()(int v1, int v2)
    {
        return v1 > v2;
    }
}

...

for(map<int, int, MyCompare>::iterator it = m.begin(); it != m.end(); it++)
{
	cout << it -> first << it -> second;
}

STL函数对象

函数对象

image.png

image.png

class MyAdd
{
public:
	int operator()(int v1, int v2)
	{
        return v1 + v2;
    }
}

MyAdd myAdd;
cout << myAdd(1, 2);

class MyPrint
{
public:
	MyPrint()
	{
        count = 0;
    }
	void operator()(string s)
	{
        cout << s << endl;
        count++;
    }

	int count; 	//内部自己的状态
}

Myprint myPrint;
myPrint("纯血的魔女久远寺有珠");
cout << myPrint.count;

void Test(MyPrint& mp, string s)
{
    mp(s);
}

MyPrint mp;
Test(mp, "不要小看人类的觉悟啊");

谓词

一元谓词

image.png

image.png

image.png

使用find_if需要#include<algroithm>

二元谓词

image.png

image.png

内建函数对象

内建函数对象的意义

image.png

算数仿函数

image.png

关系仿函数

image.png

#include<vector>
#include<functional>
#include<algorithm>

vector<int> v;
sort(v.begin(), v.end(), greater<nt>());

逻辑仿函数

image.png

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

vector<bool> v2;
v2.resize(v1.size());

//全部取反了
transform(v1.begin(), v1.end(), v2.begin(), logical_not<bool>());

常用算法

概述

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

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

  • <numeric> 体积很小,只包括几个在序列上面进行简单数学运算的函数模板

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

遍历算法

for_each 遍历

image.png

void Print1(int val)
{
    cout << val;
}

class Print2
{
public:
	void operator()(int val)
	{
        cout << val;
    }
}

for_each(v.begin(), v.end(), Print1);
for_each(v.begin(), v.end(), Print2());

transform 搬运

搬运

image.png

class Transform
{
public:
	int operator()(int val)
	{
        return val;	//除了返回值外,还可以附加其他操作
	}
}

vecter<int> v;
v.push_bacK(1);
v.push_back(2);

vector<int> v2;
v2.resize(v.size());	//提前开辟空间
transform(v.begin(), v.end(), v2.begin(), Transform());

查找算法

find 按值查找

image.png

find_if 按条件查找

image.png

class Compare
{
public: 
	bool operator()(int val)
	{
        return val > 5;
	}
}
find_if(v.begin(), v.end(), Compare())

adjacent_find 查找相邻重复

image.png

binary_search 查找某值是否存在,返回布尔值

image.png

count 统计个数

image.png

class Person
{
public:
	Person(string _name)
	{
        name = _name;
    }

	bool operator==(const Person& p)
	{
        if(name == p.name)
        {
            return true;
        }
        else
        {
            return false;
        }
    }
	string name;
}

vector<Person> v;
Person p1("阿尔托莉雅");
Person p2("冠位人偶师");
Person p3("草食狼");

v.push_back(p1);
v.push_back(p2);
v.push_back(p3);

Person p4("咕哒");

int num = count(v.begin(), v.end(), p4);
cout << "num = " << num;

count_if 按条件统计个数

image.png

排序算法

sort 排序,默认小到大

image.png

random_shuffle 随机打乱顺序

记得加随机数种子 srand((unsigned int)time(NULL));

image.png

merge 合并容器

合并完的容器仍然是有序的 目标容器需要提前开辟空间,大小为两个源容器大小的和

image.png

reverse 反转

image.png

拷贝和替换算法

copy 范围内元素拷贝

目标容器需要提前设置大小

image.png

replace 范围内某元素替换

image.png

replace_if 满足条件的范围内元素替换

image.png

swap 交换

交换的容器要同种类型

image.png

算数生成算法

使用头文件#include <numeric>

accumulate 计算容器元素累计总和

image.png

fill 向容器中添加元素

image.png

一般用来进行后期填充

集合算法

set_intersection 求交集

image.png

vTarget.resize(min(v1, v2));
vector<int>::inerator itEnd = set_intersection(v1.begin(), v1.end(), v2.begin(), v2.end(), vTarget.begin())
for_each(vTarget.begin(), itEnd, myPrint());

重设大小为两个容器中较小的那个即可

set_union 求并集

image.png

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

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

for_each(vT.begin(), itEnd, myPrint);

set_difference 求差集

image.png

//v1 和 v2 的差集

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

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



//v2 和 v1 的差集

vector<int>::iterator it2 = set_difference(v2.begin(), v2.end(), v1.begin(), v1.end(), vTarget.begin()); 
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值