模板、STL标准模板库

模板

通常 对 具有相同要求的结果或者类 提供一个模板,根据实际使用时传过来的数据类型,决定函数和类的具体实现。
模板可以让类或者函数支持一种类型,这种通用类型在实际运行的过程中可以使用任何数据类型。
这种编程方式也成为"泛型编程"。

模板函数

如果函数除了参数类型和返回值类型以外,其他部分全部相同,就可以使用模板来定义函数。

template <typename T> // T:数据类型
template <typename T1, typename T2, …>

#include <iostream>
using namespace std;

template <typename T>		// 模板只对下面的第一个函数有效
T func()					// 参数没有使用模板中的类型,或者无参,不能通过函数调用直接推导出 T 的类型
{							// 需要显性调用模板
    return 38;
}

template <typename T>		// 模板只对下面的第一个函数有效
T func(T a, T b)			// 两个参数都是模板的数据类型,可以通过函数调用推导出模板类型
{							// 隐性调用模板
    return a > b ? a : b;
}

template <typename T1, typename T2>			// 模板只对下面的第一个函数有效
T2 add(T1 a, T1 b)
{	
    T2 num;					// 模板提供的数据类型也可以在函数里面定义变量使用
    return a + b;
}

int main()
{
    int num1 = 9;
    int num2 = 6;

    cout << func<char>() << endl;
    cout << func(num1, num2) << endl;
    cout << func(6, 9) << endl;			// 若用小数,必须每个值都用小数,∵T func(T a, T b)
    cout << add<int, int>(num1, num2) << endl;
    cout << add<float, float>(6, 9) << endl;

    return 0;
}

在这里插入图片描述

模板类

如果要 给模板类的成员函数 实现 类内声明类外定义,需要在类外定义的位置再重写一次模板,并且,类要使用显性调用模板来实现。

#include <iostream>
using namespace std;

// 实现模板类
template <typename T>			// 可以使用 class,也可以使用 typename
class Complex
{
    T real;
    T vir;
public:
    Complex() { }
    Complex(T real, T vir):real(real), vir(vir) { }
    void set_(T real, T vir);  // 模板类中的成员函数,可以实现类内声明,类外定义,需要重写模板
    void show();			   // 模板类中的成员函数也可以在类内定义
};

template <typename T>  		// 只对下面一个模板函数有效
void Complex<T>::set_(T real, T vir)
{
    this->real = real;
    this->vir = vir;
}

template <typename T>		// 只对下面一个模板函数有效
void Complex<T>::show()
{
    cout << real << "+" << vir << "i" << endl;
}

int main()
{
    Complex<int> com(3, 4);
    com.show();
    com.set_(5, 12);
    com.show();
    
    return 0;
}

在这里插入图片描述

STL 标准模板库(Standard Template Library)

https://en.cppreference.com/w/(👈,放心跳转)
在这里插入图片描述

标准模板库(Standard Template Library,STL)是惠普实验室开发的一系列软件的统称。虽说它主要出现到了 C++ 中,但是在被引入 C++ 之前该技术就已经存在了很长时间。
STL 的代码从广义上讲分为三类:algorithm(算法)、container(容器)和 iterator(迭代器),几乎所有的代码都采用了模板类和模板函数的方式,这相比于传统的由函数和类组成的库来说提供了更好的代码重用机会。

C++ Iterators(迭代器)

迭代器是一个特殊的指针,主要用于元素的读写以及遍历。
在这里插入图片描述

找指定位置的迭代器

由于容器类只能找起始位置和结束位置的迭代器,所以只能在已有迭代器的位置上自增,和指针类似。访问元素需要解引用,但是不能像指针类型一样强转。

容器名<数据类型> ::iterator 迭代器名;

迭代器遍历

如果 迭代器不进行修改操作,建议使用只读迭代器 const_iterator,反之使用 iterator。
#include <iostream>
#include <array>
#include <vector>
#include <list>
#include <deque>
#include <map>

using namespace std;


