vector的實現

介紹

1. 本質與存儲結構

  • 動態數組實現:vector 本質是動態分配的數組,采用連續內存空間存儲元素,支持下標訪問(如?vec[i]),訪問效率與普通數組一致(時間復雜度 O (1))。
  • 動態擴容機制:當元素數量超過當前容量時,vector 會重新分配更大的內存空間,將原元素復制到新空間。為避免頻繁擴容,其擴容策略通常為對數增長(如每次容量翻倍),確保末尾插入元素的均攤時間復雜度為 O (1)。

2. 空間分配策略

  • 預分配額外空間:vector 會分配比實際需求更大的存儲空間,以減少擴容次數。例如,初始容量為 n 時,插入新元素可能直接擴容至 2n,而非每次只增加 1 個元素的空間。
  • 空間與效率的權衡:預分配策略雖增加了初始存儲空間占用,但避免了頻繁內存重分配的開銷(如復制元素的耗時),在動態增長場景下更高效。

?3. 與其他序列容器的差異

  • 與 deque 的對比
    • deque 兩端插入 / 刪除效率更高(vector 僅末尾高效),且支持動態擴容(但內存非連續,需維護分段數組)。
  • 與 list/forward_list 的對比
    • list/forward_list 為雙向鏈表 / 單向鏈表,內存不連續,不支持下標訪問,但任意位置插入 / 刪除效率更高(無需移動元素)。
    • vector 的迭代器和引用更穩定(連續內存保證迭代器不會因中間元素刪除而失效,除非操作涉及擴容)。

?4. 適用場景與注意事項

  • 適用場景
    • 需要頻繁通過下標訪問元素(如數組場景)。
    • 主要在末尾進行插入 / 刪除操作(如棧、隊列場景)。
  • 注意事項
    • 非末尾插入 / 刪除操作(如中間位置插入)會導致元素移動,效率較低,此時優先選擇 list。
    • 若已知數據量大小,可使用?reserve(n)?預分配空間,避免多次擴容。
    • 擴容會導致原有迭代器、指針、引用失效(因內存地址變更),需重新獲取。

實現?

基本結構

在我們的vector的實現中,迭代器部分不需要特殊處理,它只是一個普通的指針,只是typedef的結果。

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

?這就是vector的基本結構,有三個指針,分別指向vecotr的開始位置,元素最后的插入位置以及該空間結束位置。

迭代器

因為vector的迭代器很質樸,就是一個指針,所以他的實現也非常簡單,不需要進行++、--運算符重載操作,只需要寫出const迭代器和普通迭代器,其實就是用const對指針修飾一下,代碼如下:

		typedef T* iterator;typedef const T* const_iterator;iterator begin(){return _start;}iterator end(){return _finish;}const_iterator begin() const{return _start;}const_iterator end() const{return _finish;}
		T& operator[](size_t pos){assert(pos < size());return _start[pos];}const T& operator[](size_t pos) const{assert(pos < size());return _start[pos];}

?

?size與capacity

實現size與capacity就是用指針進行相減

		size_t capacity() const{return _endofstorage - _start;}size_t size() const{return _finish - _start;}

reserve?

reserve是預先分配指定大小的內存空間,以避免后續插入元素時頻繁觸發動態擴容,從而提高性能。

  • 注意reserve?僅改變容量,不改變容器的大小(size()),也不初始化元素。

