STL复习-序列式容器和容器适配器部分

STL复习

1. 常见的容器

如何介绍这些容器,分别从常见接口,迭代器类型,底层实现

在这里插入图片描述


序列式容器

string

string严格来说不属于stl,它是属于C++标准库

**底层实现:**string本质是char类型的顺序表,因为不同编译器下的具体实现不同,这里只提供一个我的简答框架

class string
{
public:typedef char* iterator;typedef const char* const_iterator; 
private:char* _str; 		// 堆上开辟的顺序表空间size_t _size; 		// 有效字符个数size_t _capacity; 	// _str的空间大小static const size_t npos; // 最大字符串大小
};const size_t string::npos = -1;

实际在VS系列下,string是包含一个指针,一个联合体(一个数组和一个指针,如果字符串长度小于16就会使用提前开辟好的数组,如果大于16字节再去堆上申请空间使用指针指向),size和capacity

在g++下string只包含一个指针,指向堆上的一段空间,包含一个指针指向为字符串开辟的空间,引用计数,size和capacity,这个引用计数可以让赋值拷贝这些对象只需要浅拷贝增加引用计数即可

迭代器类型: 随机访问迭代器

常用接口:

函数名功能
size / length返回字符串有效字符个数
clear / reserver / resize清空有效字符 / 预留空间 / 将有效字符的个数该成n个,多出的空间用字符c填充
operator[]返回pos位置的字符
push_back / append / operator+=在字符串后尾插字符c / 字符串 / 字符串
c_str返回C格式字符串
find / rfind + npos从字符串pos位置开始往(后 / 前)找字符c,返回该字符在字符串中的位置,没有返回npos
substr在str中从pos位置开始,截取n个字符,然后将其返回
operator<< / operator>> / getline从iostream中写 / 读 (空格/回车),getline可自定义分隔符
// 剪去报头 length\r\n*******\r\nlength\r
std::string Decode(std::string& str)
{// 判断条件是否满足,不满足返回空串size_t pos = str.find(SEP);if (pos == std::string::npos)return "";size_t lenght = atoi(str.substr(0, pos).c_str());if (lenght > str.size() - pos - SEP_LEN * 2)return "";str.erase(0, pos + SEP_LEN);std::string ret = str.substr(0, lenght);str.erase(0, lenght + SEP_LEN);return ret;
}
// 简单实现class string
{friend std::ostream& operator<<(std::ostream& out, const string& str);//friend istream& operator>>(istream& in, const string& str);
public:string() : _str(nullptr), _size(0), _capacity(0){}string(const char* str) :string(){size_t sz = strlen(str);_str = new char[sz + 1] {0};strcpy(_str, str);_size = sz;_capacity = sz + 1;}string(const string& str): string(str.c_str()){}string& operator==(string str){if(this != &str)swap(str);return *this;}~string(){delete[] _str;}string& operator+=(const string& str){size_t sz = str._size;if (sz + _size + 1 > _capacity){reserve(sz > _capacity ? _capacity + sz : 2 * _capacity);}strcpy(_str + _size, str.c_str());_size += sz;return *this;}char& operator[](size_t pos){return *(_str + pos);}void reserve(size_t newsize){if (newsize > _capacity){char* str = new char[newsize] {0};strcpy(str, _str);delete[] _str;_str = str;_capacity = newsize;}}void swap(string& str){std::swap(_str, str._str);std::swap(_size, str._size);std::swap(_capacity, str._capacity);}const char* c_str() const {return _str;}size_t size() const{return _size;}private:char* _str;size_t _size;size_t _capacity;static size_t npos;
};size_t string::npos = -1;std::ostream& operator << (std::ostream& out, const string& d)
{out << d.c_str();return out;
}

vector

底层实现:

vector本质是模板类型的顺序表,对于底层数据结构是顺序表类型的容器在每次增容都需要极大的代价,需要开辟更大空间,并对之前的数据进行拷贝,,vs下capacity是按1.5倍增长的,g++是按2倍增长的

