數據結構-帶頭雙向循環鏈表的實現

前言?

? ? ? ? 帶頭雙向循環鏈表是一種重要的數據結構,它的結構是很完美的,它彌補了單鏈表的許多不足,讓我們一起來了解一下它是如何實現的吧!

1.節點的結構

? ? ? ? 它的節點中存儲著數據和兩個指針,一個指針_prev用來記錄前一個節點的地址,另一個指針_next 用來記錄后一個節點的地址。

typedef int LTDataType;
typedef struct ListNode
{struct ListNode* _next;struct ListNode* _prev;LTDataType _data;
}ListNode;

2.尾部的插入和刪除的實現

? ? ? ? 由于這是帶頭循環的雙向鏈表,所以尾插只需要在它的頭結點的_prev?處進行插入,然后重新鏈接就可以了。如圖:?

? ? ? ? 如果只有一個頭結點,插入也是一樣的。

void ListPushBack(ListNode* phead, LTDataType data)//尾插
{assert(phead);ListNode* newNode = BuyListNode(data);//申請新節點ListNode* tail = phead->_prev;//找尾結點//鏈接新節點和尾結點tail->_next = newNode;newNode->_prev = tail;//與頭結點進行鏈接phead->_prev = newNode;newNode->_next = phead;
}

? ? ? ? ?尾部的刪除,首先需要找到鏈表的尾和尾的前一個節點,刪除尾結點之后,將前一個節點進與頭結點進行鏈接,如圖:

void ListPopBack(ListNode* phead)//尾刪除
{//確保指針不為空assert(phead);assert(phead->_next != phead);//保留頭結點//找尾ListNode* tail = phead->_prev;ListNode* newTail = tail->_prev;//找到新的尾結點//刪除舊的尾結點free(tail);//重新鏈接頭尾節點newTail->_next = phead;phead->_prev = newTail;
}

3.頭部插入和刪除的實現

? ? ? ? 頭部的插入,刪除和尾部的插入,刪除類似,需要注意的是刪除的不是?頭結點,是存儲有效數據的第一個節點,插入數據也是在第一個有效數據節點和頭結點之間插入。如圖:

?

void ListPushFront(ListNode* phead, LTDataType data)//頭插
{//確保指針不為空assert(phead);//申請新的節點ListNode* newNode = BuyListNode(data);//進行鏈接ListNode* realHead = phead->_next;realHead->_prev = newNode;newNode->_next = realHead;phead->_next = newNode;newNode->_prev = phead;
}
void ListPopFront(ListNode* phead)//頭刪插
{//指針存在assert(phead);//并且確保不能刪除頭結點assert(phead->_next != phead);//找到真正的頭ListNode* realHead = phead->_next;ListNode* realHeadNext = realHead->_next;//刪除頭節點free(realHead);//重新鏈接phead->_next = realHeadNext;realHeadNext->_prev = phead;
}

4.任意位置的插入和刪除?

? ? ? ? 在任意位置進行插入和刪除,需要知道節點的指針,插入或者刪除節點之后需要?更新節點的鏈接關系。如圖:

?

void ListInsert(ListNode* pos, LTDataType data)//pos位置之前的插入
{assert(pos);//確保指針有效ListNode* newNode = BuyListNode(data);//申請節點//進行鏈接ListNode* prev = pos->_prev;ListNode* next = pos;prev->_next = newNode;newNode->_prev = prev;newNode->_next = next;next->_prev = newNode;
}
void ListErase(ListNode* pos)//pos位置的刪除
{//確保指針有效assert(pos);ListNode* next = pos->_next;ListNode* prev = pos->_prev;//刪除pos所指向的節點free(pos);//進行重新鏈接prev->_next = next;next->_prev = prev;
}

? ? ? ? ?對任意位置的插入和刪除進行測試時,可以通過復用接口來實現,頭插尾插,頭刪尾刪都可以調用這兩個接口來實現,如下:

void ListPushBack(ListNode* phead, LTDataType data)//尾插
{ListInsert(phead, data);
}
void ListPopBack(ListNode* phead)//尾刪除
{ListErase(phead->_prev);
}
void ListPushFront(ListNode* phead, LTDataType data)//頭插
{ListInsert(phead->_next,data);
}
void ListPopFront(ListNode* phead)//頭刪插
{ListErase(phead->_next);
}

5.鏈表的初始化和刪除

? ? ? ? 帶頭的雙向循環鏈表初始化的時候就需要申請內存給頭節點。?