實現:若?n?大于當前容器的容量(capacity()),則重新分配內存,使容量至少為?n,然后將原來的數據拷貝到新開的空間中,完成操作后,再將_start指向新開的空間;否則不做任何操作。?

		void reserve(size_t n){if (n > capacity()){T* tmp = new T[n];size_t sz = size();if (_start){//memcpy(tmp, _start, sizeof(T) * sz);for (size_t i = 0; i < sz; i++){tmp[i] = _start[i];}delete[] _start;}_start = tmp;_finish = _start + sz;_endofstorage = _start + n;}}

resize?

  • 若?n > size(),容器擴容并插入新元素。
  • 若?n < size(),容器收縮并刪除尾部元素。
  • 若?n == size(),不做任何操作。

下面將<=合并起來。

		void resize(size_t n, const T& val = T()){if (n <= size()){_finish = _start + n;}else{reserve(n);while (_finish < _start + n){*_finish = val;++_finish;}}}

insert

首先先用assert判斷傳入的迭代器位置是否合理,不合理直接報錯,若合理,看_finsh和_endofstorage是否相等,若相等則說明需要擴容。擴容時,需要重新更新一下傳入迭代器的位置,因為擴容后位置發生了變化。

之后進行從后往前挪動數據,切記,一定是從后往前!!!

		void insert(iterator pos, const T& x){assert(pos >= _start);assert(pos <= _finish);if (_finish == _endofstorage){size_t len = pos - _start;reserve(capacity() == 0 ? 4 : capacity() * 2);pos = _start + len;}iterator end = _finish - 1;while (end >= pos){*(end + 1) = *end;--end;}*pos = x;++_finish;}

從實現我們也可以看出,insert是比較消耗時間的。

push_back

有了insert,那么push_back的實現就非常簡單了,直接復用就可以了。

		void push_back(const T& x){/*if (_finish == _endofstorage){reserve(capacity() == 0 ? 4 : capacity() * 2);}*_finish = x;++_finish;*/insert(end(), x);}

erase

類似于insert,就不多解釋。

		iterator erase(iterator pos){assert(pos >= _start);assert(pos < _finish);iterator it = pos + 1;while (it < _finish){*(it - 1) = *it;++it;}--_finish;return pos;}

構造函數

vector的構造方法是很多的,我直接分享給大家,原理都很簡單

		vector(){}template <class InputIterator>vector(InputIterator first, InputIterator last){while (first != last){push_back(*first);++first;}}vector(size_t n, const T& val = T()){reserve(n);for (size_t i = 0; i < n; i++){push_back(val);}}vector(int n, const T& val = T()){reserve(n);for (int i = 0; i < n; i++){push_back(val);}}// v2(v1)vector(const vector<T>& v){reserve(v.capacity());for (auto& e : v){push_back(e);}}

?

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/bicheng/82563.shtml
繁體地址,請注明出處:http://hk.pswp.cn/bicheng/82563.shtml
英文地址,請注明出處:http://en.pswp.cn/bicheng/82563.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

【Linux筆記】防火墻firewall與相關實驗(iptables、firewall-cmd、firewalld)

一、概念 1、防火墻firewall Linux 防火墻用于控制進出系統的網絡流量&#xff0c;保護系統免受未授權訪問。常見的防火墻工具包括 iptables、nftables、UFW 和 firewalld。 防火墻類型 包過濾防火墻&#xff1a;基于網絡層&#xff08;IP、端口、協議&#xff09;過濾流量&a…

el-date-picker 前端時間范圍選擇器

控制臺參數&#xff1a; 前端代碼&#xff1a;用數組去接受&#xff0c;同時用 value-format"YYYY-MM-DD" 格式化值為&#xff1a;年月日格式 <!-- 查詢區域 --><transition name"fade"><div class"search" v-show"showSe…

在 macOS 上安裝 jenv 管理 JDK 版本

在 macOS 上安裝 jenv 并管理 JDK 版本 在開發 Java 應用程序時&#xff0c;你可能需要在不同的項目中使用不同版本的 JDK。手動切換 JDK 版本可能會很繁瑣&#xff0c;但幸運的是&#xff0c;有一個工具可以簡化這個過程&#xff1a;jenv。jenv 是一個流行的 Java 版本管理工…

2025年全國青少年信息素養大賽復賽C++集訓(16):吃糖果2(題目及解析)

2025年全國青少年信息素養大賽復賽C集訓&#xff08;16&#xff09;&#xff1a;吃糖果2&#xff08;題目及解析&#xff09; 題目描述 現有n(50 > n > 0)個糖果,每天只能吃2個或者3個&#xff0c;請計算共有多少種不同的吃法吃完糖果。 時間限制&#xff1a;1000 內存…

ARM筆記-嵌入式系統基礎

第一章 嵌入式系統基礎 1.1嵌入式系統簡介 1.1.1嵌入式系統定義 嵌入式系統定義&#xff1a; 嵌入式系統是以應用為中心&#xff0c;以計算機技術為基礎&#xff0c;軟硬件可剪裁&#xff0c;對功能、可靠性、成本、體積、功耗等有嚴格要求的專用計算機系統 ------Any devic…

大語言模型(LLM)入門項目推薦

推薦大語言模型(LLM)的入門項目 TiaoYu-1。 https://github.com/tiaoyu1122/TiaoYu-1 項目優點&#xff1a; 幾乎每一行代碼(一些重復的代碼除外)都添加了注釋&#xff0c;詳細介紹了代碼的作用&#xff0c;方便閱讀與理解。基本上覆蓋了常見 LLM 模型的全部訓練流程&#x…

Linux里more 和 less的區別

在 Linux/Unix 系統中&#xff0c;more 和 less 都是用于分頁查看文本文件的命令&#xff0c;但 less 是 more 的增強版&#xff0c;功能更強大。以下是它們的核心區別和用法對比&#xff1a; 1. 基礎功能對比 特性moreless&#xff08;更強大&#xff09;向前翻頁? 僅支持向…

基于PDF流式渲染的Word文檔在線預覽技術

一、背景介紹 在系統開發中&#xff0c;實現在線文檔預覽與編輯功能是許多項目的核心需求&#xff0c;但在實際的開發過程中&#xff0c;我們經常會面臨以下難點&#xff1a; 1&#xff09;格式兼容性問題&#xff1a;瀏覽器原生不支持解析Word二進制格式&#xff0c;直接渲染會…

ai學習--python部分-1.變量名及命名空間的存儲

初學代碼時總有一個問題困擾我&#xff1a;a 10 # a指向地址0x1234&#xff08;存儲10&#xff09; 變量a的值10存儲在0x1234&#xff0c;那么變量a需要存儲嗎&#xff1f;a又存儲在什么地址呢 目錄 1. ??命名空間的本質?? 2. ??命名空間的內存占用?? 3. ??…

Leetcode 3563. Lexicographically Smallest String After Adjacent Removals

Leetcode 3563. Lexicographically Smallest String After Adjacent Removals 1. 解題思路2. 代碼實現 題目鏈接&#xff1a;3563. Lexicographically Smallest String After Adjacent Removals 1. 解題思路 這次的最后一題同樣沒有自力搞定&#xff0c;簡直了…… 這道題還…

微信小程序之Promise-Promise初始用

我們來嘗試使用Promise。 1、需求&#xff0c;做個抽獎的按鈕&#xff0c; 抽獎規則&#xff1a; 30%的幾率中獎&#xff0c;中獎會提示恭喜恭喜&#xff0c;獎品為10萬 RMB 勞斯萊斯優惠券&#xff0c;沒中獎會提示再接再厲。 2、先搭界面&#xff1a; <view class&qu…

spring-boot-starter-data-redis應用詳解

一、依賴引入與基礎配置 添加依賴 在 pom.xml 中引入 Spring Data Redis 的 Starter 依賴&#xff0c;默認使用 Lettuce 客戶端&#xff1a; <dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-data-redis<…

全能郵箱全能郵箱:實現郵件管理的自動化!

全能郵箱全能郵箱&#xff1a;實現郵件管理的自動化&#xff01; 全能郵箱全能郵箱的配置教程&#xff1f;如何注冊烽火域名郵箱&#xff1f; 全能郵箱全能郵箱作為一種創新的郵件管理解決方案&#xff0c;正逐漸改變我們處理郵件的方式。蜂郵EDM將圍繞全能郵箱全能郵箱&…

Real2Render2Real:無需動力學仿真或機器人硬件即可擴展機器人數據

25年5月來自UC Berkeley 和 TRI 的論文“Real2Render2Real: Scaling Robot Data Without Dynamics Simulation or Robot Hardware”。 擴展機器人學習需要大量且多樣化的數據集。然而&#xff0c;現行的數據收集范式——人類遙操作——仍然成本高昂&#xff0c;且受到手動操作…

Cadence學習筆記之---PCB的布線與鋪銅

目錄 01 | 引 言 02 | 環境描述 03 | 布 線 04 | 鋪 銅 05 | 總 結 01 | 引 言 在上一篇文章中介紹了Cadence元件放置和布局相關的操作方法和步驟&#xff0c;當完成全部的器件布局后&#xff0c;就可以進行下一步&#xff1b; 本篇文章主要介紹Cadence中布線和鋪銅相關的…

redis-7.4.2 通過 systemd管理,rpmbuild spec文件參考

redis-7 和 redis 5 版本在配置為systemd 方式管理時&#xff0c;配置關于有些許區別&#xff0c;否則會報systemctl status redis 如下錯誤&#xff1a; redis.service: control process exited, codeexited status1 Failed to start Redis persistent key-value database. Un…

2025-05-26 什么是“AI 全棧”

AI全棧&#xff1a;模型 表示學習 向量庫 API UI 一句話定義&#xff1a; ? AI 全棧開發&#xff0c;是指開發者從原始文本/語音/圖像開始&#xff0c;結合大模型能力&#xff0c;構建完整應用閉環的技術能力棧。 AI全棧應用的過程 AI應用 ≠ 一個GPT接口&#xff0c;…

康師傅的“價值戰”答卷:一碗面的創新與擔當

低價策略、口味雷同、營銷跟風……方便面行業曾長期陷于同質化競爭的泥潭&#xff0c;不過近年來&#xff0c;行業競爭邏輯已悄然改變。 一方面來源于宏觀環境的變化&#xff0c;想要在縮量市場下保住大盤&#xff0c;一定要保持逆向思維的能力&#xff0c;另一方面&#xff0…

高性能管線式HTTP請求

高性能管線式HTTP請求:原理、實現與實踐 目錄 高性能管線式HTTP請求:原理、實現與實踐 1. HTTP管線化的原理與優勢 1.1 HTTP管線化的基本概念 關鍵特性: 1.2 管線化的優勢 1.3 管線化的挑戰 2. 高性能管線式HTTP請求的實現方案 2.1 技術選型與工具 2.2 Java實現:…

傳輸線上的信號速度與阻抗無關,主要由頻率決定

阻抗與傳播速度無關 通過計算我們可以知道&#xff0c;導體流過電流時&#xff0c;電子實際上的速度只有1cm/s。是很慢的。 導線的電阻對傳輸線上信號的傳播速度幾乎沒有任何影響。只在一些極端的情況下&#xff0c;互連的電阻才會影響信號的傳播速度&#xff0c;并且這個影響…