C++——vector

目录

一、简介

二、接口

  1.构造

2.空间变化

3.增删查改

 三、vector与string的区别

四、模拟实现 

vector.h

test.cpp


一、简介

        vector,其实就是我们C语言学过的动态顺序表,一个可以存储任何数据类型,可以动态增长的数组。C++的STL将其收录,我们再想使用顺序表的时候就不用再自己去造轮子了,可以直接调用库中的顺序表帮我们完成各种需求。

        本博客主要还是介绍vector的各种接口以及部分常用接口的模拟实现

二、接口

        纵览所有接口,我们可以发现vector的接口比string简洁多了,这是因为vector吸取了很多string的经验,减少了冗余。

        我会把比较重要的接口调用的演示代码给出,并配上注释,各位有string的经验应该很容易明白,各个容器之间的很多知识是互通的。

  1.构造

#include<iostream>
#include<vector>
using namespace std;void test_vector1()
{// 默认构造,啥也没有,capacity是0vector<int> v1;// 10个1构造并初始化vector<int> v2(10, 1);// 迭代器区间构造,这个迭代器不仅可以是vector的,其实也可以是其它容器的vector<int> v3(++v2.begin(), --v2.end());// 拷贝构造vector<int> v4(v3);// 普通遍历for (size_t i = 0; i < v4.size(); i++){cout << v4[i] << " ";}cout << endl;// 迭代器遍历vector<int>::iterator it = v4.begin();while (it != v4.end()){cout << *it << " ";++it;}cout << endl;// 范围for遍历for (auto e : v3){cout << e << " ";}cout << endl;
}int main()
{test_vector1();return 0;
}

2.空间变化

#include<iostream>
#include<vector>
using namespace std;void TestVectorExpand()
{// vector在vs环境下,底层是刚开始开辟一个buff数组,等数组满了之后再开始1.5倍扩容// 如果是gcc条件下,就不会有buff数组,初始就是2倍扩容size_t sz;vector<int> v;v.reserve(100);sz = v.capacity();cout << "capacity changed: " << sz << '\n';cout << "making v grow:\n";for (int i = 0; i < 100; ++i){v.push_back(i);if (sz != v.capacity()){sz = v.capacity();cout << "capacity changed: " << sz << '\n';}}
}void test_vector2()
{//TestVectorExpand();// reserve接口的作用和在string中的类似vector<int> v(10, 1);v.reserve(20);cout << v.size() << endl;cout << v.capacity() << endl;v.reserve(15);cout << v.size() << endl;cout << v.capacity() << endl;v.reserve(5);cout << v.size() << endl;cout << v.capacity() << endl;
}void test_vector3()
{//TestVectorExpand();// resize的作用与string中的resize类似vector<int> v(10, 1);v.reserve(20);cout << v.size() << endl;cout << v.capacity() << endl;v.resize(15, 2);cout << v.size() << endl;cout << v.capacity() << endl;v.resize(25, 3);cout << v.size() << endl;cout << v.capacity() << endl;v.resize(5);cout << v.size() << endl;cout << v.capacity() << endl;
}
int main()
{test_vector1();test_vector2();return 0;
}

3.增删查改

 跟string很类似,看演示就好

#include<iostream>
#include<vector>
using namespace std;void test_vector4()
{vector<int> v(10, 1);v.push_back(2);v.insert(v.begin(), 0);for (auto e : v){cout << e << " ";}cout << endl;v.insert(v.begin() + 3, 10);for (auto e : v){cout << e << " ";}cout << endl;vector<int> v1(5, 0);for (size_t i = 0; i < 5; i++){cin >> v1[i];}for (auto e : v1){cout << e << ",";}cout << endl;}void test_vector5()
{vector<string> v1;string s1("xxxx");v1.push_back(s1);v1.push_back("yyyyy");for (const auto& e : v1){cout << e << " ";}cout << endl;
}int main()
{test_vector4();test_vector5();return 0;
}

 三、vector<char>与string的区别

        string存储的字符串是以/0结尾的,而vector<char>如果不手动添加,结尾就不是\0,另外,string有许多vector<char>没有的接口,更能有效地对字符串进行操作。 

