數據結構(4)——帶哨兵位循環雙向鏈表

目錄

前言

一、帶哨兵的循環雙向鏈表是什么

二、鏈表的實現

2.1規定結構體

2.2創建節點

2.3初始化

2.4打印

2.5檢驗是否為空

2.6銷毀鏈表

2.7尾插

2.8尾刪

2.9頭插

2.10頭刪

2.11尋找特定節點

2.12任意位置插入(pos前)

2.13刪除任意節點

總結


前言

前面我們學習了單鏈表的一些知識,由單鏈表引申出雙向鏈表,同時帶哨兵位或者不帶哨兵位是兩種,但大差不差,這里學習一下帶哨兵位的循環雙向鏈表。

其實有很多鏈表的結構,組成它們的也就是循環非循環,帶哨兵位不帶哨兵位,雙向還是單向。


一、帶哨兵的循環雙向鏈表是什么

無哨兵單向非循環鏈表:結構簡單,也就是我們常說的單鏈表,一般不會用來單獨存數據,實際中更多是作為其它數據的子結構,如哈希桶,圖的鄰接表等等。

帶哨兵雙向循環鏈表:結構最復雜,一般用來單獨存儲數據,實際中使用的鏈表數據結構,都是帶哨兵(頭)雙向鏈表,另外這個結構雖然復雜,但是使用代碼實現以后會發現結構帶來很多優勢,實現反而簡單了。

二、鏈表的實現

這里我們要實現的有

//創建節點
LTNode* BuyListNode(LTDataType x)
//初始化
LTNode* LTInit();
//打印
void LTPrint(LTNode* phead);
//銷毀鏈表
void LTDestory(LTNode* phead);
//檢驗是否為空
bool LTEmpty(LTNode* phead)
//尾插尾刪
void LTPushBack(LTNode* phead, LTDataType x);
void LTPopBack(LTNode* phead);
//檢驗鏈表是否為空
bool LTEmpty(LTNode* phead);
//頭插頭刪
void LTPushFront(LTNode* phead, LTDataType x);
void LTPopFront(LTNode* phead);
//在pos之前加入一個值
void LTInsert(LTNode* pos, LTDataType x);
//刪除節點
void LTErase(LTNode* pos);
//尋找特定節點
LTNode* LTFind(LTNode* phead, LTDataType x);

2.1規定結構體

要想實現一個鏈表,就要首先規定一下每一個節點的結構體組成部分,這里我們先使用結構體來定義一下。

每一個節點內包括數據域,頭指針和尾指針。

typedef int LTDataType;typedef struct ListNode
{struct ListNode* next;//頭指針struct ListNode* prev;//尾指針LTDataType data;//數據
}LTNode;

基于這個結構,我們就可以實現后期的一系列操作內容,包括哨兵位的創建。

2.2創建節點

這里我們命名為BuyListNode,返回類型為結構體也就是LTNode*,通過傳入一個數據LTDataType x,從而實現對節點的創建。

LTNode* BuyListNode(LTDataType x)
{LTNode* node = (LTNode*)malloc(sizeof(LTNode));if (node == NULL){perror("malloc fail");return NULL;}node->next = NULL;node->prev = NULL;node->data = x;return node;
}

通過malloc分配一個節點的內存,然后把頭指針尾指針都賦為空,因為這里不知道頭尾指針指向誰,把傳入數據,最后返回節點。

2.3初始化

初始化就是初始化一個哨兵位節點,也就是一個頭,這里把哨兵位數據定義為-1,頭尾指針指向自己,因為這里是雙向循環鏈表,返回此節點。

//初始化
LTNode* LTInit()
{LTNode* phead = BuyListNode(-1);phead->next = phead;phead->prev = phead;return phead;
}

2.4打印

打印這里就是不斷訪問當前節點的下一個節點,之后打印此節點的數據。

//打印
void LTPrint(LTNode* phead)
{assert(phead);LTNode* cur = phead->next;printf("head<=>");while (cur != phead){printf("%d<=>", cur->data);cur = cur->next;}
}

這里為了形象,打印出來的后面會接上一個<<=>>,來代表雙向循環鏈表。

2.5檢驗是否為空

?通過一個布爾值來檢驗是否為空,主要就是檢查哨兵位有沒有。

//檢驗是否為空
bool LTEmpty(LTNode* phead)
{assert(phead);return phead->next == phead;
}

