C++常见容器实现原理
引言
- 如果有一天!你骄傲离去!(抱歉搞错了)
- 如果有一天,你在简历上写下了这段话:

- 那么你不得不在面试前实现一下STL常见的容器了。
- C++的常用容器有:vector、string、deque、stack、queue、list、set、map。接下来就让我们对每种常用容器进行介绍和实现吧。
一、vector
- vector详细介绍
- 实现代码:
#include<assert.h>
#include<algorithm> // 包含函数std::swap// 模拟实现Vector
template<class T> // T为容器中元素的类型
class vector
{
public:typedef T* iterator; // 统一化指向vector中元素的指针为:iteratortypedef const T* const_iterator; // const_iterator指针无法修改指向的对象,但可以自增自减// 获取迭代器(const和非const)iterator begin(){return _start; // _start指向容器内存储的第一个元素}iterator end(){return _finish; // _finish指向容器内最后一个元素之后}const_iterator cbegin()const // 实现同上即可,返回的类型是const_iterator{return _start;}const_iterator cend()const{return _finish;}// 运算符[]的重载T& operator[](size_t pos){assert(pos < size()); // size()返回容器内容纳的元素个数return _start[pos]; // 根据指针运算,直接索引到Pos索引值即可}const T& operator[](size_t pos) // 同上{assert(pos < size());return start[pos];}// 构造函数vector() :_start(nullptr), _finish(nullptr), _endOfStorage(nullptr) {} // 初始化三个成员指针为空指针// 迭代器区间构造函数template<class InputIterator>vector(InputIterator first, InputIterator last) : _start(nullptr), _finish(nullptr), _endOfStorage(nullptr){while (first != last) // 将区间中的每个元素按照顺序压入容器内即可{push_back(*first);first++;}}// 拷贝构造函数vector(const vector<T>& v) :_start(nullptr), _finish(nullptr), _endOfStorage(nullptr){vector<T> tmp(v.cbegin(), v.cend()); // 先使用区间构造一个同样的容器,然后把其和此容器进行交换即可swap(tmp);}// 使用n个val值的构造函数vector(size_t n, const T& val = T()){reserve(n); // 将容器扩容到至少n个元素for (size_t i = 0; i < n; ++i) // 将值压入即可{push_back(val);}}// 重载运算符=vector<T>& operator=(vector<T> v){swap(v); // 由于v不是引用,是新构造来的,直接交换控制权即可return *this; // 返回自身}// 析构函数~vector() {delete[] _start; // 释放申请的空间_start = _finish = _endOfStorage = nullptr; // 将所有成员指针重置为空}// 容量调整函数(只扩容)void reserve(size_t n){if (n > capacity()) // 当且仅当需求的容量大于现在容器的最大容量时进行调整{size_t oldSize = size(); // 获取原本的容量T* tmp = new T[n]; // 申请需求的更大容量if (_start != nullptr) // 如果容器本身中包含元素{for (int i = 0; i < size(); ++i) // 将本身包含的元素拷贝到新申请的容量中{tmp[i] = _start[i];}delete[] _start; // 释放原本的内存空间}_start = tmp; // 将此容器的首地址记录为新申请的空间_finish = tmp + oldSize; // 计算容器中最后一个元素之后的地址_endOfStorage = _start + n; // 计算容器中最大容量元素之后的地址}}// 元素个数调整函数(只扩容)void reserve(size_t n, T val = T()){if (n > capacity()) // 如果需要扩容则进行扩容{reserve(n);}if (n > size()) // 如果容器包含元素数目少于n,则将包含元素数目-n中的元素设为val{while (_finish < _start + n){*_finish = val;_finish++;}}else{ // 否则容器包含元素数目多于n,则将容器包含元素数目设为n_finish = _start + n;}}// 获取元素个数sizesize_t size()const{return _finish - _start; // 指针运算}// 获取容量大小size_t capacity()const{return _endOfStorage - _start; // 指针运算}// 判断是否为空bool empty()const{return _finish == _start; // 当首元素地址 等于 最后一个元素之后的地址 时,即不存在元素即为空}void clear(){_finish = _start; // 清空,即最后一个元素之后的地址等于空间首地址}// 尾部插入函数void push_back(const T& x){if (_finish == _endOfStorage) // 如果空间满了{size_t newCapacity = (capacity() == 0 ? 4 : capacity() * 2); // 扩容两倍reserve(newCapacity); // 扩容}*_finish = x; // 将最后一个之后的元素设为x,即压入x_finish++; // 尾指针向后移动}// 尾部删除函数void pop_back(){assert(!empty()); // 不为空时删除_finish--; // 直接将尾指针向前移动即可}// 插入指定位置void insert(iterator pos, const T& val){assert(pos < _finish); // 插入位置需要位于:[_start,finish)assert(pos >= _start);if (_finish == _endOfStorage) // 如果空间满了{size_t len = pos - _start; //计算此位置之前有多少元素size_t newCapacity = capacity() == 0 ? 4 : capacity() * 2; // 计算扩容后的容量数目reserve(newCapacity); // 扩容pos = _start + len; // 计算新的对应pos位置 }iterator end = _finish - 1; // 计算尾元素位置while (end >= pos) // 从尾元素到插入位置之后的位置{*(end + 1) = *end; // 每个元素向后移动end--;}*pos = val; // 在pos位置插入val_finish++; // 将finish+1 }// 删除指定位置iterator erase(iterator pos){assert(pos >= _start);assert(pos < _finish);iterator begin = pos; while (begin < _finish - 1) // 从删除位置到最后一个元素{*(begin) = *(begin + 1); // 每个元素向前移动一位begin++;}_finish--; // 尾指针-1return pos;}// 交换void swap(vector<T>& v) // 交换对应指针即可{std::swap(_start, v._start);std::swap(_finish, v._finish);std::swap(_endOfStorage, v._endOfStorage);}private:iterator _start; // 容器中第一个元素地址,也是容器申请内存空间首地址iterator _finish; // 容器中最后一个元素之后的地址iterator _endOfStorage; // 容器申请的内存空间的尾地址,也即是容器能容纳的最多元素之后的地址
};
二、list
- 实现代码:
三、map
相关文章:
C++常见容器实现原理
引言 如果有一天!你骄傲离去!(抱歉搞错了)如果有一天,你在简历上写下了这段话: 那么你不得不在面试前实现一下STL常见的容器了。C的常用容器有:vector、string、deque、stack、queue、list、se…...
Mysql数据库 5.SQL语言聚合函数 语言日期-字符串函数
一、聚合函数 SQL中提供了一些可以对查询的记录的列进行计算的函数——聚合函数 1.count() 统计函数,统计满足条件的指定字符的值的个数 统计表中rebirth_mood个数 select count(列名) from 表名; #统计表中rebirth_namelcl的个数 select …...
使用Linux JumpServer 堡垒机进行远程访问
文章目录 前言1. 安装Jump server2. 本地访问jump server3. 安装 cpolar内网穿透软件4. 配置Jump server公网访问地址5. 公网远程访问Jump server6. 固定Jump server公网地址 前言 JumpServer 是广受欢迎的开源堡垒机,是符合 4A 规范的专业运维安全审计系统。JumpS…...
postgresql14管理(五)-tablespace
基本概念 表空间tablespace在postgresql中,表示数据库对象(比如表或索引)的存放目录。当表被访问时,系统通过表空间定位到对应数据文件所在的位置。 优势: 1、如果数据库集群所在的初始磁盘分区或磁盘卷的空间不足&a…...
Echarts-3D柱状图
通过Echarts的echarts.graphic.extendShape实现真正的3D柱状图 思路就是通过调整顶部面(CubeTop)、左侧面(CubeLeft)、右侧面(CubeRight)来决定柱状图的宽窄 建议优先调整顶部面,一般c1不需要动 // echarts-3D-bar-config.js import Vue from "vue";cons…...
vue中组件传值 引用页面与组件页面绑定参数 vue省市地区街道级联选择组件
在做后台的时候需要用到地区级联选择器 然后就自己封装了一个 其中 组件页面中 export default {props: { //使用value接收引用页面的绑定值value: [String]},watch: {value: {handler(val) {//val 以及 this.value 都可以获取到引用页面的绑定值},deep: true,immediate: tr…...
componentDidMount只执行一次的解决方法
一、前言 最近写react antd前端项目,需要页面加载时调用下查询列表的接口。 于是在componentDidMount方法里这样写了: componentDidMount() {const {dispatch,MyJS: { queryPara },} this.props;//这个调用接口查询列表dispatch({ type: MyJS/fetch, …...
React之diff原理
一、是什么 跟Vue一致,React通过引入Virtual DOM的概念,极大地避免无效的Dom操作,使我们的页面的构建效率提到了极大的提升 而diff算法就是更高效地通过对比新旧Virtual DOM来找出真正的Dom变化之处 传统diff算法通过循环递归对节点进行依…...
ElasticSearch中关于Nasted嵌套查询的介绍:生动案例,通俗易懂,彻底吸收
题注:随着对ES接触的越来越深入,发现此前了解的ES知识点有点单薄,特此寻来ES知识点汇总成的一个思维导图,全面了解自己掌握了哪些,未掌握哪些。此外,作者斌并没有足够的精力学习ES全部的知识点,…...
系列二、Spring的优缺点是什么
一、Spring的优缺点是什么 1.1、优点 集中管理对象,降低对象和对象之间的耦合性,方便维护对象;在不修改代码的情况下可以对业务代码进行增强,减少重复代码,提高开发效率,方便维护;提高开发效率…...
ESP32网络开发实例-HTTP-GET请求
HTTP-GET请求 文章目录 HTTP-GET请求1、HTTP GET请求2、软件准备3、硬件准备4、代码实现4.1 向OpenWeatherMap请求天气数据4.2 ThingSpeak 中的 ESP32 HTTP GET(更新值)在本文中,我们将介绍如使用ESP32向 ThingSpeak 和 openweathermap.org 等常用 API 发出 HTTP GET 请求。…...
PHP:json_encode和json_decode用法
json_encode 函数用于将 PHP 数据结构转换为 JSON 字符串。json_decode 函数用于将 JSON 字符串转换为 PHP 数据结构。 // 将 PHP 数据结构转换为 JSON 字符串 $data ["name" > "John","age" > 25,"city" > "New York&…...
Kafka-Java二:Spring配置kafka消息发送端的缓冲区
一、涉及到的组件概念 1.1、缓冲区 1.2、本地线程 1.3.本地线程消息推送策略 二、各组件的解释参见代码注释 // 配置消息的缓冲区/** 设置消息发送者端的缓冲区大小,如果设置了缓冲区,消息会先发送到缓冲区,可以提供发送性能* 默认大小是32…...
【ArcGIS模型构建器】05:批量为多个矢量数据添加相同的字段
本文实现借助arcgis模型构建器,实现批量为多个土地利用矢量数据添加相同的字段,例如DLMC,DLTB等。 文章目录 问题分析模型构建问题分析 有多个土地利用数据矢量图层,每个图层中有很多个图斑,现在需要给每个图层添加一个或者多个字段,如DLCM,DLBM等。 属性表如下所示: …...
坤坤的悲伤生活
描述 坤坤,这几个月来都非常悲伤,因为自己事发了,有一些问题找上了门,这个时候,有个人进献了一个阿拉丁神灯,有个灯神能够解决掉这个问题,但是有前提,必须回答出它的问题,…...
职业技术认证:《研发效能(DevOps)工程师》——开启职业发展新篇章
在互联网行业中,资质认证可以证明在该领域内的专业能力和知识水平。各种技术水平认证也是层出不穷,而考取具有公信力和权威性的认证是从业者的首选。同时,随着国内企业技术实力的提升和国家对于自主可控的重视程度不断提高,国产证…...
gin 框架出现runtime error: index out of range [0] with length 0
之前是这样的: category : c.Request.Form["type"][0] 加上这一句就变成了 fmt.Println(c.Request.FormFile("type")) category : c.Request.Form["type"][0]...
【高阶数据结构】B树
目录 1.B树 2.B树和B树的不同 3.B*树 B树较于哈希红黑树的优势:外查找:读取磁盘数据 ; B树的高度更低,对磁盘的进行I/O操作的次数更少(磁盘的性能比内存差得多); 1.B树 1.1.B树的概念&am…...
Android-Framework 应用间跳转时,提供 Android Broadcast 通知
一、环境 高通865 Android 10 二、情景 应用跳转时,通过广播发送源app的包名和目标app的包名 三、代码实现 frameworks/base/services/core/java/com/android/server/wm/ActivityStarter.java -132,6 132,14 import java.io.PrintWriter;import java.text.DateFormat;imp…...
【Javascript】函数返回值的作用
目录 返回值 中断函数 只能写在函数体里面 返回值 function a(){var b3;return b3? 4:5;} console.log(a()); 创建一个函数,给b赋值3, return b3? 4:5; 判断b是不是等于3,如果是就返回4, 如果不是就返回5 中断函数…...
web vue 项目 Docker化部署
Web 项目 Docker 化部署详细教程 目录 Web 项目 Docker 化部署概述Dockerfile 详解 构建阶段生产阶段 构建和运行 Docker 镜像 1. Web 项目 Docker 化部署概述 Docker 化部署的主要步骤分为以下几个阶段: 构建阶段(Build Stage):…...
React hook之useRef
React useRef 详解 useRef 是 React 提供的一个 Hook,用于在函数组件中创建可变的引用对象。它在 React 开发中有多种重要用途,下面我将全面详细地介绍它的特性和用法。 基本概念 1. 创建 ref const refContainer useRef(initialValue);initialValu…...
【JVM】- 内存结构
引言 JVM:Java Virtual Machine 定义:Java虚拟机,Java二进制字节码的运行环境好处: 一次编写,到处运行自动内存管理,垃圾回收的功能数组下标越界检查(会抛异常,不会覆盖到其他代码…...
用docker来安装部署freeswitch记录
今天刚才测试一个callcenter的项目,所以尝试安装freeswitch 1、使用轩辕镜像 - 中国开发者首选的专业 Docker 镜像加速服务平台 编辑下面/etc/docker/daemon.json文件为 {"registry-mirrors": ["https://docker.xuanyuan.me"] }同时可以进入轩…...
全面解析各类VPN技术:GRE、IPsec、L2TP、SSL与MPLS VPN对比
目录 引言 VPN技术概述 GRE VPN 3.1 GRE封装结构 3.2 GRE的应用场景 GRE over IPsec 4.1 GRE over IPsec封装结构 4.2 为什么使用GRE over IPsec? IPsec VPN 5.1 IPsec传输模式(Transport Mode) 5.2 IPsec隧道模式(Tunne…...
AI病理诊断七剑下天山,医疗未来触手可及
一、病理诊断困局:刀尖上的医学艺术 1.1 金标准背后的隐痛 病理诊断被誉为"诊断的诊断",医生需通过显微镜观察组织切片,在细胞迷宫中捕捉癌变信号。某省病理质控报告显示,基层医院误诊率达12%-15%,专家会诊…...
Golang——9、反射和文件操作
反射和文件操作 1、反射1.1、reflect.TypeOf()获取任意值的类型对象1.2、reflect.ValueOf()1.3、结构体反射 2、文件操作2.1、os.Open()打开文件2.2、方式一:使用Read()读取文件2.3、方式二:bufio读取文件2.4、方式三:os.ReadFile读取2.5、写…...
在鸿蒙HarmonyOS 5中使用DevEco Studio实现企业微信功能
1. 开发环境准备 安装DevEco Studio 3.1: 从华为开发者官网下载最新版DevEco Studio安装HarmonyOS 5.0 SDK 项目配置: // module.json5 {"module": {"requestPermissions": [{"name": "ohos.permis…...
MFE(微前端) Module Federation:Webpack.config.js文件中每个属性的含义解释
以Module Federation 插件详为例,Webpack.config.js它可能的配置和含义如下: 前言 Module Federation 的Webpack.config.js核心配置包括: name filename(定义应用标识) remotes(引用远程模块࿰…...
Python实现简单音频数据压缩与解压算法
Python实现简单音频数据压缩与解压算法 引言 在音频数据处理中,压缩算法是降低存储成本和传输效率的关键技术。Python作为一门灵活且功能强大的编程语言,提供了丰富的库和工具来实现音频数据的压缩与解压。本文将通过一个简单的音频数据压缩与解压算法…...