int main()
{
    // string
    string s = "abcdefg";
    for(string::const_iterator iter = s.begin();
        iter != s.end(); iter++)
    {
        cout << *iter;
    }

    cout << endl;
    cout << "-----------" << endl;

    // array
    array<int, 5> arr = {21, 2, 4, 67, 3};
    for(array<int, 5>::const_iterator iter = arr.begin();
        iter != arr.end(); iter++)
    {
        cout << *iter << " ";
    }

    cout << endl;
    cout << "-----------" << endl;
    
    // vector
    vector<string> vec(6, "world");
    for(vector<string>::const_iterator iter = vec.begin();
        iter != vec.end(); iter++)
    {
        cout << *iter << " ";
    }

    cout << endl;
    cout << "-----------" << endl;
    
    // list
    list<string> lis(5, "hello");
    for(list<string>::const_iterator iter = lis.begin();
        iter != lis.end(); ++iter) 		// 等同于 iter++
    {
        cout << *iter << " ";
    }

    cout << endl;
    cout << "-----------" << endl;

    // deque
    deque<string> de(6, "Hola~");
    for(deque<string>::const_iterator it = de.begin();
        it != de.end(); it++)
    {
        cout << *it << " ";
    }

    cout << endl;
    cout << "-----------" << endl;
    
    // map
    map<string, int> ma;
    ma["waistline"] = 66;
    ma["type"] = 1;
    ma["height"] = 188;
    ma["asset"] = 202300;

    for(map<string, int>::const_iterator i = ma.begin();
        i != ma.end(); i++)
    {
        // first 是键(key),second 值(val)
        cout <<  i->first << " " << i->second << endl;
    }
    return 0;
}

在这里插入图片描述

容器(= 顺序容器 + 关联容器)

用来存储数据的集合,数据元素可以是任何类型(因为是使用模板进行实现的)。
容器类的使用,需要引入对应的头文件。
在这里插入图片描述

顺序容器

顺序容器中每个元素均有固定的位置并呈现线性排布,
除非使用删除或者插入的操作改变原来元素的位置。

Array 数组

array 数组是 C++11 新增的容器类型,与传统数组相比更加安全,易于使用。array 数组是定长的。

EXAMPLE
#include <iostream>
#include <string.h>
#include <array>  						// 头文件

using namespace std;

int main()
{
    // 创建一个长度为 5 的 int 数组
    array<int, 5> arr = {1, 2, 3}; 		// 后面两位补零
    cout << arr[0] << endl; 			// 1
    cout << arr[4] << endl; 			// 0
 
    cout << arr.at(2) << endl; 			// 3,推荐使用 at函数(安全)

    arr[3] = 200;

    cout << "------------" << endl;
    // for 循环遍历
    for(int i = 0; i < arr.size(); i++)
    {
        cout << arr.at(i) << endl;
    }

    cout << "------------" << endl;
    // for each 遍历
    for(int i : arr)
    {
        cout << i << endl;
    }
    
    return 0;
}

在这里插入图片描述

Vector 向量

vector 的行为和数组类似,可以理解为顺序表。
vector 内部是由数组实现的,比较适合进行随机的存取操作,不擅长插入和删除操作
vector 不需要判满,动态分配内存:如果存入新的数据,会再开辟一片更大的空间,把原来的内容拷贝过去。
在这里插入图片描述

构造函数

在这里插入图片描述

Functions
bool empty();

在这里插入图片描述

size_type size();

在这里插入图片描述

TYPE at (size_type loc);

在这里插入图片描述

iterator begin();

在这里插入图片描述

iterator end();

在这里插入图片描述

void push_back (const TYPE &val);

在这里插入图片描述

size_type capacity();

在这里插入图片描述

void pop_back();

在这里插入图片描述

TYPE front();

在这里插入图片描述

TYPE back();

在这里插入图片描述

insert 函数

iterator insert (iterator loc, const TYPE &val);
void insert (iterator loc, size_type num, const TYPE &val);
void insert (iterator loc, input_iterator start, input_iterator end);

在这里插入图片描述

assign 函数

void assign (input_iterator start, input_iterator end);
void assign (size_type num, const TYPE &val);
在这里插入图片描述

