趣味數據結構之——鏈

記得數組嗎,一個蘿卜一個坑的想象。在數組的世界里我們就是第三視角,置身于坑外的。如果我們是二維平面上的生物,那數組就是一維的線,我們可以隨機訪問,增刪查改,也可以一眼看出數組大小。

那么對于鏈來說,我們則是一維鏈上的一維生物,所能知道的所有信息(即我們能看到的)就只有鏈定義的信息(比如指向自己當前位置的指針,指向下一個或上一個節點的指針)(這里面的看到,意指我們所掌握的指針)

    //這是雙鏈表template <typename E>class Node {public:E val;Node* next;Node* prev;Node(Node* prev, E element, Node* next) {//這個是構造函數,可以沒有this->val = element;this->next = next;this->prev = prev;}};

顯然按照我們的設想,我們永遠都局限在鏈的一個節點上,永遠都不可能一次性看到整個鏈,就像我們在地球上一樣。于是無法直接計算出鏈的長度,以及無法直接存取,存儲空間并不連續。

增刪→

就很高效了,因為(對于有效鏈)我們一次能看兩個(單向鏈表)或三個結點,那就說明我們可以操作鏈點的鏈接,這也是鏈的核心關鍵。

我們可以銷毀砍掉的結點,也可以鏈上新定義的節點。

而操作的唯一要點就是處理好結點之間的鏈接。(就只有兩條訊息,prev?前驅指針和next?后繼指針)

對于單鏈表,朝且只能朝著著指針指示下一個結點方向走,依次處理好每個結點存儲的指針就好了。(為什么朝且只能朝著呢,因為我們手里的信息就只有那個方向的鄰接結點嘛)

對于雙鏈表,只按一個方向走一遍是不夠的,因為至少結點n本身的指針會被存儲在兩個地方——n+1,和n-1。你需要帶著n的指針前往n-1處和n+1處將它存下。于是想要處理好一個結點就需要處理好這個結點兩端的鏈接處。記住,鏈接處只和與之相連的兩個結點有關系。(這時候就可以不止往兩個方向走了,因為我們在結點處手頭可是握有兩個方向的訊息)

定義單鏈表→

本結點的存儲,后繼結點的訊息(指針)

class ListNode {
public:int val;ListNode *next;ListNode(int x) : val(x), next(NULL) {}
};// 輸入一個數組,轉換為一條單鏈表
ListNode* createLinkedList(std::vector<int> arr) {if (arr.empty()) {return nullptr;}ListNode* head = new ListNode(arr[0]);ListNode* cur = head;for (int i = 1; i < arr.size(); i++) {cur->next = new ListNode(arr[i]);cur = cur->next;}return head;
}

查/改→

// 創建一條單鏈表
ListNode* head = createLinkedList({1, 2, 3, 4, 5});// 遍歷單鏈表
for (ListNode* p = head; p != nullptr; p = p->next) {std::cout << p->val << std::endl;
}

增→

需要處理被增結點n,那就需要處理它兩端的鏈接處,需要處理好鏈接處,那就只和鏈接處接壤的結點有關,所以這里只要處理好三個結點里的信息存儲(即指針)就好了。

插入頭部→

// 創建一條單鏈表
ListNode* head = createLinkedList({1, 2, 3, 4, 5});// 在單鏈表頭部插入一個新節點 0
ListNode* newNode = new ListNode(0);
newNode->next = head;
head = newNode;// 現在鏈表變成了 0 -> 1 -> 2 -> 3 -> 4 -> 5

插入尾部→

// 創建一條單鏈表
ListNode* head = createLinkedList({1, 2, 3, 4, 5});// 在單鏈表尾部插入一個新節點 6
ListNode* p = head;
// 先走到鏈表的最后一個節點
while (p->next != nullptr) {p = p->next;
}
// 現在 p 就是鏈表的最后一個節點
// 在 p 后面插入新節點
p->next = new ListNode(6);// 現在鏈表變成了 1 -> 2 -> 3 -> 4 -> 5 -> 6

插入中間→

// 創建一條單鏈表
ListNode* head = createLinkedList({1, 2, 3, 4, 5});// 在第 3 個節點后面插入一個新節點 66
// 先要找到前驅節點,即第 3 個節點
ListNode* p = head;
for (int i = 0; i < 2; i++) {p = p->next;
}
// 此時 p 指向第 3 個節點
// 組裝新節點的后驅指針
ListNode* newNode = new ListNode(66);
newNode->next = p->next;// 插入新節點
p->next = newNode;// 現在鏈表變成了 1 -> 2 -> 3 -> 66 -> 4 -> 5

刪中間→