reserve只负责开辟空间,如果确定知道需要用多少空间,reserve可以缓解string和vector增容的代价缺陷问题

与其它动态序列容器相比(deque, list and forward_list), vector在访问元素的时候更加高效,在末尾添加和删除元素相对高效。对于其它不在末尾的删除和插入操作,效率更低。比起list和forward_list 统一的迭代器和引用更好

template<class T>
class vector
{
public:typedef T* iterator;typedef const T* const_iterator;
private:iterator _start = nullptr;iterator _finish = nullptr;iterator _end_of_storage = nullptr;
};

迭代器类型: 随机访问迭代器

常用接口:

函数名功能
size / capacity / empty数据个数 / 容量大小 / 是否为空
reserve / resize / clear改变vector的capacity / size / 清空
push_back / pop_back尾插 / 尾删
find + v.end() (不常用)查找,注意这个是算法模块实现,不是vector的成员接口
insert / erase在pos位置插入删除
emplace / empalce_back构造和插入
operator[]返回pos位置的对象

深拷贝问题,在拷贝构造时如果对像是自定义类型,就会调用自定义类型的拷贝构造

// 简单实现template<class T>
class vector
{typedef T* iterator;
public:iterator begain() { return _start; }iterator end() { return _finish; }vector():_start(nullptr), _finish(nullptr), _end(nullptr){}vector(size_t n, T val = T()) :vector(){reserve(n);for (size_t i = 0; i < n; ++i){_start[i] = val;}_finish = _start + n;}vector(const vector& v) :vector(){reserve(v.size());_finish = _start + v.size();for (size_t i = 0; i < v.size(); ++i){operator[](i) = v[i];}}~vector(){delete[] _start; }void push_back(T val) {insert(_finish, val); }void pop_back() {erase(_finish - 1); }void insert(iterator pos, T val = T()){assert(pos >= _start && pos <= _finish);if (_finish + 1 > _end){size_t pos_size = pos - _start;reserve(size() + 1);pos = _start + pos_size;}iterator cur = _finish;while (cur != pos){*cur = *(cur - 1);--cur;}*pos = val;_finish += 1;}iterator erase(iterator pos){assert(pos >= _start && pos < _finish);iterator cur = pos;while (cur != _finish){*cur = *(cur + 1);++cur;}_finish -= 1;return pos;}T& operator[](size_t pos){assert(pos < size());return _start[pos];}const T& operator[](size_t pos) const {assert(pos < size());return _start[pos];}void reserve(size_t newcapacity){size_t capacity = _end - _start;size_t size = _finish - _start;if (capacity < newcapacity){newcapacity = newcapacity < 2 * capacity ? 2 * capacity : newcapacity;T* newv = new T[newcapacity];if(_start)memcpy(newv, _start, size * sizeof(T));delete[] _start;_start = newv;_end = newv + newcapacity;_finish = _start + size;}}size_t size() const { return _finish - _start; }size_t capacity() const { return _end - _start; }private:iterator _start;iterator _finish;iterator _end;
};

list

底层实现:

list的底层是带头双向循环链表结构,链表中每个元素存储在互不相关的独立节点中,在节点中通过指针指向其前一个元素和后一个元素

与其他的序列式容器相比(array,vector,deque),list通常在任意位置进行插入、移除元素的执行效率更好

最大的缺陷是不支持任意位置的随机访问,list还需要一些额外的空间,以保存每个节点的相关联信息

template<class T>
struct list_node
{typedef list_node<T> node;node* _next;node* _prev;T _date;
};template<class T, class Ref, class Ptr>
struct __list_iterator
{typedef list_node<T> node;typedef __list_iterator<T, Ref, Ptr> self;node* _it;
};template<class T>
class list
{typedef list_node<T> node;
public:typedef __list_iterator<T, T&, T*> iterator;typedef __list_iterator<T, const T&, const T*> const_iterator;
private:node* _head;
};