EXAMPLE
#include <iostream>
#include <vector>
using namespace std;

int main()
{
    vector<int> v1;   		// 调用 vector 的无参构造
    vector<int> v2(5, 3);
    vector<int> v3(v2);   	// 调用拷贝构造
    cout << v1.empty() << endl;		// 判断 v1 是否为空
    cout << "元素个数:" << v2.size() << endl;   	// 输出 v2 容器中元素的个数
    cout << "v2的大小:" << v2.capacity() << endl;  	// 5
    
    v2.push_back(89);				// 尾插
    cout << "元素个数:" << v2.size() << endl;
    cout << "v2的大小:" << v2.capacity() << endl;  // 插入一个元素后,是 10,二倍扩容
    cout << "V2中的元素:" << endl;
    v2.push_back(89);
    cout << "\t push 后元素个数:" << v2.size() << endl;
    v2.pop_back();
    cout << "\t pop 后元素个数:" << v2.size() << endl;
    cout << "v2的大小:" << v2.capacity() << endl;
    
    v2.front() = 45;
    v2.back() = 78;

    // 在第三个位置前插入元素,需要用到 insert 函数
    vector<int>::iterator pos = v2.begin()+2;
    v2.insert(pos, 29);
    vector<int>::iterator temp;   // 定义一个可以遍历 <int> 模板的 vector 容器的迭代器
    for (temp = v2.begin(); temp != v2.end(); temp++)
        cout << *temp << "\t";  //对迭代器解引用操作,访问到具体的元素
    cout << endl;
    
    cout << *(v2.end()-1) << endl;
    
    /*cout << v2.front() << endl;  		// 返回对象的引用
    cout << v2.back() << endl;*/
    
    cout << v2.size() << endl;
    pos = v2.begin()+4;  		// 和指针的操作相同,从第一个迭代器找下一个迭代器直接 +1
    temp = v2.end();
    v2.assign(pos, temp);
    for (temp = v2.begin(); temp != v2.end(); temp++)
    {
        cout << *temp << "\t";  //对迭代器解引用操作,访问到具体的元素
    }
    cout << endl;

    return 0;
}

在这里插入图片描述

( begin / end ) v.s. ( front / back )

begin 和 end 成员函数,返回起始位置和结尾位置的迭代器;
front 和 back 成员函数,返回起始位置和结尾位置的引用。

vector 的二倍扩容

vector<int> v2(5, 3); // 第一次开辟 5 个 int 型 大小(5个3)
v2.push_back(89); // v2 容器中元素满,再插入 89,则再开辟 5 个 int 型 大小
// 若再满,再插入,则再开辟 10 个 int 型 大小。然后是 20,40…以此类推。

List 双向链表

list 内部有双向循环链表的实现,内存空间不连续,不支持下标。
可以进行高效的删除和添加操作,但是不适合随机存取。

#include <iostream>
#include <list> 				// 头文件
using namespace std;

int main()
{
    // 创建一个默认无数值的 list
    // list<string> lis1;

    // 创建一个长度为 2 的列表,第一个元素 "hello",第二个元素 "world"
//    list<string> lis2{"hello", "world"};
//    for(string s : lis2)
//    {
//        cout << s << endl;
//    }

    // 创建一个长度为 5 的列表,每个元素都是 "hello"
    list<string> lis(5, "hello");

    // 增
    lis.push_back("world"); 			// 向后追加单元素
    lis.push_front("hahaha"); 			// 向前追加单元素
    lis.insert(++lis.begin(), "222"); 	// 在第二个位置上插入"222"

    for (list<string>::iterator iter = lis.begin(); iter != lis.end(); iter++)
        cout << *iter << ", ";
    cout << endl << "----------------" << endl;

    // 删
    lis.pop_back(); 			// 删除最后一个元素
    lis.pop_front(); 			// 删除第一个元素


    // 迭代器
    list<string>::iterator iter = lis.begin();
    advance(iter, 1); 			// 移动迭代器指针到固定位置
    lis.insert(iter, "333");

    lis.push_back("world"); // 向后追加单元素
    // 删除最后一个元素
    iter = lis.end();
    iter--;
    lis.erase(iter);

    // 删除
    iter = lis.begin();
    advance(iter, 1);
    lis.erase(iter);

    // 返回最后一个元素
    cout << "The last: " << lis.back() << endl;
    // 返回第一个元素
    cout << "The first: " << lis.front() << endl;

    cout << "----------------" << endl;
    // 不能用普通循环遍历,因为不支持下标
    for(string s : lis)
    {
        cout << s << endl;
    }

    cout << "Size = " <<lis.size() << endl;
    lis.clear();
    cout << "Size = " << lis.size() << endl;

    return 0;
}