// 創建一條單鏈表
ListNode* head = createLinkedList({1, 2, 3, 4, 5});// 刪除第 4 個節點,要操作前驅節點
ListNode* p = head;
for (int i = 0; i < 2; i++) {p = p->next;
}// 此時 p 指向第 3 個節點,即要刪除節點的前驅節點
// 把第 4 個節點從鏈表中摘除
p->next = p->next->next;// 現在鏈表變成了 1 -> 2 -> 3 -> 5

刪尾部→

// 創建一條單鏈表
ListNode* head = createLinkedList({1, 2, 3, 4, 5});// 刪除尾節點
ListNode* p = head;
// 找到倒數第二個節點
while (p->next->next != nullptr) {p = p->next;
}// 此時 p 指向倒數第二個節點
// 把尾節點從鏈表中摘除
p->next = nullptr;// 現在鏈表變成了 1 -> 2 -> 3 -> 4

刪頭部→

// 創建一條單鏈表
ListNode* head = createLinkedList(vector<int>{1, 2, 3, 4, 5});// 刪除頭結點
head = head->next;// 現在鏈表變成了 2 -> 3 -> 4 -> 5

同理對于雙鏈表也就很簡單了,處理好各個結點存儲的訊息就完事大吉了

定義

class DoublyListNode {
public:int val;DoublyListNode *next, *prev;DoublyListNode(int x) : val(x), next(NULL), prev(NULL) {}
};DoublyListNode* createDoublyLinkedList(vector<int>& arr) {if (arr.empty()) {return NULL;}DoublyListNode* head = new DoublyListNode(arr[0]);DoublyListNode* cur = head;// for 循環迭代創建雙鏈表for (int i = 1; i < arr.size(); i++) {DoublyListNode* newNode = new DoublyListNode(arr[i]);cur->next = newNode;newNode->prev = cur;cur = cur->next;}return head;
}

遍歷/查找/修改

// 創建一條雙鏈表
DoublyListNode* head = createDoublyLinkedList({1, 2, 3, 4, 5});
DoublyListNode* tail = nullptr;// 從頭節點向后遍歷雙鏈表
for (DoublyListNode* p = head; p != nullptr; p = p->next) {cout << p->val << endl;tail = p;
}// 從尾節點向前遍歷雙鏈表
for (DoublyListNode* p = tail; p != nullptr; p = p->prev) {cout << p->val << endl;
}

頭部插入→

// 創建一條雙鏈表
DoublyListNode* head = createDoublyLinkedList({1, 2, 3, 4, 5});// 在雙鏈表頭部插入新節點 0
DoublyListNode* newHead = new DoublyListNode(0);
newHead->next = head;
head->prev = newHead;
head = newHead;// 現在鏈表變成了 0 -> 1 -> 2 -> 3 -> 4 -> 5

尾部插入→

// 創建一條雙鏈表
DoublyListNode* head = createDoublyLinkedList({1, 2, 3, 4, 5});DoublyListNode* tail = head;
// 先走到鏈表的最后一個節點
while (tail->next != nullptr) {tail = tail->next;
}// 在雙鏈表尾部插入新節點 6
DoublyListNode* newNode = new DoublyListNode(6);
tail->next = newNode;
newNode->prev = tail;
// 更新尾節點引用
tail = newNode;// 現在鏈表變成了 1 -> 2 -> 3 -> 4 -> 5 -> 6

中間插入→

// 創建一條雙鏈表
DoublyListNode* head = createDoublyLinkedList({1, 2, 3, 4, 5});// 想要插入到索引 3(第 4 個節點)
// 需要操作索引 2(第 3 個節點)的指針
DoublyListNode* p = head;
for (int i = 0; i < 2; i++) {p = p->next;
}// 組裝新節點
DoublyListNode* newNode = new DoublyListNode(66);
newNode->next = p->next;
newNode->prev = p;// 插入新節點
p->next->prev = newNode;
p->next = newNode;// 現在鏈表變成了 1 -> 2 -> 3 -> 66 -> 4 -> 5

刪中間→

// 創建一個雙鏈表
DoublyListNode* head = createDoublyLinkedList({1, 2, 3, 4, 5});// 刪除第 4 個節點
// 先找到第 3 個節點
DoublyListNode* p = head;
for (int i = 0; i < 2; ++i) {p = p->next;
}// 現在 p 指向第 3 個節點,我們將它后面那個節點摘除出去
DoublyListNode* toDelete = p->next;// 把 toDelete 從鏈表中摘除
p->next = toDelete->next;
toDelete->next->prev = p;// 把 toDelete 的前后指針都置為 null 是個好習慣(可選)
toDelete->next = nullptr;
toDelete->prev = nullptr;// 現在鏈表變成了 1 -> 2 -> 3 -> 5

刪頭部→

