国产 无码 综合区,色欲AV无码国产永久播放,无码天堂亚洲国产AV,国产日韩欧美女同一区二区

數(shù)據(jù)結(jié)構(gòu)——雙向鏈表

這篇具有很好參考價(jià)值的文章主要介紹了數(shù)據(jù)結(jié)構(gòu)——雙向鏈表。希望對(duì)大家有所幫助。如果存在錯(cuò)誤或未考慮完全的地方,請(qǐng)大家不吝賜教,您也可以點(diǎn)擊"舉報(bào)違法"按鈕提交疑問(wèn)。

數(shù)據(jù)結(jié)構(gòu)雙向表,數(shù)據(jù)結(jié)構(gòu),鏈表,數(shù)據(jù)結(jié)構(gòu)

??系列專欄:??數(shù)據(jù)結(jié)構(gòu)

???歡迎關(guān)注:??點(diǎn)贊??收藏??留言

?? 博客主頁(yè):??_麥麥_的博客_CSDN博客-領(lǐng)域博主
??如果我們都不能夠擁有黑夜,又該怎樣去仰望星空??

數(shù)據(jù)結(jié)構(gòu)雙向表,數(shù)據(jù)結(jié)構(gòu),鏈表,數(shù)據(jù)結(jié)構(gòu)

目錄

一、前言

二、正文——雙向鏈表的實(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ù)據(jù)結(jié)構(gòu)雙向表,數(shù)據(jù)結(jié)構(gòu),鏈表,數(shù)據(jù)結(jié)構(gòu)

二、正文——雙向鏈表的實(shí)現(xiàn)

數(shù)據(jù)結(jié)構(gòu)雙向表,數(shù)據(jù)結(jié)構(gòu),鏈表,數(shù)據(jù)結(jié)構(gòu)

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)行鏈接

? ? ? ? 具體鏈接和代碼如下:

數(shù)據(jù)結(jié)構(gòu)雙向表,數(shù)據(jù)結(jié)構(gòu),鏈表,數(shù)據(jù)結(jié)構(gòu)

//鏈表的尾插[聲明]
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)行鏈接。不

? ? ? ? 具體圖片和代碼如下:

數(shù)據(jù)結(jié)構(gòu)雙向表,數(shù)據(jù)結(jié)構(gòu),鏈表,數(shù)據(jù)結(jié)構(gòu)

//鏈表的尾刪
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ú)須刪除了。?

? ? ? ? 具體圖片和代碼如下:

數(shù)據(jù)結(jié)構(gòu)雙向表,數(shù)據(jù)結(jié)構(gòu),鏈表,數(shù)據(jù)結(jié)構(gòu)

//鏈表的頭插[聲明]
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ú)須刪除了。?

數(shù)據(jù)結(jié)構(gòu)雙向表,數(shù)據(jù)結(jié)構(gòu),鏈表,數(shù)據(jù)結(jié)構(gòu)

//鏈表的頭刪[聲明]
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)。

數(shù)據(jù)結(jié)構(gòu)雙向表,數(shù)據(jù)結(jié)構(gòu),鏈表,數(shù)據(jù)結(jié)構(gòu)

//鏈表的插入(前)[聲明]
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)行鏈表的刪除。

數(shù)據(jù)結(jié)構(gòu)雙向表,數(shù)據(jù)結(jié)構(gòu),鏈表,數(shù)據(jù)結(jié)構(gòu)

//鏈表的刪除[聲明]
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)!

?數(shù)據(jù)結(jié)構(gòu)雙向表,數(shù)據(jù)結(jié)構(gòu),鏈表,數(shù)據(jù)結(jié)構(gòu)?文章來(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)!

本文來(lái)自互聯(lián)網(wǎng)用戶投稿,該文觀點(diǎn)僅代表作者本人,不代表本站立場(chǎng)。本站僅提供信息存儲(chǔ)空間服務(wù),不擁有所有權(quán),不承擔(dān)相關(guān)法律責(zé)任。如若轉(zhuǎn)載,請(qǐng)注明出處: 如若內(nèi)容造成侵權(quán)/違法違規(guī)/事實(shí)不符,請(qǐng)點(diǎn)擊違法舉報(bào)進(jìn)行投訴反饋,一經(jīng)查實(shí),立即刪除!