ListNode* BuyListNode(LTDataType data)//申請節點
{ListNode* newNode = (ListNode*)malloc(sizeof(ListNode));if (newNode == NULL){printf("申請空間失敗\n");exit(-1);}newNode->_data = data;return newNode;
}
void ListInit(ListNode** pphead)//初始化鏈表
{*pphead = BuyListNode(0);//申請頭結點//并且初始化(*pphead)->_next = *pphead;(*pphead)->_prev = *pphead;
}
//清理鏈表
void ListClear(ListNode* phead)
{assert(phead);//確保鏈表不為空assert(phead->_next != phead);//除了確保不清理頭結點ListNode* cur = phead->_next;while (cur != phead){ListNode* clearNode = cur;cur = cur->_next;free(clearNode);}
}
void ListDestory(ListNode** ppHead)//摧毀鏈表
{assert(*ppHead);//確保指針不為空ListClear(*ppHead);free(*ppHead);//釋放頭結點
}

6.查找并修改鏈表的節點的數據

? ? ? ? 查找和修改是一起的,實現查找就可以實現?修改鏈表的值。

ListNode* ListFind(ListNode* phead, LTDataType data)//查找鏈表
{assert(phead);ListNode* cur = phead->_next;while (cur != phead){if (cur->_data == data)return cur;cur = cur->_next;}return NULL;//找不到返回NULL
}
void ListTest4()
{//查找和修改的測試ListNode* pHead = NULL;ListInit(&pHead);ListPushFront(pHead, 1);ListPushFront(pHead, 2);ListPushFront(pHead, 3);ListPushFront(pHead, 4);ListPushFront(pHead, 5);ListPushFront(pHead, 6);ListNode* node = ListFind(pHead, 3);//在鏈表中查找if (node){//修改鏈表的值node->_data = 90;}ListPrint(pHead);ListDestory(&pHead);
}

7.全部代碼

//List.h

#include<stdio.h>
#include<stdlib.h>
#include<assert.h>
typedef int LTDataType;
typedef struct ListNode
{struct ListNode* _next;struct ListNode* _prev;LTDataType _data;
}ListNode;void ListPushBack(ListNode* phead, LTDataType data);//尾插void ListPopBack(ListNode* phead);//尾刪除
void ListPushFront(ListNode* phead,LTDataType data);//頭插
void ListPopFront(ListNode* phead);//頭刪插
ListNode* BuyListNode(LTDataType data);//申請節點
void ListInit(ListNode** pphead);//初始化鏈表void ListInsert(ListNode* pos, LTDataType data);//pos位置之前的插入void ListErase(ListNode* pos);//pos位置的刪除
//清理鏈表
void ListClear(ListNode* phead);void ListDestory(ListNode** ppHead);//摧毀鏈表void ListPrint(ListNode* phead);//打印鏈表
ListNode* ListFind(ListNode* phead, LTDataType data);//查找鏈表

?//List.c

