趣味數據結構之——數組

你們一定都聽說過它的故事……

是的沒錯,就是一個蘿卜一個坑。???

想象一下數組就是那個坑,那么定義數組就是在挖坑。

元素就是蘿卜。

坑就在那里(地上),整整齊齊地排在那里。

于是數組最重要的一個特性就顯現出來了——隨機存取。還有一個特性就是它在內存里開辟的是一整塊的連續空間,是多少就是多少。一眼望去也可以看出來它是多少。

// 定義一個大小為 10 的靜態數組
int arr[10];// 用 memset 函數把數組的值初始化為 0
memset(arr, 0, sizeof(arr));// 使用索引賦值
arr[0] = 1;
arr[1] = 2;// 使用索引取值
int a = arr[0];

數據定義(安放)的事情我們解決了,下面就是操作了——增刪查改

按理來說我們希望“增刪查改后的數組仍然還是個數組”,就是按順序去看,一個蘿卜一個坑,可以短,但中間不能又空缺的

在尾部增刪查改都好說,可在頭部或者中間就不一樣了。因為會造成空缺!!!

于是就涉及到了「數據搬移」。需要騰位置的騰位置,需要擠一下的擠一下。

插入→

// 大小為 10 的數組已經裝了 4 個元素
int arr[10];
for (int i = 0; i < 4; i++) {arr[i] = i;
}// 在索引 2 置插入元素 666
// 需要把索引 2 以及之后的元素都往后移動一位
// 注意要倒著遍歷數組中已有元素避免覆蓋,不懂的話請看下方可視化面板
for (int i = 4; i > 2; i--) {arr[i] = arr[i - 1];
}// 現在第 3 個位置空出來了,可以插入新元素
arr[2] = 666;

擴容→

// 大小為 10 的數組已經裝滿了
int arr[10];
for (int i = 0; i < 10; i++) {arr[i] = i;
}// 現在想在數組末尾追加一個元素 10
// 需要先擴容數組
int newArr[20];
// 把原來的 10 個元素復制過去
for (int i = 0; i < 10; i++) {newArr[i] = arr[i];
}// 釋放舊數組的內存空間
// ...// 在新的大數組中追加新元素
newArr[10] = 10;

刪除→

// 大小為 10 的數組已經裝了 5 個元素
int arr[10];
for (int i = 0; i < 5; i++) {arr[i] = i;
}// 刪除 arr[1]
// 需要把 arr[1] 之后的元素都往前移動一位
// 注意要正著遍歷數組中已有元素避免覆蓋,不懂的話請看下方可視化面板
for (int i = 1; i < 4; i++) {arr[i] = arr[i + 1];
}// 最后一個元素置為 -1 代表已刪除
arr[4] = -1;

數組的插入、擴容、刪除的時間復雜度是O(N),因為涉及到數據搬移,給新元素騰地方

是的這就是靜態數組,就是這么簡單。

Then,動態數組它要來咯!!!

動態數組其實就是我們找了個兔子搬運工。?_?

動態數組底層還是靜態數組,只是自動幫我們進行數組空間的擴縮容,并把增刪查改操作進行了封裝,讓我們使用起來更方便而已。

即C++提供給我們的vector類。?o?

// 創建動態數組
// 不用顯式指定數組大小,它會根據實際存儲的元素數量自動擴縮容
vector<int> arr;for (int i = 0; i < 10; i++) {// 在末尾追加元素,時間復雜度 O(1)arr.push_back(i);
}// 在中間插入元素,時間復雜度 O(N)
// 在索引 2 的位置插入元素 666
arr.insert(arr.begin() + 2, 666);// 在頭部插入元素,時間復雜度 O(N)
arr.insert(arr.begin(), -1);// 刪除末尾元素,時間復雜度 O(1)
arr.pop_back();// 刪除中間元素,時間復雜度 O(N)
// 刪除索引 2 的元素
arr.erase(arr.begin() + 2);// 根據索引查詢元素,時間復雜度 O(1)
int a = arr[0];// 根據索引修改元素,時間復雜度 O(1)
arr[0] = 100;// 根據元素值查找索引,時間復雜度 O(N)
int index = find(arr.begin(), arr.end(), 666) - arr.begin();

???

???

???

(枯燥的)動態數組代碼實現