在这里插入图片描述

Deque 双端队列

队列几乎支持所有 vector 的API,性能位于 vector 与 list 二者之间,是擅长两端存取的顺序容器。

#include <iostream>
#include <deque>			// 头文件
using namespace std;

int main()
{
    
//    deque<int> v(5);
//    for(int i : v)
//    {
//        cout << i << endl;
//    }
    
    // 创建一个长度为 5 的 int 向量
    deque<int> vec = {1, 2, 3, 4, 5};

    // 增
    // 向后追加一个元素
    vec.push_back(222);
    // cout << vec.size() << endl;
    // begin()可以返回指向第一个元素的迭代器指针,+2是在第三个位置上插入333
    vec.insert(vec.begin()+2, 333); // 1 2 333 3 4 5 222

    // 删
    // 删除最后一个元素
    vec.pop_back(); 				// 1 2 333 3 4 5

    // 删除第二个元素
    vec.erase(vec.begin() + 1);		// 1 333 3 4 5

    // 删除倒数第二个元素
    vec.erase(vec.end() - 2); 		// 1 333 3 5

    // 改
    vec.at(2) = 666; 				// 1 333 666 5
    vec[1] = 222;   				// 1 222 666 5

    // 查
    cout << vec.at(1) << endl;
    cout << vec[0] << endl;

    // 遍历
    for(int i :vec)
    {
        cout << i << " ";
    }

    cout << endl;
    cout << "-----------" << endl;

    for(int i = 0; i < vec.size(); i++)
    {
        cout << vec[i] << " " ;
    }
    
    cout << endl;
    cout << "-----------" << endl;
    
    // 判断是否为空,0:非空 1:空
    cout << vec.empty() << endl;

    // 清空
    vec.clear();
    cout << vec.empty() << endl;
    
    return 0;
}

在这里插入图片描述

关联容器

关联容器的各元素之间没有严格的顺序,虽然内部具有排序特点,但在使用时没有任何顺序相关接口。
最常见的关联容器就是 map —— 键值对映射。

Map

对于 map 而言,键具有唯一性,键通常使用字符串类型,
值可以是任何类型,通过键可以找到对应的值。
在这里插入图片描述

#include <iostream>
#include <map> 					// 头文件
using namespace std;

int main()
{
    // 列表初始化创建 c++11 支持
//    map<string, int> ma1 = {{"年龄", 5}, {"身高", 200}};
//    cout << ma1.size() << endl; 					// 2
    
    // 创建一个元素为 0 的键值对对象
    map<string, int> ma;
    cout << ma.size() << endl;
    ma["height"] = 185; 							// 插入元素
    ma.insert(pair<string, int>("weight", 140)); 		// 插入元素

    // 查
    cout << "Height: " << ma["height"] << endl;
    cout << "Weight: " << ma["weight"] << endl;
    
    // 改
    ma["height"] = 188;
    cout << "Height: " << ma["height"] << endl;

    // 删
    if(ma.find("weight") == ma.end())
    {
        cout << "Cannot find the key named \"weight\"! "<< endl;
    }
    else
    {
       int re = ma.erase("weight");
       cout << "Succeeded or not: " << re << endl;
    }

    cout << ma.size() << endl;
    
    ma.clear();
    cout << ma.size() << endl;
    
    return 0;
}

在这里插入图片描述

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/215026.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

