【初階數據結構】雙向鏈表

在這里插入圖片描述

文章目錄

  • 雙向鏈表
    • 1.申請節點
    • 2.鏈表初始化
    • 3.尾插
    • 4.打印鏈表
    • 5.頭插
    • 6.尾刪
    • 7.頭刪
    • 8.查找
    • 9.指定位置插入
    • 10.刪除pos節點
    • 11.鏈表的銷毀
    • 12.程序源碼

雙向鏈表

鏈表分類 8種 (帶頭/不帶頭 單向/雙向 循環/循環)
最常用兩種 單鏈表(不帶頭單向不循環鏈表) 雙向鏈表(帶頭雙向循環鏈表)

雙鏈表有 頭節點(哨兵位) 后繼指針(next) 前驅指針(prev)

雙向鏈表為空時,為一個哨兵位

同樣采用多文件操作

在這里插入圖片描述

1.申請節點

//申請節點
LTNode* LTBuyNode(LTDataType x)
{LTNode* node = (LTNode*)malloc(sizeof(LTNode));if (node == NULL)//申請不成功{perror("malloc fail");exit(1);//給非0值}node->data = x;node->next = node->prev = node;return node;
}

2.鏈表初始化

void LTInit(LTNode** pphead)
{//給雙向鏈表創建一個哨兵位*pphead = LTBuyNode(-1);//隨便賦一個值
}

3.尾插

在這里插入圖片描述

以上圖為例 尾插時 head->prev指向的就是d3

void LTPushBack(LTNode* phead, LTDataType x)
{assert(phead);LTNode* newnode = LTBuyNode(x);//phead phead->prev newnodenewnode->prev = phead->prev;//也就是newnode->prev指向d3newnode->next = phead;phead->prev->next = newnode;//d3的next指針指向新節點phead->prev = newnode;
}

4.打印鏈表

在這里插入圖片描述

讓pcur指向phead的next指針,然后遍歷鏈表,直到pcur=phead

void LTPrint(LTNode* phead)
{LTNode* pcur = phead->next;while (pcur != phead){printf("%d->", pcur->data);pcur = pcur->next;}printf("\n");
}

5.頭插

頭插是插到頭結點與d1之間,插在頭結點前邊跟尾插一樣(因為鏈表是雙向循環的)

在這里插入圖片描述