#include"List.h"
void ListPushBack(ListNode* phead, LTDataType data)//尾插
{assert(phead);ListNode* newNode = BuyListNode(data);//申請新節點ListNode* tail = phead->_prev;//找尾結點//鏈接新節點和尾結點tail->_next = newNode;newNode->_prev = tail;//與頭結點進行鏈接phead->_prev = newNode;newNode->_next = phead;
}
void ListPopBack(ListNode* phead)//尾刪除
{//確保指針不為空assert(phead);assert(phead->_next != phead);//保留頭結點//找尾ListNode* tail = phead->_prev;ListNode* newTail = tail->_prev;//找到新的尾結點//刪除舊的尾結點free(tail);//重新鏈接頭尾節點newTail->_next = phead;phead->_prev = newTail;
}
void ListPushFront(ListNode* phead, LTDataType data)//頭插
{//確保指針不為空assert(phead);//申請新的節點ListNode* newNode = BuyListNode(data);//進行鏈接ListNode* realHead = phead->_next;realHead->_prev = newNode;newNode->_next = realHead;phead->_next = newNode;newNode->_prev = phead;
}
void ListPopFront(ListNode* phead)//頭刪插
{//指針存在assert(phead);//并且確保不能刪除頭結點assert(phead->_next != phead);//找到真正的頭ListNode* realHead = phead->_next;ListNode* realHeadNext = realHead->_next;//刪除頭節點free(realHead);//重新鏈接phead->_next = realHeadNext;realHeadNext->_prev = phead;
}
ListNode* BuyListNode(LTDataType data)//申請節點
{ListNode* newNode = (ListNode*)malloc(sizeof(ListNode));if (newNode == NULL){printf("申請空間失敗\n");exit(-1);}newNode->_data = data;return newNode;
}
void ListInit(ListNode** pphead)//初始化鏈表
{*pphead = BuyListNode(0);//申請頭結點//并且初始化(*pphead)->_next = *pphead;(*pphead)->_prev = *pphead;
}
void ListPrint(ListNode* phead)//打印鏈表
{assert(phead);ListNode* cur = phead->_next;while (cur != phead){printf("%d ", cur->_data);cur = cur->_next;}printf("\n");
}
void ListInsert(ListNode* pos, LTDataType data)//pos位置之前的插入
{assert(pos);//確保指針有效ListNode* newNode = BuyListNode(data);//申請節點//進行鏈接ListNode* prev = pos->_prev;ListNode* next = pos;prev->_next = newNode;newNode->_prev = prev;newNode->_next = next;next->_prev = newNode;
}
void ListErase(ListNode* pos)//pos位置的刪除
{//確保指針有效assert(pos);ListNode* next = pos->_next;ListNode* prev = pos->_prev;//刪除pos所指向的節點free(pos);//進行重新鏈接prev->_next = next;next->_prev = prev;
}
//清理鏈表
void ListClear(ListNode* phead)
{assert(phead);//確保鏈表不為空assert(phead->_next != phead);//除了確保不清理頭結點ListNode* cur = phead->_next;while (cur != phead){ListNode* clearNode = cur;cur = cur->_next;free(clearNode);}
}
void ListDestory(ListNode** ppHead)//摧毀鏈表
{assert(*ppHead);//確保指針不為空ListClear(*ppHead);free(*ppHead);//釋放頭結點
}
ListNode* ListFind(ListNode* phead, LTDataType data)//查找鏈表
{assert(phead);ListNode* cur = phead->_next;while (cur != phead){if (cur->_data == data)return cur;cur = cur->_next;}return NULL;//找不到返回NULL
}

//test.c