迭代器类型: 双向访问迭代器

常用接口:

函数名功能
empty / size判空 / 返回节点个数
front / back返回最后 / 最前节点值的引用
push_front / pop_front头插 / 头删
push_front / pop_back尾插 / 尾删
insert / erase插入 / 删除
emplace / emplace_front / emplace_back构造 + 插入
sort链表的排序
template<class T>
struct list_node
{list_node* _prev;list_node* _next;T _val;list_node(T val = T()) :_prev(nullptr), _next(nullptr), _val(val){}
};template<class T, class Ref, class Ptr>
struct list_iterator
{typedef list_node<T> node;typedef list_iterator<T, Ref, Ptr> Self;node* _it;list_iterator(node* it) :_it(it) {}list_iterator(const list_iterator<T, T&, T*>& iterator) :_it(iterator._it){}Ptr operator->() {return &(_it->_val);}Ref operator*() {return _it->_val; }Self operator++() {return _it = _it->_next; }Self operator--() {return _it = _it->_prev; }bool operator!=(const Self& iterator) const {return _it != iterator._it; }
};template<class T>
struct list
{typedef list_node<T> node;typedef list_iterator<T, T&, T*> iterator;typedef list_iterator<T, const T&, const T*> const_iterator;
public:iterator begin() { return iterator(_head->_next); }const_iterator begin() const { return const_iterator(_head->_next); }iterator end() { return iterator(_head); }const_iterator end() const { return const_iterator(_head); }list():_head(new node){_head->_next = _head;_head->_prev = _head;}~list(){while (!empty()){pop_front();}delete _head;}void insert(iterator pos, const T& val){node* next = pos._it;node* prev = next->_prev;node* newnode = new node(val);prev->_next = newnode;newnode->_prev = prev;newnode->_next = next;next->_prev = newnode;_size++;}void erase(iterator pos){assert(pos._it != _head);node* next = pos._it->_next;node* prev = pos._it->_prev;delete pos._it;next->_prev = prev;prev->_next = next;_size--;}void push_back(const T& val) { insert(end(), val);  }void push_front(const T& val) { insert(begin(), val); }void pop_back(){erase(_head->_prev); }void pop_front(){erase(begin()); }bool empty() const{return _size == 0;}
private:list_node<T>* _head;size_t _size = 0;
};

deque

底层实现:

双端队列由一个指针数组和多个相同长度的定长数组组成

在这里插入图片描述

双端队列,头插尾插,头删尾删效率高,这点比vector要好,但是不如list在任意位置都可以O(1)时间复杂度插入删除(增删)

通过迭代器支持operator[]随机访问,在随机访问上比list要好,但是不如vector(查改)

因为头尾的插入删除效率高,所以他就非常适合stack和queue

迭代器类型: 随机访问迭代器

常用接口:

函数名功能
size / resize / empty大小 / 改变大小 / 判空
operator[] / front / back读数据
push_front / pop_front头插 / 头删
push_front / pop_back尾插 / 尾删
insert / erase插入 / 删除

关联式容器

map/set
unordered_map/unordered_set
bitset

容器适配器

stack

stack是一种容器适配器,专门用在具有后进先出操作的上下文环境中,其删除只能从容器的一端进行元素的插入与提取操作。

stack是作为容器适配器被实现的,容器适配器即是对特定类封装作为其底层的容器,并提供一组特定的成员函数来访问其元素,将特定类作为其底层的,元素特定容器的尾部(即栈顶)被压入和弹出。

stack的底层容器可以是任何标准的容器类模板或者一些其他特定的容器类,这些容器类应该支持以下操作:

  • empty:判空操作
  • back:获取尾部元素操作
  • push_back:尾部插入元素操作
  • pop_back:尾部删除元素操作