四、模拟实现 

由于vector需要存储不同的数据类型,所以实现需要用到模板,而模板的声明和定义如果分离的话在运行的时候会发生链接错误,所以只需要一个头文件和一个测试文件

vector.h

实现过程要尤其注意迭代器失效的问题

插入的实现中,如果插入发生了扩容,那么原来传入的pos位置的迭代器就会失效,因为vector已经转移了空间位置,而pos仍在原位,为了得到之后相应的位置,可以把之后的pos位置作为返回值返回

reverse中,如果发生了扩容,则原来的start和finish指针也会失效,则其size()接口也会失效,所以需要在开始就记录下来old_size,方便后续的使用

#pragma once
#include <iostream>
#include <assert.h>
using namespace std;namespace muss
{// 使用模板的时候不要声明和定义分离,会发生链接错误template<typename T>class vector{typedef T* iterator;typedef const T* const_iterator;public:vector() :_start(nullptr), _finish(nullptr), _end_of_storage(nullptr) { }vector(const vector<T>& v){reserve(v.size());	for (const auto& e : v){push_back(e);}}// 缺省值是类似于int()即整型的默认构造,默认是0// 必须加const才能接收T()vector(size_t n, const T& value = T()){// 提前开空间提高效率reserve(n);while (n--) push_back(value);}vector(int n, const T& val = T()){reserve(n);for (int i = 0; i < n; i++){push_back(val);}}// 可以用任何容器的迭代器区间初始化template<typename InputIterator>vector(InputIterator begin, InputIterator end){while (begin != end){push_back(*begin);++begin;}}~vector(){if (_start){delete[] _start;_start = _finish = _end_of_storage = nullptr;}}size_t size() const { return _finish - _start; }size_t capacity() const { return _end_of_storage - _start; }iterator begin() { return _start; }iterator end() { return _finish; }const_iterator begin() const { return _start; }const_iterator end() const { return _finish; }void swap(vector<T>& v){std::swap(_start, v._start);std::swap(_finish, v._finish);std::swap(_end_of_storage, v._end_of_storage);}void reserve(size_t n){size_t old_size = size();if (capacity() < n){T* tmp = new T[n];// 不能是memcpy,浅拷贝申请空间的自定义类型会出现错误for (int i = 0; i < size(); ++i){tmp[i] = _start[i];}delete[] _start;_start = tmp;// 这里的_start已经不能减_finish了,也就是说size求不出来了// 把两行换换位置可以,不过写代码的过程中为了保险起见可以用old_size//_finish = _start + size();_finish = _start + old_size;_end_of_storage = _start + n;}}void resize(size_t n, const T& value = T()){if (n < size())_finish = _start + n;else{reserve(n);// 填充到size而不是capacitywhile (_finish < _start + n)push_back(value);}}void clear(){_finish = _start;}bool empty(){return _finish == _start;}// 擦除指定位置元素void erase(iterator pos){assert(pos >= _start && pos < _finish);for (iterator i = pos; i < _finish - 1; ++i){*i = *(i + 1);}--_finish;}// 一旦发生扩容,pos会失效(pos在原来位置,但是_start和_finish等等都已经转移)//void insert(iterator pos, const T& value)//{//	assert(pos >= _start && pos <= _finish);//	if(size() == capacity())//		reserve(capacity() == 0 ? 4 : 2 * capacity());//	for (iterator i = _finish; i > pos; --i)//	{//		*i = *(i - 1);//	}//	++_finish;//	*pos = value;//}// 所以我们需要在扩容结束时更新pos,并且如果想在函数外继续使用pos,我们需要给返回值iterator insert(iterator pos, const T& value){assert(pos >= _start && pos <= _finish);if (size() == capacity()){size_t len = pos - _start;reserve(capacity() == 0 ? 4 : 2 * capacity());pos = _start + len;}for (iterator i = _finish; i > pos; --i){*i = *(i - 1);}++_finish;*pos = value;return pos;}void push_back(const T& value){if (size() == capacity()){reserve(capacity() == 0 ? 4 : 2 * capacity());}*_finish = value;++_finish;}void pop_back(){erase(end() - 1);}T& operator[](size_t n){assert(n < size());return _start[n];}const T& operator[](size_t n) const{assert(n < size());return _start[n];}vector<T>& operator=(const vector<T>& v){clear();reserve(v.size());for (size_t i = 0; i < v.size(); ++i){push_back(v[i]);}return *this;}private:iterator _start = nullptr; // 首元素位置iterator _finish = nullptr;// 尾元素位置的下一个位置iterator _end_of_storage = nullptr;// 超出容量的下一个位置};// 可以打印所有容器template<typename Container>void print_container(const Container& c){for (const auto& e : c){cout << e << " ";}cout << endl;}void vector_test1(){vector<int> v1;v1.push_back(1);v1.push_back(2);v1.push_back(3);v1.push_back(4);v1.push_back(5);print_container(v1);vector<int> v2(v1);print_container(v2);vector<int> v3(v2.begin() + 1, v2.end() - 1);print_container(v3);vector<int> v4(10);// ???????????????vector<int> v5(9, 12);print_container(v4);print_container(v5);}void vector_test2(){vector<int> v1;v1.push_back(1);v1.push_back(2);v1.push_back(3);v1.push_back(4);v1.push_back(5);print_container(v1);v1.insert(v1.begin() + 1, 22);print_container(v1);v1.insert(v1.begin(), 123);print_container(v1);v1.insert(v1.end(), 999);print_container(v1);vector<int> v2;v2.push_back(1);v2.push_back(2);v2.push_back(3);v2.push_back(4);v2.push_back(5);print_container(v2);v2.resize(3);print_container(v2);v2.resize(7, 8);print_container(v2);v2.resize(12, 13);print_container(v2);}void vector_test3(){vector<int> v1;v1.push_back(1);v1.push_back(2);v1.push_back(3);v1.push_back(4);v1.push_back(5);print_container(v1);cout << v1[2] << endl;cout << v1[0] << endl;cout << v1[4] << endl;v1.clear();print_container(v1);cout << v1.empty() << endl;v1.push_back(1);v1.push_back(2);v1.push_back(3);v1.push_back(4);v1.push_back(5);cout << v1.empty() << endl;print_container(v1);v1.erase(v1.begin() + 1);print_container(v1);v1.erase(v1.begin());print_container(v1);// 要注意尾删得用end()-1,不然会越界v1.erase(v1.end() - 1);print_container(v1);v1.pop_back();print_container(v1);}void vector_test4(){vector<int> v1;v1.push_back(1);v1.push_back(2);v1.push_back(3);v1.push_back(4);v1.push_back(5);print_container(v1);vector<int> v2;vector<int> v3;v2 = v3 = v1;print_container(v2);print_container(v3);vector<int> v4;v4.push_back(11);v4.push_back(22);v4.push_back(33);swap(v4, v1);print_container(v1);print_container(v4);}void vector_test5(){vector<string> v;v.push_back("111111");v.push_back("111111");v.push_back("111111");v.push_back("111111");v.push_back("111111");v.push_back("111111");v.push_back("111111");print_container(v);}
}