景联文科技解读《2023人工智能基础数据服务产业发展白皮书》,助力解决数据标注挑战

前段时间&#xff0c;国家工业信息安全发展研究中心发布《2023人工智能基础数据服务产业发展白皮书》&#xff08;以下简称“白皮书”&#xff09;。 《白皮书》指出&#xff0c;2022年&#xff0c;中国人工智能基础数据服务产业的市场规模为45亿元&#xff0c;预计今年将达到5…

GEE:不同方向的线性检测算子

作者:CSDN @ _养乐多_ 本文将介绍在 Google Earth Engine(GEE)平台上,使用不同方向的线性检测算子进行卷积操作的代码框架、核心函数和多种卷积核,比如 E-W、NE-SW、N-S、NW-SE 方向检测算子等。 结果如下图所示, 文章目录 一、定向检测算子二、完整代码三、代码链接一…

2.1 Linux C 编程

一、Hello World 1、在用户根目录下创建一个C_Program&#xff0c;并在这里面创建3.1文件夹来保存Hellow World程序&#xff1b; 2、安装最新版nvim ①sudo apt-get install ninja-build gettext cmake unzip curl ②sudo apt install lua5.1 ③git clone https://github.…

【MySQL的DQL查询语句】

MySQL的DQL查询语句-----在Navicat下 将学生表导入Navicat中查询语句查询一整张表查询年龄大于22年龄大于22的女生查找文科的学生查找六班的学生计算学生的总分 &#xff08;group by&#xff09;合并两表 &#xff08;join on xxxx&#xff09;合并两张表 并求总分先合并在聚合…

JOSEF约瑟时间继电器ARTD-DC110V-2H2D 0.25-2.5s导轨安装

ARTD系列断电延时继电器&#xff1a; ARTD-220VDC-1H1D断电延时继电器&#xff1b;ARTD-220VDC-2H断电延时继电器&#xff1b; ARTD-220VDC-2H2D断电延时继电器&#xff1b;ARTD-220VDC-4H断电延时继电器&#xff1b; ARTD-110VDC-1H1D断电延时继电器&#xff1b;ARTD-110VD…

中介者模式 rust和java的实现

文章目录 中介者模式介绍实现javarustrust仓库 中介者模式 中介者模式&#xff08;Mediator Pattern&#xff09;又被称为 调停者模式 。 它定义了一个中介对象来封装一系列对象之间的交互关系。 中介者使各个对象之间不需要显式地相互引用&#xff0c;从而使耦合性降低&#…

CSS实现小球边界碰撞回弹

如何通过CSS实现一个物体在屏幕中无限的边界碰撞回弹呢&#xff1f;我们可以使用动画效果实现 代码 我们只做一个小球&#xff0c;通过定位属性叠加动画的方式&#xff0c; 让小球在屏幕中进行运动&#xff0c;通过设置animation的alternate属性来设置回弹。最后&#xff0c;只…

时间序列数据压缩算法简述

本文简单介绍了时间序列压缩任务的来源&#xff0c;压缩算法的分类&#xff0c;并对常见压缩算法的优缺点进行了简介&#xff0c;爱码士们快来一探究竟呀&#xff01; 引言 时间序列数据是在许多应用程序和领域中生成的一种基本数据类型&#xff0c;例如金融、医疗保健、交通和…

Failed to connect to gitee.com port 443: Time out 连接超时提示【Bug已完美解决-鸿蒙开发】

文章目录 项目场景:问题描述原因分析:解决方案:解决方案1解决方案2:解决方案3:此Bug解决方案总结解决方案总结**心得体会:解决连接超时问题的三种方案**项目场景: 导入Sample时遇到导入失败的情况,并提示“Failed to connect to gitee.com port 443: Time out”连接超…

Git:分布式版本控制系统的崛起与演变

简介 Git是一个开源的分布式版本控制系统&#xff0c;旨在有效、高速地处理从很小到非常大的项目版本管理。它是由Linus Torvalds于2005年创建的&#xff0c;最初是为了服务于Linux内核开发的版本控制需求。Git通过强大的分支功能、高效的缓存机制以及可扩展的架构设计&#xf…