#include <iostream>
#include <stdexcept>
#include <vector>template<typename E>
class MyArrayList {
private:// 真正存儲數據的底層數組E* data;// 記錄當前元素個數int size;// 最大元素容量int cap;// 默認初始容量static const int INIT_CAP = 1;public:MyArrayList() {this->data = new E[INIT_CAP];this->size = 0;this->cap = INIT_CAP;}MyArrayList(int initCapacity) {this->data = new E[initCapacity];this->size = 0;this->cap = initCapacity;}// 增void addLast(E e) {// 看 data 數組容量夠不夠if (size == cap) {resize(2 * cap);}// 在尾部插入元素data[size] = e;size++;}void add(int index, E e) {// 檢查索引越界checkPositionIndex(index);// 看 data 數組容量夠不夠if (size == cap) {resize(2 * cap);}// 搬移數據 data[index..] -> data[index+1..]// 給新元素騰出位置for (int i = size - 1; i >= index; i--) {data[i + 1] = data[i];}// 插入新元素data[index] = e;size++;}void addFirst(E e) {add(0, e);}// 刪E removeLast() {if (size == 0) {throw std::out_of_range("NoSuchElementException");}// 可以縮容,節約空間if (size == cap / 4) {resize(cap / 2);}E deletedVal = data[size - 1];// 刪除最后一個元素// 必須給最后一個元素置為 null,否則會內存泄漏data[size - 1] = E();size--;return deletedVal;}E remove(int index) {// 檢查索引越界checkElementIndex(index);// 可以縮容,節約空間if (size == cap / 4) {resize(cap / 2);}E deletedVal = data[index];// 搬移數據 data[index+1..] -> data[index..]for (int i = index + 1; i < size; i++) {data[i - 1] = data[i];}data[size - 1] = E();size--;return deletedVal;}E removeFirst() {return remove(0);}// 查E get(int index) {// 檢查索引越界checkElementIndex(index);return data[index];}// 改E set(int index, E element) {// 檢查索引越界checkElementIndex(index);// 修改數據E oldVal = data[index];data[index] = element;return oldVal;}// 工具方法int getSize() {return size;}bool isEmpty() {return size == 0;}// 將 data 的容量改為 newCapvoid resize(int newCap) {E* temp = new E[newCap];for (int i = 0; i < size; i++) {temp[i] = data[i];}// 釋放原數組內存delete[] data;data = temp;cap = newCap;}bool isElementIndex(int index) {return index >= 0 && index < size;}bool isPositionIndex(int index) {return index >= 0 && index <= size;}// 檢查 index 索引位置是否可以存在元素void checkElementIndex(int index) {if (!isElementIndex(index)) {throw std::out_of_range("Index out of bounds");}}// 檢查 index 索引位置是否可以添加元素void checkPositionIndex(int index) {if (!isPositionIndex(index)) {throw std::out_of_range("Index out of bounds");}}void display() {std::cout << "size = " << size << " cap = " << cap << std::endl;for (int i = 0; i < size; i++) {std::cout << data[i] << " ";}std::cout << std::endl;}~MyArrayList() {delete[] data;}
};int main() {// 初始容量設置為 3MyArrayList<int> arr(3);// 添加 5 個元素for (int i = 1; i <= 5; i++) {arr.addLast(i);}arr.remove(3);arr.add(1, 9);arr.addFirst(100);int val = arr.removeLast();// 100 1 9 2 3for (int i = 0; i < arr.getSize(); i++) {std::cout << arr.get(i) << std::endl;}return 0;
}

有兩個檢查越界的方法,分別是?checkElementIndex?和?checkPositionIndex,你可以看到它倆的區別僅僅在于?index < size?和?index <= size

C++動態數組vector的底層是連續的內存空間,普通的數組,并不使用環形數組

擴展

環形數組

通過取模運算實現。

會方便在頭部增刪元素,避免了數據搬移

環形數組的關鍵在于,它維護了兩個指針?start?和?endstart?指向第一個有效元素的索引,end?指向最后一個有效元素的下一個位置索引。

這樣,當我們在數組頭部添加或刪除元素時,只需要移動?start?索引,而在數組尾部添加或刪除元素時,只需要移動?end?索引。