test.cpp

#include "vector.h"
#include <vector>
//using namespace std;int main()
{//vector<int> v1 = { 1,2,3,4,5,7,8,5,13,54 };//cout << v1.capacity() << endl;//vector<int> v2(v1);//cout << v2.capacity() << endl;muss::vector_test5();//cout << int() << endl;return 0;
}

完结撒花~~~~(✿╹◡╹)

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

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

相关文章

项目完整开发的流程

流程 1.设计产品 2.写需求文档 2.1需求分析&#xff0c;后端设计数据库&#xff0c;建表&#xff0c;客户沟通&#xff0c;说完签字&#xff0c;留证据&#xff0c;防止后面扯皮&#xff0c;和防止后续变需求重新写业务 3.画原型图&#xff0c;也就是草图&#xff0c;初始的…

Java报错输出的信息究竟是什么?

Java报错输出的信息究竟是什么&#xff1f; 本篇会带大家了解一下java运行时报错输出的信息内容&#xff0c;简单学习一下虚拟机内存中Java虚拟机栈的工作方式以及栈帧中所存储的信息内容 异常信息 当你的程序运行报错时&#xff0c;你是否会好奇打印出来的那一大坨红色的究竟…

上海AI Lab视频生成大模型书生.筑梦环境搭建推理测试