2.6銷毀鏈表

我們用 LTDestory來作為銷毀鏈表的函數名字。實際上銷毀鏈表就是先把除了哨兵位(頭節點)以外的所有節點刪除釋放,最后再釋放哨兵位,實現是這么實現的:

//銷毀釋放
void LTDestory(LTNode* phead)
{assert(phead);LTNode* cur = phead->next;while (cur != phead){LTNode* next = cur->next;free(cur);cur = next;}free(phead);phead = NULL;
}

先檢查是否有節點,然后把當前cur節點定義為哨兵位的下一個節點,如果cur不為哨兵位(因為是循環鏈表,所以最后肯定有一個時間,它的尾節點一定指向自己),在循環里面,先用next節點記住cur當前節點的下一個節點,然后釋放掉當前節點,再把之前定義的next賦給當前節點,就相當于cur不斷再往后走,不斷再釋放,最后到了循環結束的條件后,釋放一下哨兵位就可以實現全部釋放。

2.7尾插

這個尾插實現就基于之前創建節點的函數BuyListNode,先創建節點,找到尾節點后,再進行修改。

//尾插
void LTPushBack(LTNode* phead, LTDataType x)
{assert(phead);LTNode* newnode = BuyListNode(x);LTNode* tail = phead->prev;//找尾節點tail->next = newnode;newnode->prev = tail;newnode->next = phead;phead->prev = newnode;}

用newnode來代表要插入的新節點,找到尾節點,因為哨兵位的頭指針指向最后一個節點,這時候把新的newnode插入到尾節點后面就可以,注意此時新的節點成為了尾節點,所以要更新一下頭尾指針的指向關系。

2.8尾刪

尾刪就是找到當前尾節點,然后把尾節點的上一個節點作為最后一個節點,更新當前節點的頭尾指針,刪除當前尾節點。

//尾刪
void LTPopBack(LTNode* phead)
{assert(phead);assert(!LTEmpty(phead));LTNode* tail = phead->prev;LTNode* tailPrev = tail->prev;tailPrev->next = phead;phead->prev = tailPrev;free(tail);tail = NULL;}

當然這里也要斷言一下,看看是否為空,為空就不需要刪除。

2.9頭插

頭插實際上就是在哨兵位的下一個節點插入,實現過程就是類似鏈表的插入一樣。

//頭插
void LTPushFront(LTNode* phead, LTDataType x)
{assert(phead);LTNode* newnode = BuyListNode(x);phead->next->prev = newnode;newnode->next = phead->next;phead->next = newnode;newnode->prev = phead;}

插入進去后更新前后指針的指向就可以。

2.10頭刪

頭刪就是指定哨兵位的下一個節點,然后這個節點的下一個節點的頭指針更新指向哨兵位,哨兵位的下一節點指向它,就然后釋放掉剛才的頭節點可以。

//頭刪
void LTPopFront(LTNode* phead)
{assert(phead);LTNode* destorynode = phead->next;phead->next->next->prev = phead;phead->next = phead->next->next;free(destorynode);destorynode = NULL;
}

上面給出了頭刪的代碼。

2.11尋找特定節點

尋找特定節點,就是通過數據x尋找,之后返回一個節點的地址,這里就是通過一個循環尋找的特定節點,然后返回。

//尋找特定節點
LTNode* LTFind(LTNode* phead, LTDataType x)
{assert(phead);//帶頭雙向循環是定不為空的LTNode* cur = phead->next;while (cur != phead){if (cur->data == x){return cur;}cur = cur->next;}return NULL;
}

2.12任意位置插入(pos前)

基于之前的尋找特定的節點,以及新節點的創建,在這里對新節點進行插入,插入到pos的下一個節點,并且更新指針。

//任意位置插入
void LTInsert(LTNode* pos, LTDataType x)
{assert(pos);LTNode* prev = pos->prev;LTNode* newnode = BuyListNode(x);prev->next = newnode;newnode->prev = prev;newnode->next = pos;pos->prev = newnode;
}

2.13刪除任意節點

通過傳入一個pos節點,進行刪除,邏輯和前面的刪除差不多。

//刪除節點
void LTErase(LTNode* pos)
{assert(pos);LTNode* p = pos->prev;LTNode* n = pos->next;p->next = n;n->prev = p;free(pos);pos = NULL;
}

總結

這里對循環有哨兵位雙鏈表進行基本功能的編寫和學習。

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

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

相關文章

Github 2025-03-30 php開源項目日報 Top10

根據Github Trendings的統計,今日(2025-03-30統計)共有10個項目上榜。根據開發語言中項目的數量,匯總情況如下: 開發語言項目數量PHP項目10TypeScript項目1Coolify: 開源自助云平臺 創建周期:1112 天開發語言:PHP, Blade協議類型:Apache License 2.0Star數量:10527 個Fo…

3. 線程間共享數據

1. 線程共享數據會造成什么問題&#xff1f; 1.1 讀寫不一致 多線程讀不會造成數據變動&#xff0c;所以沒有問題。只要有一個線程設計修改數據&#xff0c;就會導致數據共享出現問題&#xff0c;簡單的是數據不一致&#xff0c;嚴重的是程序訪問已經釋放的內存&#xff0c;造…

JAVA垃圾回收算法和判斷垃圾的算法

一、判斷垃圾的算法 判斷對象是否為垃圾的核心是確定對象是否不再被使用。Java主要采用以下兩種算法&#xff1a; 1. 引用計數法&#xff08;Reference Counting&#xff09; 原理&#xff1a;每個對象維護一個引用計數器&#xff0c;記錄被引用的次數。當引用被添加時計數器…

界面架構 - MVVM (Qt)

MVVM MVVM 的主要特點示例示例功能示例代碼ViewModel 類&#xff08;C&#xff09;主函數入口&#xff08;main.cpp&#xff09; QML 文件&#xff08;main.qml&#xff09;總結 MVVM&#xff08;Model-View-ViewModel&#xff09;架構是一種旨在進一步分離界面和業務邏輯的設計…

第十四屆MathorCup高校數學建模挑戰賽-C題:基于 LSTM-ARIMA 和整數規劃的貨量預測與人員排班模型

目錄 摘要 一、 問題重述 1.1 背景知識 1.2 問題描述 二、 問題分析 2.1 對問題一的分析 2.2 對問題二的分析 2.3 對問題三的分析 2.4 對問題四的分析 三、 模型假設 四、 符號說明 五、 問題一模型的建立與求解 5.1 數據預處理 5.2 基于 LSTM 的日貨量預測模型 5.3 日貨量預測…

銀河麒麟V10 aarch64架構安裝mysql教程

國產操作系統 ky10.aarch64 因為是arm架構&#xff0c;故選擇mysql8&#xff0c;推薦安裝8.0.28版本 嘗試8.0.30和8.0.41版本均未成功&#xff0c;原因不明?? 1. 準備工作 ? 下載地址&#xff1a;https://downloads.mysql.com/archives/community/ 2. 清理歷史環境 不用管…

C++多繼承

可以用多個基類來派生一個類。 格式為&#xff1a; class 類名:類名1,…, 類名n { private: … &#xff1b; //私有成員說明; public: … &#xff1b; //公有成員說明; protected: … &#xff1b; //保護的成員說明; }; class D: public A, protected B, private C { …//派…

某地老舊房屋自動化監測項目

1. 項目簡介 自從上個世紀90年代以來&#xff0c;我國經濟發展迅猛&#xff0c;在此期間大量建筑平地而起&#xff0c;并且多為磚混結構的住房&#xff0c;使用壽命通常約為30-50年&#xff0c;鋼筋混凝土結構&#xff0c;鋼結構等高層建筑&#xff0c;這些建筑在一般情況下的…

產品經理的大語言模型課 04 -模型應用的云、邊、端模式對比

目錄 算力部署方式的影響因素數據量計算難度前期投入數據隱私應用規模與泛化能力 云、邊、端部署的特點和對比典型場景舉例社區人臉門禁后廚老鼠識別 未來展望 算力部署方式的影響因素 最近和人工智能從業者進行了非常廣泛的溝通&#xff0c;嘗試對模型應用的云、邊、端模式進…

基于Python設計的TEQC數據質量可視化分析軟件

標題:基于Python設計的TEQC數據質量可視化分析軟件 內容:1.摘要 本文旨在設計一款基于Python的TEQC數據質量可視化分析軟件。隨著全球導航衛星系統&#xff08;GNSS&#xff09;的廣泛應用&#xff0c;數據質量的評估變得至關重要。TEQC&#xff08;TransEditQualityCheck&…

Flinksql--訂單寬表

參考&#xff1a; https://chbxw.blog.csdn.net/article/details/115078261 (datastream 實現) 一、ODS 模擬訂單表及訂單明細表 CREATE TABLE orders (order_id STRING,user_id STRING,order_time TIMESTAMP(3),-- 定義事件時間及 Watermark&#xff08;允許5秒亂序&#x…

粒子濾波介紹

目錄 粒子濾波的主要流程可以分為以下 5 個步驟&#xff1a; 粒子濾波&#xff08;PF&#xff09; vs. ESKF&#xff08;誤差狀態卡爾曼濾波&#xff09; 粒子濾波的主要流程可以分為以下 5 個步驟&#xff1a; 初始化&#xff08;Initialization&#xff09; 生成 N 個粒子&…

一場國際安全廠商的交流會議簡記

今天參與了一場國際安全廠商A公司組織的交流會議 與會有國際TOP企業跨境企業 還有國內一些頭部商業公司。 A公司很有意思介紹了自己是怎么做安全運營中心SOC的。 介紹了很多內容&#xff0c;包括他們自己的員工量/設備量/事件量/SOC中心人員量&#xff0c;其中人員量只有個位數…

Java面試黃金寶典30

1. 請詳細列舉 30 條常用 SQL 優化方法 定義 SQL 優化是指通過對 SQL 語句、數據庫表結構、索引等進行調整和改進&#xff0c;以提高 SQL 查詢的執行效率&#xff0c;減少系統資源消耗&#xff0c;提升數據庫整體性能的一系列操作。 要點 從索引運用、查詢語句結構優化、數據…

花灑洗澡完畢并關閉后過段時間會突然滴水的原因探究

洗澡完畢后的殘留水 在洗澡的過程中&#xff0c;我們通常會使用到大量的水。這些水會通過花灑管子到達花灑頂噴流出。由于大頂噴花灑的噴頭較大&#xff0c;關閉后里面的存水會更多。 氣壓失衡后的滴水 當花灑關閉后&#xff0c;內部的水管和花灑頭中仍存有一定量的水。由于…

QSettings用法實戰(相機配置文件的寫入和讀取)

很多情況&#xff0c;在做項目開發的時候&#xff0c;將參數獨立出來是比較好的方法 例如&#xff1a;相機的曝光次數、曝光時長等參數&#xff0c;獨立成ini文件&#xff0c;用戶可以在外面修改即可生效&#xff0c;無需在動代碼重新編譯等工作 QSettings便可以實現該功能 內…

運維培訓班之最佳選擇(The best Choice for Operation and Maintenance Training Courses)

運維培訓班之最佳選擇 從面試官的角度聊聊培訓班對運維的幫助&#xff0c;同時給培訓班出身的運維一些建議~ 談到運維&#xff08;尤其是零基礎非科班轉行的運維&#xff09;找工作&#xff0c;培訓班是個不可回避的討論熱點。雖然本人也做過兼職運維培訓老師&#xff0c;多少…

網絡安全與防護策略

隨著信息技術的飛速發展&#xff0c;互聯網已成為現代社會不可或缺的一部分。從日常生活到企業運營&#xff0c;幾乎所有活動都離不開網絡。然而&#xff0c;網絡的開放性和廣泛性也使得網絡安全問題愈發嚴峻。無論是個人數據泄露&#xff0c;還是大規模的網絡攻擊&#xff0c;…

LLM 分詞器Tokenizer 如何從 0 到 1 訓練出來

寫在前面 大型語言模型(LLM)處理的是人類的自然語言,但計算機本質上只能理解數字。Tokenizer(分詞器) 就是架在自然語言和計算機數字表示之間的一座至關重要的橋梁。它負責將我們輸入的文本字符串分解成模型能夠理解的最小單元——Token,并將這些 Token 轉換成對應的數字…

【ArcGIS微課1000例】0142:如何從谷歌地球保存高清影像圖片

文章目錄 一、選取影像區域1. 搜索地圖區域2. 導入矢量范圍二、添加輸出圖層三、保存高清影像1. 地圖選項2. 輸出分辨率3. 保存圖像四、注意事項一、選取影像區域 首先需要選取影像區域,可通過以下方式快速定位。 1. 搜索地圖區域 在搜索框內輸入關鍵詞,例如青海湖,點擊【…