#include"List.h"
void ListTest1()
{//尾插尾刪的測試代碼ListNode* pHead = NULL;ListInit(&pHead);ListPushBack(pHead, 1);ListPushBack(pHead, 2);ListPushBack(pHead, 3);ListPushBack(pHead, 4);ListPushBack(pHead, 5);ListPushBack(pHead, 6);ListPrint(pHead);ListPopBack(pHead);ListPopBack(pHead);ListPopBack(pHead);ListPopBack(pHead);ListPopBack(pHead);ListPopBack(pHead);//ListPopBack(pHead);}
void ListTest2()
{//頭插頭刪的測試ListNode* pHead = NULL;ListInit(&pHead);ListPushFront(pHead, 1);ListPushFront(pHead, 2);ListPushFront(pHead, 3);ListPushFront(pHead, 4);ListPushFront(pHead, 5);ListPushFront(pHead, 6);ListPrint(pHead);ListPopFront(pHead);ListPopFront(pHead);ListPopFront(pHead);ListPopFront(pHead);ListPopFront(pHead);ListPopFront(pHead);ListPopFront(pHead);}
void ListTest3()
{//Destory和Clear的測試ListNode* pHead = NULL;ListInit(&pHead);ListPushFront(pHead, 1);ListPushFront(pHead, 2);ListPushFront(pHead, 3);ListPushFront(pHead, 4);ListPushFront(pHead, 5);ListPushFront(pHead, 6);ListDestory(&pHead);
}
int main()
{ListTest3();return 0;
}

?

8.測試代碼

void ListTest1()
{//尾插尾刪的測試代碼ListNode* pHead = NULL;ListInit(&pHead);ListPushBack(pHead, 1);ListPushBack(pHead, 2);ListPushBack(pHead, 3);ListPushBack(pHead, 4);ListPushBack(pHead, 5);ListPushBack(pHead, 6);ListPrint(pHead);ListPopBack(pHead);ListPopBack(pHead);ListPopBack(pHead);ListPopBack(pHead);ListPopBack(pHead);ListPopBack(pHead);//ListPopBack(pHead);}
void ListTest2()
{//頭插頭刪的測試ListNode* pHead = NULL;ListInit(&pHead);ListPushFront(pHead, 1);ListPushFront(pHead, 2);ListPushFront(pHead, 3);ListPushFront(pHead, 4);ListPushFront(pHead, 5);ListPushFront(pHead, 6);ListPrint(pHead);ListPopFront(pHead);ListPopFront(pHead);ListPopFront(pHead);ListPopFront(pHead);ListPopFront(pHead);ListPopFront(pHead);ListPopFront(pHead);}
void ListTest3()
{//Destory和Clear的測試ListNode* pHead = NULL;ListInit(&pHead);ListPushFront(pHead, 1);ListPushFront(pHead, 2);ListPushFront(pHead, 3);ListPushFront(pHead, 4);ListPushFront(pHead, 5);ListPushFront(pHead, 6);ListDestory(&pHead);
}

?

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

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

相關文章

Git詳解及使用

Git簡介 Git 是一種分布式版本控制系統&#xff0c;它可以不受網絡連接的限制&#xff0c;加上其它眾多優點&#xff0c;目前已經成為程序開發人員做項目版本管理時的首選&#xff0c;非開發人員也可以用 Git 來做自己的文檔版本管理工具。 大概是大二的時候開始接觸和使用Gi…

云計算——ACA學習 云計算核心技術

作者簡介&#xff1a;一名云計算網絡運維人員、每天分享網絡與運維的技術與干貨。 座右銘&#xff1a;低頭趕路&#xff0c;敬事如儀 個人主頁&#xff1a;網絡豆的主頁????? 寫在前面 本系列將會持續更新云計算阿里云ACA的學習&#xff0c;了解云計算及網絡安全相關…

DeepSpeed加速大模型訓練

DeepSpeed是微軟推出的一個框架&#xff0c;可以對Pytorch的模型進行包裝&#xff0c;提供了加快模型的訓練速度&#xff0c;降低對GPU顯存的占用&#xff0c;以及方便進行分布式訓練等等高級特性。在這里我也對DeepSpeed進行了測試&#xff0c;看看是否能提高我的transformer模…

Maven 插件 maven-antrun-plugin 執行 ant 腳本

Ant 相信大家都不陌生&#xff0c;你可以把它理解為使用 xml 格式描述的一系列命令處理工具。它是一種基于Java的build工具。理論上來說&#xff0c;它有些類似于&#xff08;Unix&#xff09;C中的make、有些類似于基于shell命令編寫的sh腳本文件。Ant 用 Java 的類來擴展。&a…

多維時序 | MATLAB實現PSO-CNN-BiLSTM多變量時間序列預測

多維時序 | MATLAB實現PSO-CNN-BiLSTM多變量時間序列預測 目錄 多維時序 | MATLAB實現PSO-CNN-BiLSTM多變量時間序列預測基本介紹模型特點程序設計參考資料 基本介紹 本次運行測試環境MATLAB2021b&#xff0c;MATLAB實現PSO-CNN-BiLSTM多變量時間序列預測。代碼說明&#xff1a…

Java mail郵件開發 OA辦公系統

目錄 1 Java mail郵件開發 OA辦公系統 1.1 //用戶登錄 1.2 //用戶注冊 1.3 //根據郵箱賬號查詢用戶ID Java mail郵件開發 OA辦公系統package com.email.dao.impl; import java.sql.Connection; import java.sql.PreparedStatement;<

POSTGRESQL 關于2023-08-14 數據庫自動啟動文章中使用KILL 來進行配置RELOAD的問題解釋...

開頭還是介紹一下群&#xff0c;如果感興趣Polardb ,mongodb ,MySQL ,Postgresql ,redis &#xff0c;SQL SERVER ,ORACLE,Oceanbase 等有問題&#xff0c;有需求都可以加群群內有各大數據庫行業大咖&#xff0c;CTO&#xff0c;可以解決你的問題。加群請加 liuaustin3微信號 &…

Oracle執行計劃

Oracle執行計劃 1. 什么是執行計劃Oracle explain使用3. Explain執行順序 1. 什么是執行計劃 執行計劃是一條查詢語句在Oracle中的執行過程或訪問路徑的描述。 執行計劃描述了SQL引擎為執行SQL語句進行的操作&#xff1b;分析SQL語句相關的性能問題或僅僅質疑查詢優化器的決定…

蔚來李斌賣手機:安卓系統,蘋果售價,一年一發

?作者 | Amy 編輯 | 德新 車圈大佬的玩法真讓人尋不著套路&#xff01; 蘋果的庫克和小米的雷布斯&#xff0c;甚至是FF賈老板準備許久&#xff0c;都想分一塊新能源車的蛋糕&#xff0c;蔚來李斌卻反手進軍手機界&#xff0c;從宣布造手機到手機入網僅僅隔了一年。 近期…

說幾個常見的語法糖

目錄 面試回答 知識擴展 如何解語法糖&#xff1f; 糖塊一、swith 支持 String 與枚舉 糖塊二、泛型 糖塊三、自動裝箱與拆箱 糖塊四、枚舉 糖塊五、條件編譯 糖塊六、斷言 糖塊七、數值字面量 糖塊八、for-each 糖塊九、try-with-resource 可能遇到的坑 泛型 自…

Beats:安裝及配置 Metricbeat (一)- 8.x

在我之前的文章&#xff1a; Beats&#xff1a;Beats 入門教程 &#xff08;一&#xff09;Beats&#xff1a;Beats 入門教程 &#xff08;二&#xff09; 我詳細描述了如何在 Elastic Stack 7.x 安裝及配置 Beats。在那里的安裝&#xff0c;它通常不帶有安全及 Elasticsearc…

MapReduce介紹

目錄 ?一、什么是MapReduce 二、MapReduce 的設計思想 2.1 分而治之 2.2 構建抽象模型&#xff1a;Map和Reduce 2.3 隱藏系統層細節 三、MapReduce 的框架原理 3.1 MRv1工作原理 3.1.1 MRv1架構工作原理圖 3.1.1.1 流程說明 3.1.1.1.1 作業的提交 3.1.1.1.2 作業的初始化 3…

【AI大模型】訓練Al大模型 (上篇)

大模型超越AI 前言 潔潔的個人主頁 我就問你有沒有發揮&#xff01; 知行合一&#xff0c;志存高遠。 目前所指的大模型&#xff0c;是“大規模深度學習模型”的簡稱&#xff0c;指具有大量參數和復雜結構的機器學習模型&#xff0c;可以處理大規模的數據和復雜的問題&#x…

【Java】Queue中增加刪除方法的區別

offer&#xff0c;add 區別&#xff1a; 一些隊列有大小限制&#xff0c;因此如果想在一個滿的隊列中加入一個新項&#xff0c;多出的項就會被拒絕。 這時新的 offer 方法就可以起作用了。它不是對調用 add() 方法拋出一個 unchecked 異常&#xff0c;而只是得到由 offer() 返…

題目:售貨員的難題(狀壓dp)

售貨員的難題 題目描述輸入輸出格式輸入格式&#xff1a;輸出格式&#xff1a; 輸入輸出樣例輸入樣例#1&#xff1a;輸出樣例#1&#xff1a; 思路AC代碼&#xff1a; 題目描述 某鄉有n個村莊( 1 < n < 16 )&#xff0c;有一個售貨員&#xff0c;他要到各個村莊去售貨&am…

consul限制注冊的ip

假設當前服務器的ip是&#xff1a;192.168.56.130 1、允許 所有ip 注冊(驗證可行) consul agent -server -ui -bootstrap-expect1 -data-dir/usr/local/consul -nodedevmaster -advertise192.168.56.130 -bind0.0.0.0 -client0.0.0.0 2、只允許 當前ip 注冊 consul agent -…

Leetcode33 搜索旋轉排序數組

題解&#xff1a; /*** 旋轉排序數組可分為N1 N2兩個部分&#xff0c;如&#xff1a;[4,5,6,7,1,2,3]&#xff0c;N1為[4,5,6,7]&#xff0c;N2為[1,2,3]** 必然滿足以下兩個條件&#xff1a;* 1. N1和N2都是分別遞增的&#xff1b;* 2. N1中的所有元素大于N2中的所有元素;** …

【Python機器學習】實驗12 基于神經網絡的回歸-分類實驗

文章目錄 神經網絡的回歸例1 基于神經網絡的回歸(簡單例子)1.1 導入包1.2 構造數據集&#xff08;隨機構造的&#xff09;1.3 構造訓練集和測試集1.4 構建神經網絡模型1.5 采用訓練數據來訓練神經網絡模型 實驗1 基于神經網絡的分類(鳶尾花數據集)1.1 導入包1.2 構造數據集1.3 …

Selenium瀏覽器自動化測試框架簡單介紹

selenium簡介 介紹   Selenium [1] 是一個用于Web應用程序測試的工具。Selenium測試直接運行在瀏覽器中&#xff0c;就像真正的用戶在操作一樣。支持的瀏覽器包括IE&#xff08;7, 8, 9, 10, 11&#xff09;&#xff0c;Mozilla Firefox&#xff0c;Safari&#xff0c;Googl…

系統學習Linux-MongoDB

概述 mongodb是一個nosql數據庫&#xff0c;它有高性能、無模式、文檔型的特點。是nosql數據庫中功能最豐富&#xff0c;最像關系數據庫的。數據庫格式為BSON 相關概念實例&#xff1a;系統上運行的mongodb的進程&#xff0c;類似于mysql實例&#xff1b;庫&#xff1a;每個數…