// 創建一條雙鏈表
DoublyListNode* head = createDoublyLinkedList({1, 2, 3, 4, 5});// 刪除頭結點
DoublyListNode* toDelete = head;
head = head->next;
head->prev = nullptr;// 清理已刪除節點的指針
toDelete->next = nullptr;// 現在鏈表變成了 2 -> 3 -> 4 -> 5

刪尾部→

// 創建一條雙鏈表
DoublyListNode* head = createDoublyLinkedList({1, 2, 3, 4, 5});// 刪除頭結點
DoublyListNode* toDelete = head;
head = head->next;
head->prev = nullptr;// 清理已刪除節點的指針
toDelete->next = nullptr;// 現在鏈表變成了 2 -> 3 -> 4 -> 5

總結,在鏈表的定義和操作中,我們要且僅要關注的要點,我們手頭握有的訊息(指針(方向)),處理好鏈接處(也就是處理好每個結點中存儲的訊息,這事關鏈表的結構)。

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

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

相關文章

構建低代碼平臺的技術解析

低代碼平臺表單引擎與業務事件設計實踐 低代碼平臺表單引擎與業務事件設計實踐一、什么是低代碼&#xff1f;它能做什么&#xff1f;二、請假系統案例介紹2.1 主要功能2.2 業務流程 三、表單元數據、實例數據與業務事件聯動設計3.1 表單元數據&#xff08;Meta&#xff09;如何…

Hive SQL 快速入門指南

在大數據蓬勃發展的當下&#xff0c;處理海量數據成為企業面臨的關鍵挑戰。Hive SQL 作為一款強大的工具&#xff0c;為我們打開了高效處理大數據的大門。接下來&#xff0c;讓我們一起踏上 Hive SQL 的入門之旅。? 一、Hive SQL 是什么? Hive 是基于 Hadoop 的數據倉庫工具…

國內公司把數據湖做成了數據庫

在做多年的數據倉庫項目&#xff0c;數據湖也在做&#xff0c;但是做完發現&#xff0c;這個不是傳統數據庫里面的ODS嗎&#xff1f; 好多公司做數據湖&#xff0c;就是把數據湖做成了ODS層&#xff08;貼源數據層&#xff09;&#xff0c;難道真的數據湖就是這樣等于ODS嗎&am…

Python 數據分析與可視化 Day 6 - 可視化整合報告實戰

&#x1f3af; 今日目標 整合數據分析與可視化結果生成結構化報告用代碼自動生成完整的圖文分析文檔熟悉 Jupyter Notebook / Markdown 圖表 報告生成流程 &#x1f9e9; 一、項目背景&#xff1a;學生成績分析報告 數據來源&#xff1a;students_cleaned.csv&#xff08;含姓…

服務器、樹莓派/香橙派部署HomeAssistant與小愛音箱聯動

HomeAssistant功能介紹與多平臺部署實戰&#xff1a;CentOS服務器、樹莓派、香橙派部署及小愛音箱聯動控制 一、HomeAssistant簡介 HomeAssistant是一款基于Python開發的開源智能家居自動化平臺&#xff0c;它最大的特點是高度集成和自定義。通過HomeAssistant&#xff0c;用…

內存泄漏系列專題分析之二十四:內存泄漏測試Camera相機進程內存指標分布report概述

【關注我,后續持續新增專題博文,謝謝!!!】 上一篇我們講了: 這一篇我們開始講: 內存泄漏系列專題分析之二十四:內存泄漏測試Camera相機進程內存指標分布report概述 目錄 一、問題背景 二、:內存泄漏測試Camera相機進程內存指標分布report概述 2.1:Camera領域相機進…

華為堆疊理論及配置

一&#xff0c;堆疊基本概念 1.1交換機角色 主交換機&#xff08;Master&#xff09;&#xff1a;主交換機負責管理整個堆疊。**堆疊系統中只有一臺主交換機。**備交換機&#xff08;Standby&#xff09;&#xff1a;備交換機是主交換機的備份交換機。堆疊系統中只有一臺備交換…

【數字經濟】數據即產品架構在數字經濟時代的應用

數據即產品架構在數字經濟時代的應用 在數字經濟中&#xff0c;數據已成為核心生產要素&#xff0c;“數據即產品”&#xff08;Data-as-a-Product&#xff09;架構通過系統化封裝原始數據&#xff0c;實現其可交易、可交付的產品化價值。以下是其架構設計與應用解析&#xff…

MySQL 中的時間序列數據分析與處理

在互聯網應用和企業業務系統中&#xff0c;特別是現在當下環境電商以及跨境電商火爆的情況下&#xff0c;時間序列數據無處不在&#xff0c;如電商訂單時間、用戶登錄日志、設備監控數據等。MySQL 作為主流數據庫&#xff0c;具備強大的時間序列數據處理能力。本文將結合電商訂…