引子 最近视频生成大模型层出不穷&#xff0c;上海AI Lab推出新一代视频生成大模型 “书生・筑梦 2.0”(Vchitect 2.0)。根据官方介绍&#xff0c;书生・筑梦 2.0 是集文生视频、图生视频、插帧超分、训练系统一体化的视频生成大模型。OK&#xff0c;那就让我们开始吧。 一、模…

怎么将手机备忘录传送至电脑

在数字化时代&#xff0c;手机备忘录已成为我们生活中不可或缺的一部分。无论是记录购物清单、工作事项&#xff0c;还是灵感闪现的瞬间&#xff0c;手机备忘录都能随时记录下这些宝贵的信息&#xff0c;帮助我们防止遗忘。然而&#xff0c;有时候我们需要将这些备忘录内容转移…

AtCoder Beginner Contest 374

C - Separated Lunch 题目&#xff1a; 思路&#xff1a; dfs枚举每个数是否选入a数组中&#xff0c;求和比较 代码&#xff1a; #include <bits/stdc.h>using namespace std;typedef long long LL;const int N25;int a[N]; bool st[N]; int mn0x3f3f3f3f; int sum; …

thinkphp 学习记录

1、PHP配置 &#xff08;点开链接后&#xff0c;往下拉&#xff0c;找到PHP8.2.2版本&#xff0c;下载的是ZIP格式&#xff0c;解压即用&#xff09; PHP For Windows: Binaries and sources Releases &#xff08;这里是下载地址&#xff09; 我解压的地址是&#xff1a;D:\…

webGL进阶(一)多重纹理效果

效果&#xff1a; 代码&#xff1a; <!DOCTYPE html> <html lang"en"><head><meta charset"UTF-8"><meta http-equiv"X-UA-Compatible" content"IEedge"><meta name"viewport" content&q…

初始Linux(二)基础命令

前言&#xff1a; 之前那一篇我们已经介绍了一部分的基础命令&#xff0c;当然那只不过是九牛一毛&#xff0c;本篇我们继续介绍一些比较重要且需要掌握的基础命令。 mv命令&#xff1a; 其实这个命令有两个功能&#xff0c;一个是移动&#xff08;剪切&#xff09;文件&#…

【LeetCode】每日一题 2024_10_9 找到按位或最接近 K 的子数组(LogTrick、位运算)

前言 每天和你一起刷 LeetCode 每日一题~ LeetCode 启动&#xff01; 题目&#xff1a;找到按位或最接近 K 的子数组 代码与解题思路 今天是 2100 的题目&#xff0c;难度略高&#xff0c;不在我的能力范围&#xff0c;推荐题解&#xff1a;两种方法&#xff1a;LogTrick/滑…

【优选算法】--- 位运算

位运算 一、常见的位运算总结&#xff08;重点&#xff01;&#xff09;1、关于位运算的符号2、&#xff08;判断&#xff09;给一个数字n&#xff0c;确定它的二进制表示中的第X位&#xff0c;是1还是0&#xff1f;3、&#xff08;修改&#xff09;如何把一个二进制的数字的第…

计算机、大数据与人工智能国际学术会议