領(lǐng)支付寶紅包贊助服務(wù)器費(fèi)用

相關(guān)文章

  • 數(shù)據(jù)結(jié)構(gòu)-雙向鏈表

    數(shù)據(jù)結(jié)構(gòu)-雙向鏈表

    在單鏈表那一篇博客中介紹了單鏈表和雙向鏈表的優(yōu)缺點(diǎn),所以此篇博客直接分享怎樣實(shí)現(xiàn)一個(gè)帶頭雙向循環(huán)鏈表。 單鏈表博客: 首先我們需要寫(xiě)一個(gè)結(jié)構(gòu)體,雙向帶頭鏈表的話需要一個(gè)前驅(qū)指針prev和一個(gè)后驅(qū)指針next,前驅(qū)指針的作用是方便找尾節(jié)點(diǎn),因?yàn)轭^節(jié)點(diǎn)的prev指

    2024年02月05日
    瀏覽(44)
  • 數(shù)據(jù)結(jié)構(gòu)—雙向鏈表

    數(shù)據(jù)結(jié)構(gòu)—雙向鏈表

    目錄 1.? 鏈表的種類 2.? 最實(shí)用的兩種鏈表類型 3.? 實(shí)現(xiàn)雙向帶頭循環(huán)鏈表 ? ? ? ? ? ? ? ? ? 3.1 創(chuàng)建頭節(jié)點(diǎn) ????????3.2 實(shí)現(xiàn)雙向循環(huán)功能—返回頭指針 ????????3.3? 尾插?? ????????3.4 頭插 ????????3.5 尾刪 ????????3.6 頭刪 4.? 實(shí)現(xiàn)兩個(gè)重要接口函數(shù) ?

    2023年04月23日
    瀏覽(28)
  • 數(shù)據(jù)結(jié)構(gòu)——雙向鏈表

    數(shù)據(jù)結(jié)構(gòu)——雙向鏈表

    ??系列專欄:??數(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鏈表的初始化

    2024年02月02日
    瀏覽(26)
  • 數(shù)據(jù)結(jié)構(gòu)——實(shí)現(xiàn)雙向鏈表

    數(shù)據(jù)結(jié)構(gòu)——實(shí)現(xiàn)雙向鏈表

    怎么說(shuō)呢?光乍一聽(tīng)名字好像很難的樣子是吧,那如果你這樣認(rèn)為的話,可就要讓你大跌眼鏡了哦,其實(shí)雙向帶頭循環(huán)鏈表從操作和理解上來(lái)說(shuō)都是要易于單項(xiàng)不帶頭不循環(huán)鏈表(俗稱單鏈表)的。 咱們就來(lái)見(jiàn)識(shí)見(jiàn)識(shí)吧!希望真的能讓你們“大跌眼鏡”哈! 雙向帶頭循環(huán)鏈

    2024年02月07日
    瀏覽(22)
  • 【數(shù)據(jù)結(jié)構(gòu)】鏈表的分類和雙向鏈表

    【數(shù)據(jù)結(jié)構(gòu)】鏈表的分類和雙向鏈表

    本篇是基于上篇單鏈表所作,推薦與上篇配合閱讀,效果更加 http://t.csdnimg.cn/UhXEj 鏈表的結(jié)構(gòu)非常多樣,以下情況組合起來(lái)就有8種(2 x 2 x 2)鏈表結(jié)構(gòu): 我們一般叫這個(gè)頭為哨兵位 我們上回講的單鏈表就是不帶頭單項(xiàng)不循環(huán)鏈表。 今天我們要講帶頭雙向循環(huán)的鏈表。 不過(guò)

    2024年01月25日
    瀏覽(26)
  • 數(shù)據(jù)結(jié)構(gòu)入門 — 鏈表詳解_雙向鏈表

    數(shù)據(jù)結(jié)構(gòu)入門 — 鏈表詳解_雙向鏈表

    數(shù)據(jù)結(jié)構(gòu)入門 — 雙向鏈表詳解 博客主頁(yè)鏈接:https://blog.csdn.net/m0_74014525 關(guān)注博主,后期持續(xù)更新系列文章 文章末尾有源碼 *****感謝觀看,希望對(duì)你有所幫助***** 第一篇:數(shù)據(jù)結(jié)構(gòu)入門 — 鏈表詳解_單鏈表 第二篇:數(shù)據(jù)結(jié)構(gòu)入門 — 鏈表詳解_雙向鏈表 第三篇:數(shù)據(jù)結(jié)構(gòu)入門

    2024年02月11日
    瀏覽(19)
  • 數(shù)據(jù)結(jié)構(gòu):詳解【鏈表】的實(shí)現(xiàn)(單向鏈表+雙向鏈表)

    數(shù)據(jù)結(jié)構(gòu):詳解【鏈表】的實(shí)現(xiàn)(單向鏈表+雙向鏈表)

    1.順序表的問(wèn)題和思考 問(wèn)題: 中間/頭部的插入刪除,時(shí)間復(fù)雜度為O(N)。 增容需要申請(qǐng)新空間,拷貝數(shù)據(jù),釋放舊空間,會(huì)有不小的消耗。 增容一般是呈2倍的增長(zhǎng),勢(shì)必會(huì)有一定的空間浪費(fèi)。例如當(dāng)前容量為100,滿了以后增容到200,我們?cè)倮^續(xù)插入了5個(gè)數(shù)據(jù),后面沒(méi)有數(shù)據(jù)

    2024年03月26日
    瀏覽(36)
  • 【數(shù)據(jù)結(jié)構(gòu)與算法】雙向鏈表

    【數(shù)據(jù)結(jié)構(gòu)與算法】雙向鏈表

    作者:舊夢(mèng)拾遺186 專欄:數(shù)據(jù)結(jié)構(gòu)成長(zhǎng)日記 ? 帶頭雙向循環(huán)鏈表:結(jié)構(gòu)最復(fù)雜,一般用在單獨(dú)存儲(chǔ)數(shù)據(jù)。實(shí)際中使用的鏈表數(shù)據(jù)結(jié)構(gòu),都是帶頭雙向循環(huán)鏈表。另外這個(gè)結(jié)構(gòu)雖然結(jié)構(gòu)復(fù)雜,但是使用代碼實(shí)現(xiàn)以后會(huì)發(fā)現(xiàn)結(jié)構(gòu)會(huì)帶來(lái)很多優(yōu)勢(shì),實(shí)現(xiàn)反而簡(jiǎn)單了。 現(xiàn)在我們來(lái)通

    2024年02月11日
    瀏覽(30)
  • 數(shù)據(jù)結(jié)構(gòu)與算法:雙向鏈表

    數(shù)據(jù)結(jié)構(gòu)與算法:雙向鏈表

    朋友們大家好啊,在上節(jié)完成單鏈表的講解后,我們本篇文章來(lái)對(duì) 帶頭循環(huán)雙向鏈表進(jìn)行講解 單鏈表中,一個(gè)節(jié)點(diǎn)存儲(chǔ)數(shù)據(jù)和指向下一個(gè)節(jié)點(diǎn)的指針,而雙向鏈表除了上述兩個(gè)內(nèi)容,還包括了 指向上一個(gè)節(jié)點(diǎn)的指針 帶頭的雙向鏈表,是指在雙向鏈表的最前端添加了一個(gè) 額

    2024年02月20日
    瀏覽(26)
  • 【數(shù)據(jù)結(jié)構(gòu)】手撕雙向鏈表

    【數(shù)據(jù)結(jié)構(gòu)】手撕雙向鏈表

    目錄 前言 1. 雙向鏈表? 帶頭雙向循環(huán)鏈表的結(jié)構(gòu) 2. 鏈表的實(shí)現(xiàn) 2.1 初始化 2.2 尾插 2.3 尾刪 2.4 頭插 2.5 頭刪 2.6 在pos位置之前插入 2.7 刪除pos位置 3.雙向鏈表完整源碼 List.h List.c 在上一期中我們介紹了單鏈表,也做了一些練習(xí)題,在一些題中使用單鏈表會(huì)十分繁瑣。因?yàn)閱捂?/p>

    2024年02月05日
    瀏覽(27)

覺(jué)得文章有用就打賞一下文章作者

支付寶掃一掃打賞

博客贊助

微信掃一掃打賞

請(qǐng)作者喝杯咖啡吧~博客贊助

支付寶掃一掃領(lǐng)取紅包,優(yōu)惠每天領(lǐng)

二維碼1

領(lǐng)取紅包

二維碼2

領(lǐng)紅包