當?start, end?移動超出數組邊界(< 0?或?>= arr.length)時,我們可以通過求模運算?%?讓它們轉一圈到數組頭部或尾部繼續工作,這樣就實現了環形數組的效果。

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

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

相關文章

PR-2025《Scaled Robust Linear Embedding with Adaptive Neighbors Preserving》

核心思想分析 這篇論文的核心思想在于解決線性嵌入&#xff08;linear embedding&#xff09;與非線性流形結構之間的不匹配問題。傳統方法通過保留樣本點間的親和關系來提取數據的本質結構&#xff0c;但這種方法在某些情況下無法有效捕捉到數據的全局或局部特性。此外&#…

Redis-漸進式遍歷

之前使用的keys查找key,一次獲取到了所有的key,當key較多時,這個操作就有可能造成Redis服務器阻塞.特別是keys *操作. 于是可以通過漸進式遍歷,每次獲取部分key,通過多次遍歷,既查詢到了所有的key,又不會卡死服務器. 漸進式遍歷不是通過一個命令獲取到所有元素的,而是由一組命…

ISP Pipeline(3):Lens Shading Correction 鏡頭陰影校正

上一篇文章講的是&#xff1a;ISP Pipeline&#xff08;2&#xff09;&#xff1a; Black Level Compensation:ISP Pipeline&#xff08;2&#xff09;&#xff1a;Black Level Compensation 黑電平補償-CSDN博客 視頻&#xff1a;(4) Lens Shading Correction | Image Signal…

什么是WebAssembly(WASM)

WebAssembly&#xff08;WASM&#xff09; 是一種高性能的低級編程語言字節碼格式&#xff0c;可在網頁和非網頁環境中運行&#xff0c;支持多語言編譯&#xff0c;運行速度接近原生代碼。它在區塊鏈中的作用是&#xff1a;作為智能合約的執行引擎&#xff0c;被多條非以太坊鏈…

【C++】inline的作用

一、inline的作用 1.1函數內聯 作用?&#xff1a;建議編譯器將函數調用替換為函數體代碼&#xff0c;減少函數調用的開銷&#xff08;壓棧/跳轉&#xff09;。?注意?&#xff1a;這只是對編譯器的建議&#xff0c;編譯器可能忽略&#xff08;如函數體過大或遞歸&#xff0…

代碼隨想錄|圖論|04廣度優先搜索理論基礎

廣搜的使用場景 廣搜的搜索方式就適合于解決兩個點之間的最短路徑問題。 因為廣搜是從起點出發&#xff0c;以起始點為中心一圈一圈進行搜索&#xff0c;一旦遇到終點&#xff0c;記錄之前走過的節點就是一條最短路。 當然&#xff0c;也有一些問題是廣搜 和 深搜都可以解決…

Xposed框架深度解析:Android系統級Hook實戰指南

引言:Android系統定制化的革命性突破 在移動安全研究和系統優化領域,傳統的APP修改方案面臨??三重技術瓶頸??: ??逆向工程壁壘??:APK重打包方案需處理簽名校驗、代碼混淆等防護,平均耗時增加200%??兼容性挑戰??:Android碎片化導致設備適配率不足65%??功能…

大模型在通訊網絡中的系統性應用架構

一、網絡架構智能化重構?? ??1.1 空天地一體化組網優化?? 智能拓撲動態調整??&#xff1a;大模型通過分析衛星軌道數據、地面基站負載及用戶分布&#xff0c;實時優化天地一體化網絡拓撲。例如&#xff0c;在用戶密集區域&#xff08;如城市中心&#xff09;自動增強低…

軟件測試進階:Python 高級特性與數據庫優化(第二階段 Day6)

在掌握 SQL 復雜查詢和 Python 數據庫基礎操作后&#xff0c;第六天將深入探索Python 高級編程特性與數據庫性能優化。通過掌握 Python 的模塊與包管理、裝飾器等高級語法&#xff0c;結合數據庫索引優化、慢查詢分析等技術&#xff0c;提升測試工具開發與數據處理效率。 一、…

【NLP】自然語言項目設計04

目錄 04模型驗證 代碼架構核心設計說明 05運行推理 代碼架構核心設計說明 項目展望 項目簡介 訓練一個模型&#xff0c;實現歌詞仿寫生成 任務類型&#xff1a;文本生成&#xff1b; 數據集是一份歌詞語料&#xff0c;訓練一個模型仿寫歌詞。 要求 1.清洗數據。歌詞語料…

