??系列專欄:??數(shù)據(jù)結(jié)構(gòu)
???歡迎關(guān)注:??點(diǎn)贊??收藏??留言
?? 博客主頁(yè):??_麥麥_的博客_CSDN博客-領(lǐng)域博主
??如果我們都不能夠擁有黑夜,又該怎樣去仰望星空??
目錄
一、前言
二、正文——雙向鏈表的實(shí)現(xiàn)
2.1模塊化
2.2 數(shù)據(jù)類型與結(jié)構(gòu)體定義
?2.3鏈表的初始化
?2.4鏈表的打印
2.5 鏈表的查找
?2.6判斷鏈表是否只有哨兵衛(wèi)
2.7申請(qǐng)新的結(jié)點(diǎn)?
2.8 鏈表的尾插
?2.9鏈表的尾刪
?2.10鏈表的頭插
2.11鏈表的頭刪
2.12鏈表的插入【pos之前】
2.13鏈表的刪除?
2.14鏈表的銷毀
?三、雙向鏈表完整代碼(含測(cè)試模塊)
3.1 List.h
3.2 List.c
3.3 text.c
四、結(jié)語(yǔ)
一、前言
? ? ? ? 在筆者的前兩篇文章具體講解的單鏈表的實(shí)現(xiàn),即無(wú)頭單向非循環(huán)。但是除此之外,鏈表還有另外七種類型,本篇文章將主要介紹雙向鏈表的實(shí)現(xiàn),即帶頭雙向鏈表。相信有的小伙伴一定會(huì)問(wèn)那另外六種需不需要講解呢,要不要掌握呢?其實(shí),條條大路通羅馬,在掌握的單鏈表和雙鏈表這兩大基礎(chǔ)鏈表,其他的鏈表的實(shí)現(xiàn)和運(yùn)用也是輕而易舉,毫不費(fèi)力。
? ? ? ? 因此,就讓我們一起實(shí)現(xiàn)雙向鏈表叭!
? ? ? ?
二、正文——雙向鏈表的實(shí)現(xiàn)
2.1模塊化
? ? ? ? ?相信看過(guò)博主前幾篇文章的小伙伴對(duì)“模塊化”已經(jīng)熟悉的不能再熟悉了,為了后期代碼的修改和維護(hù)能夠更加簡(jiǎn)便,我們這次雙向鏈表的實(shí)現(xiàn)依舊采取模塊化的方式。本次的程序共分為3個(gè)文件,分別是:List.c[具體功能的實(shí)現(xiàn)]、List.h[[函數(shù)、變量的聲明]]、Text.c[測(cè)試部分]。
2.2 數(shù)據(jù)類型與結(jié)構(gòu)體定義
? ? ? ? 在進(jìn)行鏈表功能的實(shí)現(xiàn)之前,首先是要對(duì)數(shù)據(jù)類型進(jìn)行定義和結(jié)構(gòu)體定義。
????????數(shù)據(jù)類型采取的是整形的形式,與前文的單鏈表相同。
????????結(jié)構(gòu)體定義這一塊則與單鏈表的定義有所不同。由于單鏈表是單向鏈表,故每個(gè)結(jié)點(diǎn)只需存放下一個(gè)結(jié)點(diǎn)的地址,而無(wú)需存放上一個(gè)結(jié)點(diǎn)的地址。而雙向鏈表,顧名思義是雙向的,通過(guò)一個(gè)結(jié)點(diǎn)我們能夠找到它的上一個(gè)結(jié)點(diǎn)和下一個(gè)結(jié)點(diǎn)。因此在對(duì)結(jié)構(gòu)體進(jìn)行定義的時(shí)候我們就需要兩個(gè)結(jié)構(gòu)體指針,分別用于存放該結(jié)點(diǎn)的上下結(jié)點(diǎn)。
? ? ? ? 具體代碼實(shí)現(xiàn)如下:
//數(shù)據(jù)類型與結(jié)構(gòu)體定義
typedef int LTDataType;
typedef struct ListNode
{
struct ListNode* next; //存放下一個(gè)結(jié)點(diǎn)
struct ListNode* prev; //存放上一個(gè)結(jié)點(diǎn)
LTDataType data; //數(shù)據(jù)類型
}LTNode;
?2.3鏈表的初始化
? ? ? ? 在進(jìn)行完數(shù)據(jù)類型和結(jié)構(gòu)體定義,還需要做一些準(zhǔn)備工作,來(lái)幫助我們更好的實(shí)現(xiàn)和測(cè)試后續(xù)的鏈表功能。而準(zhǔn)備工作大致分為以下幾點(diǎn):鏈表的初始化,鏈表的打印,鏈表的查找,判斷鏈表是否只有哨兵衛(wèi),申請(qǐng)新的結(jié)點(diǎn)。
? ? ? ? 我們先從鏈表的初始化開(kāi)始吧。首先毫無(wú)疑問(wèn)的是先建立的鏈表的哨兵衛(wèi),為了表現(xiàn)鏈表雙向的特性,接下來(lái)我們還要將哨兵衛(wèi)的上下結(jié)點(diǎn)指向它本身。
? ? ? ? 具體代碼如下:
//鏈表初始化
LTNode* LTInit();
//鏈表初始化
LTNode* LTInit()
{
LTNode* phead =BuyListNode(-1);
phead->next = phead; //下一個(gè)結(jié)點(diǎn)指向本身
phead->prev = phead; //上一個(gè)結(jié)點(diǎn)指向本身
return phead;
}
?2.4鏈表的打印
? ? ? ? 鏈表的打印是為了更好的測(cè)試我們后續(xù)的插入、刪除是否完成。那么該如何實(shí)現(xiàn)鏈表的打印呢?
? ? ? ? 雙向鏈表的打印與單鏈表也是有所不同的。對(duì)于單鏈表的打印,我們只需從從頭指針開(kāi)始遍歷鏈表,直至為空。而對(duì)于雙向鏈表來(lái)說(shuō),遍歷鏈表是不可行的,這是由它的結(jié)構(gòu)決定的。雙向鏈表的鏈接是循環(huán)的,單憑遍歷的話,是永遠(yuǎn)也不可能將這個(gè)鏈表打印結(jié)束的,因此我們就需要做一點(diǎn)小小的改變,讓遍歷鏈表的指針【cur】從哨兵衛(wèi)的下一個(gè)結(jié)點(diǎn)開(kāi)始遍歷,直至遍歷到哨兵衛(wèi)停止,這樣就可以將鏈表的數(shù)據(jù)全部打印出來(lái)了。
? ? ? ? 具體代碼如下:
//鏈表的打印[聲明]
void LTPrint(LTNode* phead);
//鏈表的打印[具體實(shí)現(xiàn)]
void LTPrint(LTNode* phead)
{
assert(phead);
LTNode* cur = phead->next;
while (cur != phead)
{
if (cur->next == phead)
{
printf("<->%d<->", cur->data);
}
else
{
printf("<->%d", cur->data);
}
cur = cur->next;
}
printf("\n");
}
2.5 鏈表的查找
? ? ? ? 為了后續(xù)鏈表指定位置的插入和刪除,我們需要找到指定數(shù)據(jù)所指向的結(jié)點(diǎn),為了提高代碼的復(fù)用,我們將鏈表的查找單獨(dú)封裝成一個(gè)函數(shù)。
? ? ? ? 那么該如何去編寫(xiě)呢?這里的代碼其實(shí)與單向鏈表差不多,即遍歷鏈表,直至找到數(shù)據(jù)所對(duì)應(yīng)的結(jié)點(diǎn),并將其地址返回即可。相對(duì)而言還是很簡(jiǎn)單的。
? ? ? ? 具體代碼實(shí)現(xiàn)如下:
//鏈表的查找[聲明]
LTNode* LTFind(LTNode* phead, LTDataType x);
//鏈表的查找[實(shí)現(xiàn)]
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.6判斷鏈表是否只有哨兵衛(wèi)
? ? ? ? 這一部分是為了鏈表的刪除的準(zhǔn)備的,對(duì)于單鏈表而言,當(dāng)鏈表為空的時(shí)候,就不能進(jìn)行數(shù)據(jù)的刪除了,而對(duì)于雙向鏈表來(lái)說(shuō),有了哨兵衛(wèi)的存在,自然就不存在鏈表為空的情況,相應(yīng)的,就是當(dāng)雙向鏈表只存在哨兵衛(wèi)的時(shí)候,就不能進(jìn)行數(shù)據(jù)的刪除了。
? ? ? ? 那么如何判斷鏈表是否只有哨兵衛(wèi)呢?方法其實(shí)很簡(jiǎn)單,只需要判斷所給的頭指針的上下結(jié)點(diǎn)是否指向本身即可,當(dāng)然兩條件選其一即可。
? ? ? ? 具體代碼實(shí)現(xiàn)如下:
//判斷鏈表是否只有哨兵衛(wèi)[聲明]
bool LTEmpty(LTNode* phead);
//判斷鏈表是否只有哨兵衛(wèi)[實(shí)現(xiàn)]
bool LTEmpty(LTNode* phead)
{
assert(phead);
return phead->next == phead;
}
2.7申請(qǐng)新的結(jié)點(diǎn)?
? ? ? ? 這一部分主要是為了鏈表的插入而準(zhǔn)備的,無(wú)論是頭插、尾插還是指定位置的插入都需要申請(qǐng)新的結(jié)點(diǎn),而重復(fù)的書(shū)寫(xiě)未免使代碼顯得冗雜,因此將“申請(qǐng)新的結(jié)點(diǎn)”這一功能單獨(dú)分離出來(lái)并封裝成一個(gè)函數(shù),大大提高代碼的簡(jiǎn)潔性。
? ? ? ? 而這一功能的實(shí)現(xiàn)與單鏈表大同小異,都是使用內(nèi)存函數(shù)來(lái)向內(nèi)存申請(qǐng)一片空間并返回指向這片空間的指針,不同的只是結(jié)構(gòu)體的內(nèi)容發(fā)生了改變而已。
? ? ? ? 具體代碼如下:
//申請(qǐng)新的結(jié)點(diǎn)[聲明]
LTNode* BuyListNode(LTDataType x);
/申請(qǐng)新的結(jié)點(diǎn)[實(shí)現(xiàn)]
LTNode* BuyListNode(LTDataType x)
{
LTNode* newnode = malloc(sizeof(LTNode));
if (newnode == NULL)
{
perror("malloc error");
}
else
{
newnode->data = x;
//避免野指針
newnode->next = NULL;
newnode->prev = NULL;
return newnode;
}
}
2.8 鏈表的尾插
? ? ? ? 準(zhǔn)備工作準(zhǔn)備就緒后,就開(kāi)始鏈表的主要功能的實(shí)現(xiàn)啦。
? ? ? ? 首先就是鏈表的尾插。我們先來(lái)看看單鏈表是如何進(jìn)行尾插的,對(duì)于單鏈表,我們需要對(duì)單鏈表進(jìn)行遍歷找到最后一個(gè)結(jié)點(diǎn),再對(duì)這個(gè)結(jié)點(diǎn)和新結(jié)點(diǎn)進(jìn)行鏈接的操作。而對(duì)于雙向鏈表,就沒(méi)有這么復(fù)雜了,因?yàn)?span style="color:#fe2c24;">哨兵衛(wèi)的上一個(gè)結(jié)點(diǎn)就已經(jīng)指向了鏈表的最后一個(gè)結(jié)點(diǎn),在找到這個(gè)尾結(jié)點(diǎn)之后,剩下的就是鏈接的問(wèn)題了。相比于單鏈表要復(fù)雜一點(diǎn),要將哨兵衛(wèi)、尾結(jié)點(diǎn)、新結(jié)點(diǎn)這三個(gè)結(jié)點(diǎn)進(jìn)行鏈接。
? ? ? ? 具體鏈接和代碼如下:
//鏈表的尾插[聲明]
void LTPushBack(LTNode* phead, LTDataType x);
//鏈表的尾插[實(shí)現(xiàn)]
void LTPushBack(LTNode* phead, LTDataType x)
{
assert(phead);
LTNode* tail = phead->prev;
//創(chuàng)建新的結(jié)點(diǎn)
LTNode* newnode = BuyListNode(x);
//尾結(jié)點(diǎn)的鏈接
tail->next = newnode;
newnode->prev = tail;
//哨兵衛(wèi)的鏈接
phead->prev = newnode;
newnode->next = phead;
}
?2.9鏈表的尾刪
? ? ? ? ?在講解完鏈表的尾插,接著就是鏈表的尾刪了。同樣地,我們不需要對(duì)鏈表進(jìn)行遍歷來(lái)找到尾結(jié)點(diǎn),只需要通過(guò)哨兵衛(wèi)來(lái)找到最后一個(gè)結(jié)點(diǎn),并將其置空,再將倒數(shù)第二個(gè)結(jié)點(diǎn)和哨兵衛(wèi)進(jìn)行鏈接。不
? ? ? ? 具體圖片和代碼如下:
//鏈表的尾刪
void LTPopBack(LTNode* phead);
//鏈表的尾刪
void LTPopBack(LTNode* phead)
{
assert(phead);
//判斷是否只有哨兵衛(wèi)
assert(!LTEmpty(phead));
//改變哨兵衛(wèi)的鏈接
phead->prev = phead->prev->prev;
//釋放尾結(jié)點(diǎn)的內(nèi)存
free(phead->prev->next);
//改變尾部鏈接
phead->prev->next = phead;
}
?2.10鏈表的頭插
? ? ? ? 在尾插、尾刪之后,就是頭插、頭刪了,那么該如何實(shí)現(xiàn)鏈表的頭插呢。
? ? ? ? 其步驟也很簡(jiǎn)單,先是申請(qǐng)一個(gè)新的結(jié)點(diǎn),進(jìn)而將該結(jié)點(diǎn)與哨兵衛(wèi)與鏈表的頭結(jié)點(diǎn)進(jìn)行鏈接。需要注意的一點(diǎn)就是判斷鏈表是否只有哨兵衛(wèi),若是只有哨兵衛(wèi)就無(wú)須刪除了。?
? ? ? ? 具體圖片和代碼如下:
//鏈表的頭插[聲明]
void LTPushFront(LTNode* phead, LTDataType x);
//鏈表的頭插[實(shí)現(xiàn)]
void LTPushFront(LTNode* phead, LTDataType x)
{
//創(chuàng)建新的結(jié)點(diǎn)
LTNode* newnode = BuyListNode(x);
LTNode* first = phead->next;
//改變鏈接關(guān)系
newnode->next = first;
first->prev = newnode;
phead->next = newnode;
newnode->prev = phead;
//代碼復(fù)用
//LTInsert(phead->next, x);
}
2.11鏈表的頭刪
? ? ? ? 頭插之后便是頭刪了,這一部分的代碼也是相對(duì)簡(jiǎn)單的,主要思路是將哨兵衛(wèi)與頭結(jié)點(diǎn)的下一個(gè)結(jié)點(diǎn)鏈接,并將頭結(jié)點(diǎn)的內(nèi)存釋放。唯一需要注意的一點(diǎn)就是判斷鏈表是否只有哨兵衛(wèi),若是只有哨兵衛(wèi)就無(wú)須刪除了。?
//鏈表的頭刪[聲明]
void LTPopFront(LTNode* phead);
//鏈表的頭刪[實(shí)現(xiàn)]
void LTPopFront(LTNode* phead)
{
assert(phead);
//改變鏈接關(guān)系+釋放內(nèi)存
phead->next = phead->next->next;
free(phead->next->prev);
phead->next->prev = phead;
}
2.12鏈表的插入【pos之前】
? ? ? ? 鏈表的頭插、頭刪、尾插、尾刪已經(jīng)全部講解完畢了,但其實(shí)對(duì)于雙向鏈表來(lái)說(shuō),以上四個(gè)功能并不需要,只需要通過(guò)鏈表的插入和刪除便可以實(shí)現(xiàn),也就是代碼的復(fù)用。但是為了幫助小伙伴們更好的理解雙向鏈表,便將上述功能一一實(shí)現(xiàn)。
? ? ? ? 接下來(lái)就讓我們進(jìn)入“”鏈表的插入“”這一功能的實(shí)現(xiàn),我們采取的是在"pos"之前進(jìn)行數(shù)據(jù)的插入。對(duì)“pos”之后插入數(shù)據(jù)的感興趣的小伙伴也可以嘗試自己編寫(xiě),兩者的邏輯是類似的。
? ? ? ? 具體的實(shí)現(xiàn)邏輯呢,就是申請(qǐng)一個(gè)新的結(jié)點(diǎn),并將pos位置的結(jié)點(diǎn)、pos位置之前的結(jié)點(diǎn)和新結(jié)點(diǎn)進(jìn)行鏈接。不過(guò)需要注意的一點(diǎn)是,如果你用的的指針過(guò)少,便要注意鏈接的順序,若是鏈接順序便可能無(wú)法找到原來(lái)結(jié)點(diǎn)的數(shù)據(jù),比較保險(xiǎn)且快捷的方法就是再另外設(shè)置一個(gè)指針用來(lái)記錄鏈接的結(jié)點(diǎn),便可以毫無(wú)顧慮的進(jìn)行結(jié)點(diǎn)間的鏈接了。
注:在尾插的代碼中對(duì)該段代碼的復(fù)用有些獨(dú)特,是通過(guò)傳哨兵衛(wèi)的指針進(jìn)行插入,這是由于雙向鏈表的循環(huán)特性決定的,鏈表的最后一個(gè)結(jié)點(diǎn)就是哨兵衛(wèi)的前一個(gè)結(jié)點(diǎn)。
//鏈表的插入(前)[聲明]
void LTInsert(LTNode* pos, LTDataType x);
//鏈表的插入(前)[實(shí)現(xiàn)]
void LTInsert(LTNode* pos, LTDataType x)
{
assert(pos);
LTNode* newnode = BuyListNode(x);
LTNode* prev = pos->prev;
//改變鏈接關(guān)系
prev->next = newnode;
newnode->prev = prev;
newnode->next = pos;
pos->prev = newnode;
}
2.13鏈表的刪除?
?????????鏈表的刪除的實(shí)現(xiàn)邏輯大致就是將要?jiǎng)h除的結(jié)點(diǎn)置空,并將其前后兩個(gè)結(jié)點(diǎn)進(jìn)行鏈接即可。不過(guò)要注意的依舊是鏈表是否只含有哨兵衛(wèi),若只含有哨兵衛(wèi),就無(wú)需進(jìn)行鏈表的刪除。
//鏈表的刪除[聲明]
void LTErase(LTNode* pos);
//鏈表的刪除[實(shí)現(xiàn)]
void LTErase(LTNode* pos)
{
assert(pos);
LTNode* next = pos->next;
LTNode* prev = pos->prev;
//改變鏈接關(guān)系并釋放內(nèi)存
prev->next = next;
next->prev = prev;
free(pos);
}
2.14鏈表的銷毀
? ? ? ? 不知不覺(jué)之中,就來(lái)到了雙向鏈表的最后一個(gè)功能:鏈表的銷毀
? ? ? ? 其實(shí)現(xiàn)邏輯:從哨兵衛(wèi)的下一個(gè)結(jié)點(diǎn)開(kāi)始遍歷鏈表,邊遍歷邊銷毀,直至遍歷到哨兵衛(wèi)為止,最后將哨兵衛(wèi)的內(nèi)存銷毀并將指針置空。
//鏈表的銷毀[聲明]
void LTDestroy(LTNode* phead);
//鏈表的銷毀[實(shí)現(xiàn)]
void LTDestroy(LTNode* phead)
{
assert(phead);
LTNode* cur = phead->next;
while (cur != phead)
{
LTNode* next = cur->next;
free(cur);
cur = next;
}
free(phead);
phead = cur=NULL;
}
?三、雙向鏈表完整代碼(含測(cè)試模塊)
3.1 List.h
#include<stdlib.h>
#include<assert.h>
#include<stdio.h>
#include<stdbool.h>
//數(shù)據(jù)類型與結(jié)構(gòu)體定義
typedef int LTDataType;
typedef struct ListNode
{
struct ListNode* next; //存放下一個(gè)結(jié)點(diǎn)
struct ListNode* prev; //存放上一個(gè)結(jié)點(diǎn)
LTDataType data; //數(shù)據(jù)類型
}LTNode;
//申請(qǐng)新的結(jié)點(diǎn)
LTNode* BuyListNode(LTDataType x);
//鏈表初始化
LTNode* LTInit();
//鏈表的打印
void LTPrint(LTNode* phead);
//判斷鏈表是否只有哨兵衛(wèi)
bool LTEmpty(LTNode* phead);
//鏈表的查找
LTNode* LTFind(LTNode* phead, LTDataType x);
//鏈表的尾插
void LTPushBack(LTNode* phead, LTDataType x);
//鏈表的尾刪
void LTPopBack(LTNode* phead);
//鏈表的頭插
void LTPushFront(LTNode* phead, LTDataType x);
//鏈表的頭刪
void LTPopFront(LTNode* phead);
//鏈表的插入(前)
void LTInsert(LTNode* pos, LTDataType x);
//鏈表的刪除
void LTErase(LTNode* pos);
//鏈表的銷毀
void LTDestroy(LTNode* phead);
3.2 List.c
#include "List.h"
//申請(qǐng)新的結(jié)點(diǎn)
LTNode* BuyListNode(LTDataType x)
{
LTNode* newnode = malloc(sizeof(LTNode));
if (newnode == NULL)
{
perror("malloc error");
}
else
{
newnode->data = x;
//避免野指針
newnode->next = NULL;
newnode->prev = NULL;
return newnode;
}
}
//鏈表初始化
LTNode* LTInit()
{
LTNode* phead =BuyListNode(-1);
phead->next = phead; //下一個(gè)結(jié)點(diǎn)指向本身
phead->prev = phead; //上一個(gè)結(jié)點(diǎn)指向本身
return phead;
}
//判斷鏈表是否只有哨兵衛(wèi)
bool LTEmpty(LTNode* phead)
{
assert(phead);
return phead->next == phead;
}
//鏈表的查找
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;
}
//鏈表的打印
void LTPrint(LTNode* phead)
{
assert(phead);
LTNode* cur = phead->next;
while (cur != phead)
{
if (cur->next == phead)
{
printf("<->%d<->", cur->data);
}
else
{
printf("<->%d", cur->data);
}
cur = cur->next;
}
printf("\n");
}
//鏈表的尾插
void LTPushBack(LTNode* phead, LTDataType x)
{
assert(phead);
LTNode* tail = phead->prev;
//創(chuàng)建新的結(jié)點(diǎn)
LTNode* newnode = BuyListNode(x);
//尾結(jié)點(diǎn)的鏈接
tail->next = newnode;
newnode->prev = tail;
//哨兵衛(wèi)的鏈接
phead->prev = newnode;
newnode->next = phead;
//代碼復(fù)用
//LTInsert(phead, x);
}
//鏈表的尾刪
void LTPopBack(LTNode* phead)
{
assert(phead);
//判斷是否只有哨兵衛(wèi)
assert(!LTEmpty(phead));
//改變哨兵衛(wèi)的鏈接
phead->prev = phead->prev->prev;
//釋放尾結(jié)點(diǎn)的內(nèi)存
free(phead->prev->next);
//改變尾部鏈接
phead->prev->next = phead;
//代碼復(fù)用
//LTErase(phead->prev);
}
//鏈表的頭插
void LTPushFront(LTNode* phead, LTDataType x)
{
//創(chuàng)建新的結(jié)點(diǎn)
LTNode* newnode = BuyListNode(x);
LTNode* first = phead->next;
//改變鏈接關(guān)系
newnode->next = first;
first->prev = newnode;
phead->next = newnode;
newnode->prev = phead;
//代碼復(fù)用
//LTInsert(phead->next, x);
}
//鏈表的頭刪
void LTPopFront(LTNode* phead)
{
assert(phead);
//改變鏈接關(guān)系+釋放內(nèi)存
phead->next = phead->next->next;
free(phead->next->prev);
phead->next->prev = phead;
//代碼復(fù)用
//LTErase(phead->next);
}
//鏈表的插入(前)
void LTInsert(LTNode* pos, LTDataType x)
{
assert(pos);
LTNode* newnode = BuyListNode(x);
LTNode* prev = pos->prev;
//改變鏈接關(guān)系
prev->next = newnode;
newnode->prev = prev;
newnode->next = pos;
pos->prev = newnode;
}
//鏈表的刪除
void LTErase(LTNode* pos)
{
assert(pos);
LTNode* next = pos->next;
LTNode* prev = pos->prev;
//改變鏈接關(guān)系并釋放內(nèi)存
prev->next = next;
next->prev = prev;
free(pos);
}
//鏈表的銷毀
void LTDestroy(LTNode* phead)
{
assert(phead);
LTNode* cur = phead->next;
while (cur != phead)
{
LTNode* next = cur->next;
free(cur);
cur = next;
}
free(phead);
phead = cur=NULL;
}
3.3 text.c
#include "List.h"
//測(cè)試代碼1:尾插
text1()
{
LTNode* phead = LTInit();
LTPushBack(phead, 1);
LTPushBack(phead, 2);
LTPushBack(phead, 3);
LTPushBack(phead, 4);
LTPrint(phead);
}
//測(cè)試代碼2:尾刪
text2()
{
LTNode* phead = LTInit();
LTPushBack(phead, 1);
LTPushBack(phead, 2);
LTPushBack(phead, 3);
LTPushBack(phead, 4);
LTPrint(phead);
printf("\n");
LTPopBack(phead);
LTPopBack(phead);
LTPrint(phead);
}
//測(cè)試代碼3:頭插
text3()
{
LTNode* phead = LTInit();
LTPushFront(phead, 4);
LTPushFront(phead, 3);
LTPushFront(phead, 2);
LTPushFront(phead, 1);
LTPrint(phead);
}
//測(cè)試代碼4:頭刪
text4()
{
LTNode* phead = LTInit();
LTPushFront(phead, 4);
LTPushFront(phead, 3);
LTPushFront(phead, 2);
LTPushFront(phead, 1);
LTPopFront(phead);
LTPopFront(phead);
LTPrint(phead);
}
//測(cè)試代碼5:插入(前)
text5()
{
LTNode* phead = LTInit();
LTPushFront(phead, 4);
LTPushFront(phead, 2);
LTPushFront(phead, 1);
LTPrint(phead);
LTNode* pos=LTFind( phead,4);
LTInsert(pos, 3);
LTPrint(phead);
}
//測(cè)試代碼6:插入(前)
text6()
{
LTNode* phead = LTInit();
LTPushFront(phead, 4);
LTPushFront(phead, 2);
LTPushFront(phead, 1);
LTPrint(phead);
LTNode* pos = LTFind(phead, 4);
LTInsert(pos, 3);
LTPrint(phead);
}
//測(cè)試代碼7:刪除
text7()
{
LTNode* phead = LTInit();
LTPushFront(phead, 4);
LTPushFront(phead, 3);
LTPushFront(phead, 2);
LTPushFront(phead, 1);
LTPrint(phead);
LTNode* pos = LTFind(phead, 3);
LTErase(pos);
LTPrint(phead);
}
int main()
{
//text1();
//text2();
//text3();
//text4();
//text5();
//text6();
text7();
}
四、結(jié)語(yǔ)
? ? ? ? 至此為止,關(guān)于雙向鏈表的講解已經(jīng)全部結(jié)束,看到這里的小伙伴快給自己點(diǎn)個(gè)贊,希望你們能夠從本篇文章中有所收獲,就是對(duì)筆者最大的支持!
????????關(guān)注我?_麥麥_分享更多干貨:_麥麥_的博客_CSDN博客-領(lǐng)域博主
? ? ? ? 大家的「關(guān)注?? + 點(diǎn)贊?? + 收藏?」就是我創(chuàng)作的最大動(dòng)力!謝謝大家的支持,我們下期見(jiàn)!文章來(lái)源:http://www.zghlxwxcb.cn/news/detail-788324.html?
?文章來(lái)源地址http://www.zghlxwxcb.cn/news/detail-788324.html
到了這里,關(guān)于數(shù)據(jù)結(jié)構(gòu)——雙向鏈表的文章就介紹完了。如果您還想了解更多內(nèi)容,請(qǐng)?jiān)谟疑辖撬阉鱐OY模板網(wǎng)以前的文章或繼續(xù)瀏覽下面的相關(guān)文章,希望大家以后多多支持TOY模板網(wǎng)!