分享81个节日PPT,总有一款适合您

分享81个节日PPT&#xff0c;总有一款适合您 81个节日PPT下载链接&#xff1a;https://pan.baidu.com/s/1V0feg5pZ8C1Szycy40CrUw?pwd6666 提取码&#xff1a;6666 Python采集代码下载链接&#xff1a;采集代码.zip - 蓝奏云 学习知识费力气&#xff0c;收集整理更不易…

BGP多跳及BGP4+

一、知识补充 1、BGP4 传统BGP-4只管理IPV4路由信息&#xff0c;对于使用其它网络程协议 (若IPV6等)的应用末给予支持。IETF对BGP-4扩展&#xff0c;提出BGP4&#xff0c;可以提供对IPV6、IPX和MPLS VPN的支持 (简单说: 扩展IPV6协议栈支持)。 2、全互联 在上一篇博文中提…

爬虫学习(一)

文章目录 文件目录结构打开文件操作 爬取网页的理解尝试 文件目录结构 打开文件操作 爬取网页的理解尝试 这个放回值为请求正常

C语言扫雷游戏

提示&#xff1a;文章写完后&#xff0c;目录可以自动生成&#xff0c;如何生成可参考右边的帮助文档 文章目录 前言一、扫雷游戏的分析和设计1.1扫雷游戏的功能说明1.2数据结构的分析1.3文件结构设计 二、扫雷游戏的代码实现总结 前言 详细介绍扫雷游戏的思路和实现过程。 一…

泊车功能专题介绍 ———— 记忆泊车评价规程(征求意见稿)

文章目录 评价方法指标体系指标权重分配算分方法指标得分计算方法露天停车场一键召唤得分情况说明泊出能力得分情况说明水平划线车位——两侧存在静止车辆水平划线车位——两侧存在静止车辆且车位附近有静止直立儿童垂直划线车位——两侧存在静止车辆垂直划线车位——两侧存在静…

智能优化算法应用:基于JAYA算法无线传感器网络(WSN)覆盖优化 - 附代码

智能优化算法应用&#xff1a;基于JAYA算法无线传感器网络(WSN)覆盖优化 - 附代码 文章目录 智能优化算法应用&#xff1a;基于JAYA算法无线传感器网络(WSN)覆盖优化 - 附代码1.无线传感网络节点模型2.覆盖数学模型及分析3.JAYA算法4.实验参数设定5.算法结果6.参考文献7.MATLAB…

Java基础语法之数组

数组的定义与初始化 数组的创建 大体上有如下三种创建方式&#xff1a; int[]array1 {1,2,3,4,5}; int[]array2 new int[]{1,2,3,4,5}; int[]array3 new int[5];一般创建框架就是T[ ]new T[ ];T是数组中元素的类型&#xff0c;T[ ]是数组类型 如果是double[],则对应new …

34、AD/DA

AD/DA介绍 AD&#xff08;Analog to Digital&#xff09;&#xff1a;模拟-数字转换&#xff0c;将模拟信号转换为计算机可操作的数字信号 DA&#xff08;Digital to Analog&#xff09;&#xff1a;数字-模拟转换&#xff0c;将计算机输出的数字信号转换为模拟信号 AD/DA转换…

已解决:虚拟机集群xsehll连接不上

问题描述&#xff1a; hadoop102能连上&#xff0c;hadoop103、hadoop104无法连接&#xff0c;以前都能连上&#xff0c;今天突然就连不上了 解决方案&#xff1a; 使用ifconfig命令查看有没有ens33 如果没有的话那就证明你的问题和我一样 依次使用以下命令&#xff1a; sys…

维基百科文章爬虫和聚类:高级聚类和可视化

一、说明 维基百科是丰富的信息和知识来源。它可以方便地构建为带有类别和其他文章链接的文章&#xff0c;还形成了相关文档的网络。我的 NLP 项目下载、处理和应用维基百科文章上的机器学习算法。 在我的上一篇文章中&#xff0c;KMeans 聚类应用于一组大约 300 篇维基百科文…