雙向鏈表增刪改查的模擬實現

本章目標

0.雙向鏈表的基本結構
1.雙向鏈表的初始化
2.頭插尾插
3.頭刪尾刪
4.查找與打印
5.在指定位置之前插入數據/在指定位置之后插入數據
6.在指定位置之前刪除數據/在指定位置之后刪除數據
7.銷毀鏈表

0.雙向鏈表的基本結構

本章所實現的雙向鏈表是雙向循環帶頭鏈表,是stl中list容器的結構一致.
在這里插入圖片描述
它有一個真正意義上的頭結點,但該結點并不存儲數據,我們一般管它叫做哨兵位.
它與單鏈表不同的是它的結點中有兩個指向結點的指針,分別是前一個結點和下一個結點的指針.

typedef int listdatatype;struct listNode
{listdatatype data;struct listNode* prev;struct listNode* next;
};
typedef struct listNode listNode;

我們把數據類型和鏈表結點進行typedef方便后面我們進行實現該鏈表的函數.

1.雙向鏈表的初始化

與單鏈表不同的是,每當我們創建鏈表的時候,需要創建一個新的哨兵位,然后才能將數據進行插入,刪除操作.既然要創建一個新的結點,我們就需要將該邏輯進行分裝,方便后續使用.

listNode* buyNode(listdatatype x)
{listNode* newnode = (listNode*)malloc(sizeof(listNode));if (!newnode){perror("malloc fail");exit(1);}newnode->data = x;newnode->next = newnode->prev = newnode;return newnode;
}

對于頭節點的創建我們有兩種方法,第一個中是在函數體內實現,另一種是傳過來一個指針進行操作,如果時第二種方法,我們就需要傳址,需要二級指針,如果傳一級指針相當于傳值操作,當函數結束的時候,函數棧幀會自動銷毀,那么外面的指針就成為野指針了.

listNode* listinit()
{listNode* newnode = buyNode(-1);return newnode;}void listintalpha(listNode **pphead)
{*pphead = buyNode(-1);
}

因為該結點時頭節點,并不存儲數據,所以在創建結點時給的參數可以隨便給.

2.頭插尾插

2.1頭插

在這里插入圖片描述
對于頭插來說,我們需要操作三個部分,哨兵位,哨兵位的下一個結點,newnode.
我們先討論newndoe,要讓它的prev指向哨兵位,next指向哨兵位的下一個結點,該操作時不會對鏈表產生影響的.我可以隨意他們的順序.
接著讓哨兵位的下一個結點的prev指向newnode,然后再讓哨兵位的next指向newnode.
該操作是有順序要求的,如果先讓哨兵位的next指向newnode,會找不到后面的鏈表,當然我們也可以提前保存一份,這樣就可以隨意操作了.

void listpushfront(listNode* phead, listdatatype x)
{assert(phead);listNode* newnode = buyNode(x);newnode->prev = phead;newnode->next = phead->next;phead->next->prev = newnode;phead->next = newnode;
}

2.2.尾插

在這里插入圖片描述
對于尾插來說,我們要操作的結點一共有三個,最后一個結點,哨兵位,newnode.
我們先操作對鏈表沒有影響newnode,讓它的prev的結點指向最后一個結點(頭節點的prev結點)
讓它的next結點指向哨兵位,然后讓最后一個結點的下一個結點的指針指向newnode,讓哨兵位的prev結點指向newnode.

void listpushback(listNode* phead,listdatatype x)
{assert(phead);listNode* newnode = buyNode(x);newnode->prev = phead->prev;newnode->next = phead;phead->prev->next = newnode;phead->prev = newnode;
}

3.頭刪尾刪

3.0判斷鏈表是否為空

當我們如果要進行刪除操作的時候鏈表中一定是有元素的.我們可以將鏈表的判空封裝成一個方法.
如果當前結點下一個結點仍然是當前結點就證明,該鏈表為空.

/判斷是否非空
bool LTEmpty(listNode* phead)
{assert(phead);return phead->next == phead;
}

3.1頭刪