标准容器vector、deque、list均符合这些需求,默认情况下,如果没有为stack指定特定的底层容器, 默认情况下使用deque

在这里插入图片描述

函数名功能
stack()构造空的栈
empty检测stack是否为空
size返回stack中元素的个数
top返回栈顶元素的引用
push将元素val压入stack中
pop将stack中尾部的元素弹出

queue

队列是一种容器适配器,专门用于在FIFO上下文(先进先出)中操作,其中从容器一端插入元素,另一端提取元素。

队列作为容器适配器实现,容器适配器即将特定容器类封装作为其底层容器类,queue提供一组特定的成员函数来访问其元素。元素从队尾入队列,从队头出队列。

底层容器可以是标准容器类模板之一,也可以是其他专门设计的容器类。该底层容器应至少支持以下操作:

  • empty:检测队列是否为空
  • size:返回队列中有效元素的个数
  • front:返回队头元素的引用
  • back:返回队尾元素的引用
  • push_back:在队列尾部入队列
  • pop_front:在队列头部出队列

标准容器类deque和list满足了这些要求。默认情况下,如果没有为queue实例化指定容器类,则使用标准容器deque

在这里插入图片描述

函数名功能
queue()构造空的队列
empty检测queue是否为空
size返回queue中元素的个数
front返回queue顶元素的引用
back返回queue尾元素的引用
push将元素val压入queue中
pop将queue中尾部的元素弹出

priority_queue

优先队列是一种容器适配器,根据严格的弱排序标准,它的第一个元素总是它所包含的元素中最大的

类似于堆,在堆中可以随时插入元素,并且只能检索最大堆元素(优先队列中位于顶部的元素)

优先队列被实现为容器适配器,容器适配器即将特定容器类封装作为其底层容器类,queue提供一组特定的成员函数来访问其元素。元素从特定容器的“尾部”弹出,其称为优先队列的顶部。

底层容器可以是任何标准容器类模板,也可以是其他特定设计的容器类。容器应该可以通过随机访问迭代器访问,并支持以下操作:

  • empty():检测容器是否为空
  • size():返回容器中有效元素个数
  • front():返回容器中第一个元素的引用
  • push_back():在容器尾部插入元素
  • pop_back():删除容器尾部元素

标准容器类vector和deque满足这些需求。默认情况下,如果没有为特定的priority_queue类实例化指 定容器类,则使用vector(模板参数第二位)

需要支持随机访问迭代器,以便始终在内部保持堆结构。容器适配器通过在需要时自动调用算法函数 make_heap、push_heap和pop_heap 来自动完成此操作

默认情况下priority_queue是大堆,使用less(模板参数第三位)

在这里插入图片描述

一句话,少的点挪动的次数多 时间复杂度约等于 T(N)

在这里插入图片描述

多的点挪动次数多 时间复杂度 T(N*LogN)

若是pop n次用来排序,时间复杂度 T(N*LogN)

优先级队列,使用迭代器建堆,比遍历push,要好

函数名功能
priority_queue()构造一个空的优先级队列
priority_queue(first,last)根据迭代器区间构造优先级队列
empty()检测优先级队列是否为空
top()返回优先级队列中最大(最小元素),即堆顶元素
size()返回优先级队列里的元素个数
push(x)在优先级队列中插入元素x
pop()删除优先级队列中最大(最小)元素,即堆顶元素

杂度 T(N*LogN)

优先级队列,使用迭代器建堆,比遍历push,要好

函数名功能
priority_queue()构造一个空的优先级队列
priority_queue(first,last)根据迭代器区间构造优先级队列
empty()检测优先级队列是否为空
top()返回优先级队列中最大(最小元素),即堆顶元素
size()返回优先级队列里的元素个数
push(x)在优先级队列中插入元素x
pop()删除优先级队列中最大(最小)元素,即堆顶元素

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

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

3-一元函数微分学