第五届计算机、大数据与人工智能国际会议由景德镇陶瓷大学主办&#xff0c;西安交通大学、暨南大学、南京邮电大学、长沙学院、景德镇学院、爱迩思出版社&#xff08;ELSP&#xff09;协办。会议于2024年11月1日~3日在江西景德镇举行。在本次会议上发表的文章将出版到会议论文集…

目标检测实战教程Day1(原创)

原创不易&#xff0c;转载请标明本文地址 目标检测一直是计算机视觉领域的核心问题之一&#xff0c;它就像是让计算机拥有了一双“鹰眼”&#xff0c;能在复杂的图像中迅速锁定和识别出各种有趣的目标&#xff0c;比如人、汽车、动物或者任何其他特定物体。在这一章&#xff0c…

NeuVector部署、使用与原理分析

文章目录 前言1、概述2、安装与使用2.1、安装方法2.1.1、部署NeuVector前的准备工作2.1.1.1 扩容系统交换空间2.1.1.2 Kubernetes单机部署2.1.1.2.1 部署Docker2.1.1.2.2 部署Kubectl2.1.1.2.3 部署Minikube 2.1.1.3 Helm部署 2.1.2、使用Helm部署NeuVector 2.2、使用方法2.2.1…

跟《经济学人》学英文:2024年09月28日这期 The curse of the Michelin star

The curse of the Michelin star Restaurants awarded the honour are more likely to close, research finds 原文&#xff1a; The twelve new restaurants added to the New York Michelin Guide this month, serving up cuisine ranging from “haute French” to “eco…

【springboot9735】基于springboot+vue的车辆充电桩

主营内容&#xff1a;SpringBoot、Vue、SSM、HLMT、Jsp、PHP、Nodejs、Python、爬虫、数据可视化、小程序、安卓app等设计与开发。 收藏点赞不迷路&#xff0c;关注作者有好处 项目描述 随着信息化时代的到来&#xff0c;管理系统都趋向于智能化、系统化&#xff0c;车辆充电桩…

LabVIEW交直流接触器动态检测系统

LabVIEW软件与霍尔传感器技术结合的交直流接触器动态检测系统通过实时数据采集和处理技术&#xff0c;有效地测量并分析交直流接触器在吸合及吸持阶段的电流和电压变化&#xff0c;以及相应的功率消耗&#xff0c;从而优化电力和配电系统的性能和可靠性。 项目背景 交直流接触…

【Linux:线程控制】

目录 线程的创建与等待&#xff1a; ​编辑 代码中tid是什么&#xff1f; 如何看待线程函数传参&#xff1f; ​编辑 ​编辑创建多线程&#xff1a;​编辑 终止多线程&#xff1a; 线程分离&#xff1a; 线程封装&#xff1a; 线程的创建与等待&#xff1a; void *thre…

在docker中安装并运行mysql8.0.31

第一步&#xff1a;命令行拉取mysql镜像 docker pull mysql:8.0.31查看是否拉取成功 docker images mysql:latest第二步&#xff1a;运行mysql镜像&#xff0c;启动mysql实例 docker run -p 3307:3307 -e MYSQL_ROOT_PASSWORD"123456" -d mysql:8.0.313307:3307前…

51单片机的智能水温控制系统【proteus仿真+程序+报告+原理图+演示视频】

1、主要功能 该系统由AT89C51/STC89C52单片机LCD1602显示模块温度传感器继电器LED和按键等模块构成。适用于智能热水器控制、泳池水温控制系统等相似项目。 可实现功能: 1、LCD1602实时显示水温信息和上下限 2、温度传感器DS18B20采集水体温度 3、当温度低于下限&#xff0…

Linux环境通过APT 仓库安装版PostgreSQL 数据库实战

Linux环境通过APT 仓库安装版PostgreSQL 数据库是运维人员常见的需求之一&#xff0c;今天我们一步一步演示一下&#xff1a; 1、添加 PostgreSQL APT 仓库 确保你的系统更新&#xff0c;然后添加 PostgreSQL 的官方 APT 仓库。 sudo apt update sudo apt install -y wget w…