因為我們傳過來的結點一定是哨兵位,我們刪除的數據是它的下一個結點.為了防止丟失,我們可以提前將它保存為del.與它相關聯的結點時哨兵位以及del的下一個結點,我們要讓它的del的下一個結點的prev指向哨兵位,哨兵位的next指向del的下一個結點.然后釋放del,置空.
該實現該函數的時候要注意判空.

void listpopfront(listNode* phead)
{assert(!LTEmpty(phead));listNode* del = phead->next;del->next->prev = phead;phead->next = del->next;free(del);del = NULL;
}

3.2尾刪

對于尾刪來說,我們要刪除最后一個有數據的結點,與之關聯的結點一共有兩個,哨兵位以及它的前一個結點.我們要讓它的前一個結點的next指向哨兵位,讓哨兵位的prev指針指向要刪除結點的前一個結點.然后釋放該結點.我們可以提前保存該結點為del,方便操作.

void listpopback(listNode* phead)
{assert(!LTEmpty(phead));listNode* del = phead->prev;del->prev->next = phead;phead->prev = del->prev;free(del);del = NULL;
}

4.查找與打印

4.1查找

對于查找來說,它需要遍歷整個鏈表,然后用當前值與該結點數據域中的值進行比對.如果找到就返回該結點,找不到就返回空.結束條件時當前結點等于哨兵位

listNode* listFind(listNode* phead, listdatatype x)
{listNode* pcur = phead->next;while (pcur != phead){if (pcur->data == x){return pcur;}pcur = pcur->next;}return NULL;
}

4.2打印

打印仍然時遍歷鏈表,直到結束條件時當前結點等于哨兵位.

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

5.在指定位置之前插入數據/在指定位置之后插入數據

5.1在指定位置之前插入數據

該函數實現涉及三個結點pos結點,pos結點的前一個結點.newnode.
我們讓newnode的prev指向pos結點的前一個結點.它的next結點指向pos結點.
pos結點的前一個結點的next指針指向newnode,pos結點的prev指針指向newnode即可

void listinsertFront(listNode* pos, listdatatype x)
{assert(pos);listNode* newnode = buyNode(x);newnode->next = pos;newnode->prev = pos->prev;pos->prev->next = newnode;pos->prev = newnode;
}

5.2在指定位置之后插入數據

該方法實現涉及三個結點.pos結點.pos結點的下一個結點,newnode.
我們仍然newnode結點的prev和next分別指向pos結點和pos結點的下一個結點.
pos結點的下一個結點的prev指針指向newnode,pos結點的next指針指向newnode.

void listinsertBack(listNode* pos, listdatatype x)
{assert(pos);listNode* newnode = buyNode(x);newnode->next = pos->next;newnode->prev = pos;pos->next->prev = newnode;pos->next = newnode;
}

6.在指定位置之前刪除數據/在指定位置之后刪除數據

6.1在指定位置之前刪除數據

我們先要將pos之前那個要刪除的結點保存為del.
讓del的前一個結點的next指針指向pos.
pos的prev指針指向del的前一個結點,然后釋放del.
但再刪除前仍然需要判空.

void listErasefront(listNode* pos)
{assert(!LTEmpty(pos));listNode* del = pos->prev;del->prev->next = pos;pos->prev = del->prev;free(del);del = NULL;
}

6.2在指定位置之后刪除數據

我們要先將pos結點之后的那個要刪除的結點保存為del,然后讓del的下一個結點的prev指向pos.
pos的next指針指向del的下一個結點,然后釋放del.

void listEraseback(listNode* pos)
{assert(!LTEmpty(pos));listNode* del = pos->next;del->next->prev = pos;pos->next = del->next;free(del);del = NULL;
}

7.銷毀鏈表

與鏈表的初始化相對,它也有兩種實現方式,但大體的思想都是循環銷毀.

void destroyalpha(listNode** pphead)
{listNode* pcur = (*pphead)->next;while (pcur != (*pphead)){listNode* next = pcur->next;free(pcur);pcur = next;}free((*pphead));*pphead = NULL;
}void destroybata(listNode* phead)
{listNode* pcur = phead->next;while (pcur != phead){listNode* next = pcur->next;free(pcur);pcur = next;}free(phead);phead = NULL;}

但要注意第二種方式如果使用,我們需要再外面對結點置空,防止成為野指針,

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

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