看到高次求导0---->立即想到奇偶性

STM32智能无人机控制系统教程

目录 引言环境准备智能无人机控制系统基础代码实现&#xff1a;实现智能无人机控制系统 4.1 数据采集模块 4.2 数据处理与飞行控制 4.3 通信与导航系统实现 4.4 用户界面与数据可视化应用场景&#xff1a;无人机应用与优化问题解决方案与优化收尾与总结 1. 引言 智能无人机控…

复旦微JFMVU3P-2FFVC1517 FPGA+AI全国产化人工智能数据处理平台,适用于雷达与中频信号采集、视频图像采集

板载FPGA实时处理器&#xff1a;JFMVU3P-2FFVC1517支持1个FMC&#xff08;HPC&#xff09;扩展接口支持2路QSFP光纤接口支持x8 Gen3 PCIE主机接口&#xff0c;系统带宽&#xff1e;5GByte/s支持1个R45自适应千兆以太网口支持1个GPIO/RS422接口 基于复旦微16nm工艺JFM9VU3P FPG…

C语言 -- 深入理解指针(二)

C语言 -- 深入理解指针&#xff08;二&#xff09; 1. 数组名的理解2. 使用指针访问数组3. 一维数组传参的本质4. 冒泡排序5. 二级指针6. 指针数组7. 指针数组模拟二维数组8. 字符指针变量9. 数组指针变量2.1数组指针变量是什么&#xff1f;2.2 数组指针变量怎么初始化 10. 二维…

SQLServer的系统数据库用别的服务器上的系统数据库替换后做跨服务器连接时出现凭证、非对称金钥或私密金钥的资料无效

出错作业背景&#xff1a; 公司的某个sqlserver服务器要做迁移&#xff0c;由于该sqlserver服务器上数据库很多&#xff0c;并且做了很多的job和维护计划&#xff0c;重新安装的sqlserver这些都是空的&#xff0c;于是就想到了把系统4个系统数据库进行替换&#xff0c;然后也把…

Android进入Recovery模式 显示无命令 / no command

问题&#xff1a; 进入 recovery 模式后就显示no command&#xff0c;倒地机器人 解决&#xff1a; 在此界面按住电源键不放&#xff0c;再按一下音量

Git 查看、新建、删除、切换分支

Git 是一个版本控制系统&#xff0c;软件开发者用它来跟踪应用程序的变化并进行项目协作。 分支的诞生便于开发人员在彼此独立的环境中进行开发工作。主分支&#xff08;通常是 main 或 master&#xff09;可以保持稳定&#xff0c;而新的功能或修复可以在单独的分支中进行开发…

MySQL之表的约束(上)

目录 空属性(NULL) 实例建表 插入操作 默认值(default) 建表 插入操作 NULL与default的结合 列描述 建表 zerofill 建表 插入操作 主键 建表 插入 主键的增加与去掉 去掉 增加 复合主键 插入的影响 真正约束字段的是数据类型&#xff0c;但是数据类型约束很单一&a…

2 ECMAScript

JavaScript 概述 JavaScript 编程语言允许你在 Web 页面上实现复杂的功能;如果你看到一个网页不仅仅显示静态的信息,而是显示依时间更新的内容,或者交互式地图,或者 2D/3D 动画图像,或者滚动的视频播放器,等等——你基本可以确定,这需要 JavaScript 的参与 JavaScript 编程语言…

gams103作业1含提高部分

第一部分 检测碰撞 首先需要对所有点进行碰撞检测&#xff0c;判断是否与平面发生碰撞 这里碰撞检测根据读入给定的表面点和表面的法向量求点积判断是否小于0&#xff0c;如果是则证明两个的方向相反&#xff0c;发生碰撞。 同时判断是否速度方向和法线方向相反。 当同时满…

我国静止无功发生器(SVG)市场规模逐渐扩大 高压SVG为主流产品