void LTPushFront(LTNode* phead, LTDataType x)
{assert(phead);LTNode* newnode = LTBuyNode(x);newnode->next = phead->next;newnode->prev = phead;phead->next->prev = newnode;//先改影響小的phead->next = newnode;}

6.尾刪

在這里插入圖片描述

void LTPopBack(LTNode* phead)
{//鏈表必須有效且鏈表不能為空assert(phead && phead->next != phead);LTNode* del = phead->prev;del->prev->next = phead;phead->prev = del->prev;//刪除del節點free(del);del = NULL;}

7.頭刪

在這里插入圖片描述

void LTPopFront(LTNode* phead)
{assert(phead && phead->next != phead);LTNode* del = phead->next;phead->next = del->next;del->next->prev = phead;//刪除del節點free(del);del = NULL;
}

8.查找

LTNode* LTFind(LTNode* phead, LTDataType x)
{LTNode* pcur = phead->next;while (pcur != phead){if (pcur->data == x){return pcur;}pcur = pcur->next;}//沒有找到return NULL;
}

9.指定位置插入

在這里插入圖片描述

10.刪除pos節點

在這里插入圖片描述

void LTErase(LTNode* pos)//這里傳一級指針是為了保持接口的一致性 其他函數傳的都是一級指針
{//pos理論上來說不能為phead,但是參數沒有phead,所以無法增加校驗pos->next->prev = pos->prev;pos->prev->next = pos->next;free(pos);pos = NULL;
}

11.鏈表的銷毀

在這里插入圖片描述

void LTDesTroy(LTNode* phead)
{assert(phead);LTNode* pcur = phead->next;while (pcur->next != phead){LTNode* next = pcur->next;free(pcur);pcur = next;}//此時pcur指向phead,而phead還沒有被銷毀free(phead);phead = NULL;//如果不置為空 plist(保存的地址空間被釋放掉了) 若后續不再使用plist則沒問題(野指針)}

12.程序源碼

List.h

#pragma once
#include<stdio.h>
#include<stdlib.h>
#include<assert.h>typedef int LTDataType;
//定義雙向鏈表節點的結構
typedef struct ListNode
{LTDataType data;struct ListNode* next;struct ListNode* prev;}LTNode;//聲明雙向鏈表種提供的方法//初始化
void LTInit(LTNode** pphead);
void LTPrint(LTNode* phead);
//插入數據之前,鏈表必須初始化到只有一個頭結點的情況
// 不改變哨兵位的地址,所以傳一級指針即可
//尾插
void LTPushBack(LTNode* phead,LTDataType x);
//頭插
void LTPushFront(LTNode* phead, LTDataType x);void LTPopBack(LTNode* phead);
void LTPopFront(LTNode* phead);
//在pos位置之后插入數據
void LTInsert(LTNode* pos, LTDataType x);
void LTErase(LTNode* pos);
//查找
LTNode* LTFind(LTNode* phead, LTDataType x);void LTDesTroy(LTNode* phead);

List.c

#include"List.h";void LTPrint(LTNode* phead)
{LTNode* pcur = phead->next;while (pcur != phead){printf("%d->", pcur->data);pcur = pcur->next;}printf("\n");
}//申請節點
LTNode* LTBuyNode(LTDataType x)
{LTNode* node = (LTNode*)malloc(sizeof(LTNode));if (node == NULL){perror("malloc fail");exit(1);//給非0值}node->data = x;node->next = node->prev = node;return node;
}
void LTInit(LTNode** pphead)
{//給雙向鏈表創建一個哨兵位*pphead = LTBuyNode(-1);
}
//尾插
void LTPushBack(LTNode* phead, LTDataType x)
{assert(phead);LTNode* newnode = LTBuyNode(x);//phead phead->prev newnodenewnode->prev = phead->prev;newnode->next = phead;phead->prev->next = newnode;//不能交換位置phead->prev = newnode;
}
//頭插
void LTPushFront(LTNode* phead, LTDataType x)
{assert(phead);LTNode* newnode = LTBuyNode(x);newnode->next = phead->next;newnode->prev = phead;phead->next->prev = newnode;//先改影響小的phead->next = newnode;}
//尾刪
void LTPopBack(LTNode* phead)
{//鏈表必須有效且鏈表不能為空assert(phead && phead->next != phead);LTNode* del = phead->prev;del->prev->next = phead;phead->prev = del->prev;//刪除del節點free(del);del = NULL;}
//頭刪
void LTPopFront(LTNode* phead)
{assert(phead && phead->next != phead);LTNode* del = phead->next;phead->next = del->next;del->next->prev = phead;//刪除del節點free(del);del = NULL;
}
//查找
LTNode* LTFind(LTNode* phead, LTDataType x)
{LTNode* pcur = phead->next;while (pcur != phead){if (pcur->data == x){return pcur;}pcur = pcur->next;}//沒有找到return NULL;
}
//指定位置插入數據
void LTInsert(LTNode* pos, LTDataType x)
{assert(pos);LTNode* newnode = LTBuyNode(x);newnode->next = pos->next;newnode->prev = pos;pos->next->prev = newnode;pos->next = newnode;}
//刪除pos節點
void LTErase(LTNode* pos)//這里傳一級指針是為了保持接口的一致性 其他函數傳的都是一級指針
{//pos理論上來說不能為phead,但是參數沒有phead,所以無法增加校驗pos->next->prev = pos->prev;pos->prev->next = pos->next;free(pos);pos = NULL;
}
//鏈表銷毀
void LTDesTroy(LTNode* phead)
{assert(phead);LTNode* pcur = phead->next;while (pcur->next != phead){LTNode* next = pcur->next;free(pcur);pcur = next;}//此時pcur指向phead,而phead還沒有被銷毀free(phead);phead = NULL;//如果不置為空 plist(保存的地址空間被釋放掉了) 若后續不再使用plist則沒問題(野指針)}
//LTErase和LTDestroy參數理論上要傳二級,因為我們需要讓形參的改變影響到實參,但是為了接口的一致性才穿的一級
//傳一級存在的問題是,當形參phead置為NULL后,實參plist不會被修改為NULL,因此解決方法是 調用完方法后手動將實參置為NULL

test.c

#define _CRT_SECURE_NO_WARNINGS
#include"List.h";void ListTest01()
{LTNode* plist = NULL;LTInit(&plist);LTPushBack(plist, 1);LTPrint(plist);LTPushFront(plist, 2);LTPrint(plist);LTPopBack(plist);LTPrint(plist);LTPopFront(plist);LTPushFront(plist, 3);LTPrint(plist);LTNode* find = LTFind(plist, 3);{if (find == NULL){printf("找不到\n");}else{printf("找到了\n");}}LTInsert(find, 66);LTPrint(plist);LTErase(find);LTPrint(plist);}
int main()
{ListTest01();return 0;
}

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

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

相關文章

從 Prompt 管理到人格穩定:探索 Cursor AI 編輯器如何賦能 Prompt 工程與人格風格設計(下)

六、引入 Cursor AI 編輯器的開發流程革新 在整個系統開發過程中&#xff0c;我大量采用了 Cursor 編輯器作為主要的開發環境&#xff0c;并獲得以下關鍵收益&#xff1a; 具備 AI 補全與代碼聯想功能&#xff1a;支持通過內置 Copilot 模型對 Python、FastAPI、YAML、JSON 等…

Spark運行架構

Spark框架的核心是一個計算引擎&#xff0c;整體來說&#xff0c;它采用了標準master-slave的結構 ?如下圖所示&#xff0c;它展示了一個Spark執行時的基本結構&#xff0c;圖形中的Driver表示master&#xff0c;負責管理整個集群中的作業任務調度&#xff0c;圖形中的Executo…

基于未合入PR創建增量patch的git管理方法

目錄前言準備操作步驟精準移植基礎PR到本地分支修改代碼鴻蒙編譯、調試、測試具體編譯指令、測試步驟這里帶過&#xff0c;這不是本文論述重點創建diff文件工作倉庫應用最新patch總結前言 作為程序員&#xff0c;多人協同開發同一個需求是正常的。即使是自己一個人搞需求&…

git真正更新項目

背景 Fetch all remote后flutter代碼都拉下來&#xff0c;都是Android項目應用不上&#xff1b;git–>update project才生效&#xff01;&#xff01;&#xff01;

AI時代如何拓展Web前端開發的邊界

文章目錄 1 從“頁面仔”到“智能體驗構建者”——前端的變與不變2 AI 如何重塑 Web 前端&#xff1a;從開發到用戶體驗的革命2.1 AI 賦能開發效率&#xff1a;前端工程師的“超級外掛”2.1.1 智能代碼輔助與生成2.1.2 自動化測試與 Bug 定位 2.2 AI 提升用戶體驗&#xff0c;構…

chrome webdrive異常處理-session not created falled opening key——仙盟創夢IDE

注冊表錯誤 :EKKOK:chromeinstallerut1 Lgoogle update settings.cc:26b falled opening key .( e\Update\ClientStateMedium 8A69D345-D564-463c-AFF1-A69D9E530F96} to set usagestats 連接超時 disconnected: received Inspector.detached eventfailed to check if windo…

【Java EE初階 --- 多線程(進階)】JUC

樂觀學習&#xff0c;樂觀生活&#xff0c;才能不斷前進啊&#xff01;&#xff01;&#xff01; 我的主頁&#xff1a;optimistic_chen 我的專欄&#xff1a;c語言 &#xff0c;Java 歡迎大家訪問~ 創作不易&#xff0c;大佬們點贊鼓勵下吧~ 文章目錄 JUC組件ReentrantLock與s…

免費靜態網站搭建

免費靜態網站搭建 內容簡介搭建步驟GitHub倉庫創建Jekyll安裝使用Jekyll安裝指南Jekyll快速搭建測試Jekyll后續玩法 內容簡介 &#x1f6a9;Tech Contents&#xff1a;GithubPage/Jekyll/Custom URLs &#x1f431;GitHub Pages&#xff1a;靜態網站托管服務&#xff0c;自動將…

MySQL 8.0 OCP 1Z0-908 題目解析(21)

題目81 Choose two. Examine the modified output: mysql> SHOW SLAVE STATUS\G *************************** 1. row ***************************Slave_IO_Running: YesSlave_SQL_Running: YesSeconds_Behind_Master: 1612Seconds_Behind_Master value is steadily gro…

Web前端開發-HTML、CSS

文章目錄是什么&#xff1f;HTML快速入門VS Code開發工具基礎標簽&樣式新浪新聞-標題標題排版標題樣式標題樣式-1標題樣式-2超鏈接新浪新聞-正文新浪新聞-正文排版新浪新聞-頁面布局表格標簽表單標簽表單標簽-表單項是什么&#xff1f; HTML快速入門 VS Code開發工具 基礎標…

Vue.js狀態管理: Vuex在大型項目中的實際應用

# Vue.js狀態管理: Vuex在大型項目中的實際應用 ## 一、Vuex核心架構與大型項目適配 ### 1.1 狀態管理&#xff08;State Management&#xff09;的本質需求 在復雜前端系統中&#xff0c;組件間的數據傳遞成本隨項目規模呈指數級增長。根據Vue官方統計&#xff0c;超過500個組…

C++開發:結構體作為函數形參的值傳遞與引用傳遞

筆者定義了一個結構體變量&#xff0c;用于作為函數的形參&#xff0c;定義如下&#xff1a;struct CardParameters {float* Average nullptr;int averageSize 0; }; 需求描述&#xff1a;結構體變量作為函數的形參&#xff0c;在函數體中給指針變量分配內存空間并賦值&#…

【unity小技巧】在 Unity 中將 2D 精靈添加到 3D 游戲中,并實現陰影投射效果,實現類《八分旅人》《饑荒》等等的2.5D游戲效果

注意&#xff1a;考慮到unity小技巧的內容比較多&#xff0c;我將該內容分開&#xff0c;并全部整合放在【unity小技巧】專欄里&#xff0c;感興趣的小伙伴可以前往逐一查看學習。 文章目錄 前言實戰1、在3D場景中&#xff0c;新建一些不同形狀的2D圖片2、我們新建一個Lit材質3…

Rust 內存結構:深入解析

Rust 的內存管理系統是其核心特性之一&#xff0c;結合了手動內存管理的效率與自動內存管理的安全性。以下是 Rust 內存結構的全面解析&#xff1a; 內存布局概覽 ----------------------- | 代碼段 (Text) | 只讀&#xff0c;存儲可執行指令 ----------------------…

【Chrome】‘Good助手‘ 擴展程序使用介紹

這是我開發的一款 Chrome 瀏覽器擴展程序&#xff0c;目前主要集成了‘AI對話‘&#xff0c;’總結頁面’&#xff0c;‘基于頁面問答’等功能&#xff0c;最近幾天我也將寫一篇介紹如何開發 chrome 擴展程序的博客&#xff0c;帶你了解如何開發屬于自己的插件。 注&#xff1…

基于mysql8.0.27部署1主2從的MHA集群

目錄 一、mysql概述 1.1、關系型數據庫 1.2、MySQL數據庫 1.3、RDBMS術語 二、mysql的部署 2.1、拉取mysql 2.2、解壓 2.3、 改名 2.4、 指定安裝文件位置 2.5、 創建用戶組 2.6、 修改mysql配置文件 2.7、創建data文件夾 2.8、更改mysql目錄權限 2.9、初始化數據…

Highcharts 安裝使用教程

一、Highcharts 簡介 Highcharts 是一款使用 JavaScript 編寫的前端數據可視化庫&#xff0c;支持折線圖、柱狀圖、餅圖、面積圖、散點圖等多種圖表類型&#xff0c;特點是渲染性能優秀、交互豐富、兼容性強&#xff0c;適合構建商業圖表、統計報表等。 二、Highcharts 安裝方…

Qt中的坐標系

Qt中的坐標系 1.坐標系概念2.數學坐標系VS計算機坐標系3.Qt坐標系4.像素 &#x1f31f;&#x1f31f;hello&#xff0c;各位讀者大大們你們好呀&#x1f31f;&#x1f31f; &#x1f680;&#x1f680;系列專欄&#xff1a;【Qt的學習】 &#x1f4dd;&#x1f4dd;本篇內容&am…

C++原子類型操作與內存序

C原子類型操作與內存序詳解 這段內容深入介紹了C標準原子類型的操作接口、內存序語義及使用規范。以下是關鍵知識點的分層解析&#xff1a; 一、原子類型的命名規則與類型映射 C提供兩種方式表示原子類型&#xff1a; 模板特化形式&#xff1a;std::atomic<T>別名形式…

互聯網摸魚日報(2025-07-07)

互聯網摸魚日報(2025-07-07) 鈦媒體 一場突如其來的“召回潮”&#xff0c;點燃中國制造的“靈魂拷問” 史上最大外賣補貼戰開打&#xff0c;美團聚攏資源迎戰“巨無霸” 1315億加冕潮汕女首富&#xff0c;“最強打工妹”劍指港股 用14346字&#xff0c;講透上市前必做的10…