數據結構1 ——數據結構的基本概念+一點點算法

數據結構算法程序設計 什么是數據結構 數據&#xff08;data&#xff09;&#xff1a;符號集合&#xff0c;處理對象。 數據元素&#xff08;data element&#xff09;&#xff0c;由數據項&#xff08;data item&#xff09; 組成。 關鍵字&#xff08;key&#xff09;識別…

每日八股文7.1

每日八股-7.1 網絡1.能說說 TCP 報文頭部都包含哪些關鍵字段嗎&#xff1f;2.TCP 是如何確保數據傳輸的可靠性的&#xff1f;你能詳細談談嗎&#xff1f;3.你能解釋一下 TCP 滑動窗口是如何設計的&#xff1f;它主要解決了什么問題&#xff1f;4.TCP 協議的擁塞控制是如何實現的…

高性能 List 轉 Map 解決方案(10,000 元素)

文章目錄 前言一、問題背景&#xff1a;為什么List轉Map如此重要&#xff1f;二、基礎方法對比&#xff1a;Stream vs For循環三、性能優化關鍵點四、面試回答技巧 前言 遇到一個有意思的面試題&#xff0c;如標題所說&#xff0c;當10,000條數據的List需要轉Map&#xff0c;如…

今日行情明日機會——20250701

上證指數縮量收陽線&#xff0c;形成日線上漲中繼&#xff0c;個股上漲和下跌總體持平。 深證指數量能持續放大&#xff0c;即將回補缺口位&#xff0c;短線注意周三或周四的調整。 2025年7月1日漲停股主要行業方向分析 1. 芯片&#xff08;17家漲停&#xff0c;國產替代&…

P1312 [NOIP 2011 提高組] Mayan 游戲

題目描述 Mayan puzzle 是最近流行起來的一個游戲。游戲界面是一個 7 7 7 行 5 \times5 5 列的棋盤&#xff0c;上面堆放著一些方塊&#xff0c;方塊不能懸空堆放&#xff0c;即方塊必須放在最下面一行&#xff0c;或者放在其他方塊之上。游戲通關是指在規定的步數內消除所有…

Spring Boot 2 多模塊項目中配置文件的加載順序

Spring Boot 2 多模塊項目中配置文件的加載順序 在 Spring Boot 2 多模塊項目中&#xff0c;配置文件的加載遵循特定的順序規則。了解這些規則對于正確管理多模塊應用的配置至關重要。 一、默認配置文件加載順序 Spring Boot 會按照以下順序加載 application.properties 或 …

邊界的藝術:支持向量機與統計學習時代的王者

當揚勒丘恩的卷積神經網絡LeNet在90年代初于手寫數字識別領域綻放光芒&#xff0c;卻因計算與數據的桎梏未能點燃更廣泛的燎原之火時&#xff0c;人工智能&#xff0c;特別是其子領域機器學習&#xff0c;正步入一個理論深化與方法論多元化的關鍵時期。經歷了符號主義通用智能探…

js filter()

listType(queryParams.value).then(response > {filterTable.value response.rows.slice(1); // 只顯示前3條數據;filterTable.value filterTable.value.filter(item > {return wnSensorsList.value.some(sensorsgroup > {return sensorsgroup.sensorType item.cod…

Python 庫 包 nltk (Natural Language Toolkit)

文章目錄 &#x1f9f0; 一、nltk 的主要功能? 文本處理功能? 內置語料庫&#xff08;Corpora&#xff09; &#x1f4e6; 二、安裝與使用1. 安裝 nltk2. 下載語料庫&#xff08;第一次使用時需要下載&#xff09; &#x1f50d; 三、常用功能示例示例 1&#xff1a;分詞示例…

設計模式之房產中介——代理模式

手撕設計模式之房產中介——代理模式 1.業務需求 ? 大家好&#xff0c;我是菠菜啊&#xff0c;好久不見&#xff0c;今天給大家帶來的是——代理模式。老規矩&#xff0c;在介紹這期內容前&#xff0c;我們先來看看這樣的需求&#xff1a;我們有一套房產需要出售&#xff0c…