我国静止无功发生器&#xff08;SVG&#xff09;市场规模逐渐扩大 高压SVG为主流产品 静止无功发生器&#xff08;SVG&#xff09;又称为静止同步补偿器、先进静止补偿器、静止调相机等&#xff0c;是利用全控型功率器件组成的桥式变流器来实现动态无功调节的一种先进无功自动补…

Table 表格--分页序号自增

代码&#xff1a; import { Space, Table, Tag } from antd; import type { ColumnsType } from antd/es/table; import React, { useState } from react;interface DataType {key: string;name: string;age: number;address: string;tags: string[]; }const data: DataType[]…

python爬虫入门(四)之Beautiful Soup库

一、什么是Beautiful Soup库 1、Beautiful Soup库是用来做HTML解析的库 Beautiful Soup把看起来复杂的HTML内容&#xff0c;解析成树状结构&#xff0c;让搜索和修改HTML结构变得更容易 2、第三方库&#xff0c;先安装 终端输入pip install bs4 from bs4 import Beautiful…

Linux服务管理(一)SSH服务

Linux服务管理-SSH服务 1、SSH的登录验证2、SSH的登录端口设置3、SSH的登录用户设置4、SSH的登录超时设置5、SSH的尝试登录次数设置6、ssh尝试次数超了&#xff0c;服务器端怎么放行 程序优化是有上限的&#xff0c;比如一个网站的代码量你只会随着需求越写越多不会越写越少。架…

想买开放式耳机怎么选?五款高热度产品甄选推荐!

在追求自由与舒适的今天&#xff0c;开放式蓝牙耳机以其独特魅力&#xff0c;正引领音频设备的新风尚。它们摒弃了传统入耳式的封闭束缚&#xff0c;让音乐与周围世界和谐共存&#xff0c;既保证了音质的清晰与沉浸&#xff0c;又保留了对环境的敏锐感知。开放式设计不仅减轻了…

【2024最新】Arduino通过Python进行串口通信控制电机

1. 背景 最近想研究一下用 Python 控制 Arduino 的技术&#xff0c;通过上网查询&#xff0c;发现可以用 Python 中的 serial 库来实现和 Arduino 主板的串口通信&#xff0c;从而控制 Arduino。 特此记录一下这个小项目的过程及出现的问题。 2. 基础准备 主板&#xff1a;…

景联文科技打造高质量图文推理问答数据集,赋能大语言模型提升推理能力

大语言模型在处理推理任务时&#xff0c;不同于人类能够反思错误并修正思维路径&#xff0c;当它遇到自身知识盲区时&#xff0c;缺乏自我校正机制&#xff0c;往往导致输出结果不仅无法改善&#xff0c;反而可能变得更不准确。 需要依赖外部的知识库和推理能力来克服其在理解和…

蚓链实践告诉你“企业确保达成数字化营销效果的方法”

在如今这个数字化盛行的时代&#xff0c;企业想在激烈的市场竞争里崭露头角&#xff0c;确保数字营销效果那可是至关重要&#xff01;今天就来给大家聊聊实现这一目标的基本条件&#xff0c;来自蚓链数字化营销系统的广大用户体验总结。 一、精准的目标定位 企业一定要清楚地知…

uniapp 表格,动态表头表格封装渲染

1.接口表格数据&#xff1a; {"headers": [{"label": "实例名","name": "v1","order": 1,"hide": false,"dateTypeValue": null},{"label": "所属科室","name&quo…

CentOS 安装 annie/lux,以及 annie/lux 的使用

annie 介绍 如果第一次听到 annie 想必都会觉得陌生&#xff0c;annie 被大家称为视频下载神器&#xff0c;annie 作者介绍说可以下载抖音、哔哩哔哩、优酷、爱奇艺、芒果TV、YouTube、Tumblr、Vimeo 等平台的视频。 githup&#xff1a;https://github.com/pingf/annie 支持…