相關文章

實戰交易策略 篇十四:江南神鷹捕捉熱點和熊市生存交易策略

文章目錄 系列文章捕捉熱點是股市最大的掘金術市場溫度不低于50是熱點產生的必要條件題材的大小和新穎程度決定熱點的持續時間和漲幅炒作熱點的3個階段捕捉熱點的方法與步驟操作實戰案例熊市生存術“熊市最好的做法是離開股市”的說法是一句空話熊市盈利模式:不輕言底部,超跌…

Linux錯誤(6)X64向量指令訪問地址未對齊引起SIGSEGV

Linux錯誤(6)X64向量指令訪問地址未對齊引起SIGSEGV Author: Once Day Date: 2025年4月4日 一位熱衷于Linux學習和開發的菜鳥,試圖譜寫一場冒險之旅,也許終點只是一場白日夢… 漫漫長路,有人對你微笑過嘛… 全系列文章可參考專欄: Linux實…

解碼 __iter__ 和 itertools.islice - 迭代的藝術

文章目錄 前言一、`_iter__`:自定義迭代的鑰匙1.1 什么是 __iter__?1.2 基本用法1.3 高級用法:獨立迭代器二、itertools.islice:迭代切片的利器2.1 什么是 itertools.islice?2.2 基本用法2.3 處理無限序列2.4 實際應用三、`__iter__` 與 `islice` 的結合六、為什么需要它們…

使用VSCode編寫C#程序

目錄 一、環境搭建:構建高效開發基礎1. 安裝VSCode2. 配置.NET SDK3. 安裝核心擴展 二、項目開發全流程1. 創建項目2. 代碼編輯技巧3. 調試配置4. 高級調試技巧5. 編譯與運行 三、常見問題解決指南1. 項目加載失敗2. IntelliSense失效3. 代碼格式化4. 典型編譯錯誤&…

日本汽車規模性經濟計劃失敗,日產三大品牌的合并合作共贏,還是絕地求生?本田與日產合并確認失敗,將成為世界第三大汽車集團愿景失敗

本田與日產(含三菱汽車)的合并計劃最終因核心矛盾無法調和而宣告失敗,這一事件揭示了傳統車企在行業變革期的深層困境。以下從合并動機、失敗原因、本質判斷及未來影響等方面綜合分析: 一、合并的初衷:生存壓力主導的被動策略 市場危機與財務困境 中國市場潰敗:日系品牌在…

AutoCAD2026中文版下載安裝教程

AutoCAD是一款由Autodesk公司開發的計算機輔助設計軟件,被廣泛應用于建筑設計、機械設計、電氣設計、土木工程、裝飾裝潢等多個領域。AutoCAD2026中文版在原有的基礎上進行了多項改進和優化,為用戶提供了更為高效、便捷的繪圖和設計體驗。這里我給大家分…

Latex語法入門之數學公式

Latex是一種高質量的排版系統,尤其擅長于數學公式的排版。本文我將帶大家深入了解Latex在數學公式排版中的應用。從基礎的數學符號到復雜的公式布局,我們都會一一講解,通過本文的學習,你將能夠輕松編寫出清晰、美觀的數學公式&…

洛谷 P3214 [HNOI2011] 卡農

題目傳送門 前言 再次敗在 d p dp dp 手下,但是數據范圍這么小應該是可以看出是 d p dp dp 的(畢竟對于其他組合數的問題數據范圍都是 1 0 9 10^9 109 起步)。 思路 題意簡化 現有 1 , 2 , 3 , . . . , n ? 1 , n 1, 2, 3, ... , n -…

【年份數據類型及使用】