STM32——MDK5編譯和串口下載程序+啟動模式

一、MDK5編譯 1.1 編譯中間文件 還可通過 .map文件計算程序大小 中間文件 > 下載到開發板中的文件 > .hex 二、串口下載 2.1 前提須知 2.2 串口硬件鏈接&#xff08;M3、M4系列&#xff09; M7無串口下載 PC端需安裝 CH340 USB 虛擬串口驅動&#xff1a;CH340 USB 虛…

HyperWorks仿真案例:拓撲優化與激光增材制造的完美結合挖掘輕量化結構的新潛力

許多技術創新都基于自然界中生物結構的設計。通過不斷進化&#xff0c;大自然在數百萬年間已學會根據各種形狀的功能對形狀進行調整&#xff0c;從而最大程度地提高效率。當工程師設法構建堅固而輕盈的結構時&#xff0c;這些自然界中的示例可以提供重要線索。在目前的研究項目…

在Windows系統部署本地智能問答系統:基于百度云API完整教程

引言 在人工智能時代&#xff0c;搭建私有化智能問答系統能有效保護數據隱私并提升響應效率。本教程將手把手教你在Windows環境中&#xff0c;通過百度云API構建專屬智能問答系統&#xff0c;全程無需服務器&#xff0c;僅需本地計算機即可運行&#xff01; 一、環境準備 系統…

Vue的watch函數實現

<script setup> import { watch, ref, reactive, toRefs } from vue;const count ref(0); const obj reactive({name: 張三,age: 18 });// 我們可以使用toRefs&#xff0c;將reactive對象中的屬性轉換為ref對象&#xff0c;保持響應性&#xff01;&#xff01; const {…

Tomcat 安裝使用教程

&#x1f4cc; 什么是 Tomcat&#xff1f; Apache Tomcat 是一個開源的 Java Servlet 容器&#xff0c;也是運行 Java Web 應用最常用的服務器之一&#xff0c;支持 Servlet、JSP 等規范。 &#x1f9f0; 一、準備工作 1. 系統要求 操作系統&#xff1a;Windows / Linux / m…

【邀請】點擊邀請鏈接參加阿里云訓練營活動,完成學習送禮品+戶外折疊凳,一個小時就能完成

點擊邀請鏈接參加阿里云訓練營活動&#xff0c;完成學習送禮品戶外折疊凳&#xff0c;快的話一個小時就能完成。 7月28日23:59前完成。 OSS進階應用與成本優化訓練營 禮品如下&#xff1a; 包尖鋼筆/祈福小神仙積木/雨傘/不銹鋼餐具隨機發放 戶外折疊凳

用戶行為序列建模(篇六)-【阿里】DSIN

簡介 DSIN&#xff08;Deep Session Interest Network&#xff09;是阿里巴巴于2019年提出的點擊率預估模型。相比于DIN、DIEN&#xff0c;考慮了用戶行為序列的內在結構&#xff08;序列是由session組成的&#xff0c;在每個session內&#xff0c;用戶行為是高度同構的&#…

現代Web表情選擇器組件:分類系統與實現詳解

你好呀&#xff0c;我是小鄒。今天給博客的emoji表情進行了歸類、補充&#xff0c;具體優化如下。 表情選擇器的核心價值在于其分類系統。本文將深入解析表情分類體系的設計與實現&#xff0c;通過完整代碼示例展示如何構建一個專業級的表情選擇器組件。 一、表情分類系統設計…

華為云Flexus+DeepSeek征文 |華為云ModelArts Studio集成OpenAI Translator:開啟桌面級AI翻譯新時代

華為云FlexusDeepSeek征文 |華為云ModelArts Studio集成OpenAI Translator&#xff1a;開啟桌面級AI翻譯新時代 引言一、ModelArts Studio平臺介紹華為云ModelArts Studio簡介ModelArts Studio主要特點 二、OpenAI Translator介紹openai-translator簡介openai-translator主要特…

GitHub 趨勢日報 (2025年06月27日)

&#x1f4ca; 由 TrendForge 系統生成 | &#x1f310; https://trendforge.devlive.org/ &#x1f310; 本日報中的項目描述已自動翻譯為中文 &#x1f4c8; 今日獲星趨勢圖 今日獲星趨勢圖 817 twenty 655 awesome 476 free-for-dev 440 Best-websites-a-programmer-shoul…

Java語法通關秘籍:this、構造方法到String核心精粹

文章目錄 &#x1f50d; **一、就近原則與this關鍵字**1. **成員變量**2. **局部變量** &#x1f6e0;? **二、構造方法&#xff08;構造器&#xff09;**1. **標準格式**2. **有參構造實戰**3. **靈魂三問** ? &#x1f4e6; **三、JavaBean黃金標準**&#x1f9e0; **四、對…