在數據分析中,年份的處理需要根據具體場景選擇合適的數據類型,以確保后續分析的準確性和效率。以下是常見的年份數據類型及使用場景: 1. 數值類型(整數或浮點數) 適用場景: 僅需存儲年份數值(如 2020, 2023),無需進行日期計算。需要將年份作為連續變量參與數學運算(如…

詳解七大排序

目錄 一.直接插入排序 (1)基本思想 (2)算法步驟 (3)代碼實現 (4)算法特性 (5)算法優化 (6)示例演示 二.希爾排序 &#xff08…

YOLOv12 訓練從這里開始:LabelImg 標注數據集

視頻講解: YOLOv12 訓練從這里開始:LabelImg 標注數據集 labelimg https://github.com/tzutalin/labelImg sudo apt-get install pyqt5-dev-tools pip3 install lxml git clone https://github.com/tzutalin/labelImg.git cd labelImg 開始編譯 make…

Day2:前端項目uniapp壁紙實戰

先來做一個輪番圖。 效果如下&#xff1a; common-style.css view,swiper,swiper-item{box-sizing: border-box; } index.vue <template><view class"homeLayout"><view class"banner"><swiper circular indicator-dots autoplay…

SAP-ABAP:ABAP `LEAVE LIST-PROCESSING` 深度解析

ABAP LEAVE LIST-PROCESSING 深度解析 核心機制 模式切換(Dialog → List) 中斷屏幕流 強制終止當前Dialog程序的PBO/PAI處理,脫離屏幕序列控制(如事務碼SE38執行的程序)。觸發報表事件 激活類報表程序的事件鏈:INITIALIZATION → AT SELECTION-SCREEN → START-OF-SEL…

在PyTorch中使用GPU加速:從基礎操作到模型部署

本文將通過具體代碼示例&#xff0c;詳細介紹如何在PyTorch中利用GPU進行張量計算和模型訓練&#xff0c;包含設備查詢、數據遷移以及模型部署等完整流程。 1. 查看GPU硬件信息 使用 nvidia-smi 命令檢查GPU狀態和進程信息&#xff1a; # 查看GPU信息 !nvidia-smi 輸出示例&…

lib-zo,C語言另一個協程庫,dns協程化, gethostbyname

lib-zo,C語言另一個協程庫,dns協程化, gethostbyname 另一個 C 協程庫 https://blog.csdn.net/eli960/article/details/146802313 本協程庫 支持 DNS查詢 協程化. 禁用所有 UDP 協程化 zvar_coroutine_disable_udp 1;禁用 53 端口的UDP 協程化 zvar_coroutine_disable_ud…

Java第三節:新手如何用idea創建java項目

作者往期文章&#xff1a; Java第一節&#xff1a;debug如何調試程序&#xff08;附帶源代碼&#xff09;-CSDN博客 Java第二節&#xff1a;debug如何調試棧幀鏈&#xff08;附帶源代碼&#xff09;-CSDN博客 步驟一 ? 步驟二 ? 步驟三 創建src文件夾包含main文件&#…

(一)從零開始:用 LangChain 和 ZhipuAI 搭建簡單對話

最近一直在研究如何用 LangChain 和 ZhipuAI 搭建一個智能對話系統&#xff0c;發現這個組合真的非常強大&#xff0c;而且實現起來并不復雜。今天就來分享一下我的學習過程和一些心得體會&#xff0c;希望能幫到同樣在探索這個領域的小伙伴們。 一、 環境搭建&#xff1a;從零…

uniapp地圖導航及后臺百度地圖回顯(v2/v3版本)

百度地圖申請地址&#xff1a;控制臺 | 百度地圖開放平臺 效果&#xff1a; 1.后臺 1.1申請百度地圖APi 1.2 引入百度地圖 <script type"text/javascript" src"//api.map.baidu.com/api?v3.0&ak自己百度生氣apikey"></script> 1.3 v2組…

Java模板方法模式詳解

模板方法模式詳解 一、模式定義 模板方法模式(Template Method Pattern)定義一個操作中的算法骨架&#xff0c;將某些步驟延遲到子類實現。 二、核心結構 1. 抽象模板類 public abstract class AbstractTemplate {// 模板方法&#xff08;final防止子類覆蓋&#xff09;pu…

(5)模擬后——Leonardo的可視化操作

1 引言 經過n天的模擬&#xff0c;模擬結果相信已經到手&#xff0c;但如何進行分析呢。 首先是可視化&#xff0c;可視化方法基本分為兩類 基于ENVI-met自帶軟件Leonardo的可視化操作基于NetCDF的可視化操作 2 模擬結果變量說明 首先&#xff0c;模擬結果會有以下幾個文件…