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

數(shù)據(jù)結(jié)構(gòu)入門(C語言版)線性表帶頭雙向循環(huán)鏈表接口實(shí)現(xiàn)

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

數(shù)據(jù)結(jié)構(gòu)入門(C語言版)線性表帶頭雙向循環(huán)鏈表接口實(shí)現(xiàn)

導(dǎo)航

1、帶頭雙向循環(huán)鏈表介紹

數(shù)據(jù)結(jié)構(gòu)入門(C語言版)線性表帶頭雙向循環(huán)鏈表接口實(shí)現(xiàn)
在上一篇博客我們講述了鏈表的概念和結(jié)構(gòu),還實(shí)現(xiàn)了無頭單向非循環(huán)鏈表接口寫法,那么這一章節(jié),我們來實(shí)現(xiàn)另一種常用的鏈表組成結(jié)構(gòu)——帶頭雙向循環(huán)鏈表。
如果對(duì)前面的鏈表基本概念還是不了解,可以看作者的上一篇博客:
線性表中鏈表介紹及無頭單向非循環(huán)鏈表接口實(shí)現(xiàn)

2、結(jié)構(gòu)體及接口函數(shù)定義

首先是結(jié)構(gòu)體的定義
代碼如下:

typedef int LTDateType;
typedef struct ListNode
{
	LTDateType data;//結(jié)點(diǎn)存儲(chǔ)元素
	struct ListNode* next;//下一結(jié)點(diǎn)指針
	struct ListNode* prev;//上一結(jié)點(diǎn)指針
}LTNode;

然后就是接口函數(shù)的定義
代碼如下:

void ListInit(LTNode* phead);//哨兵位頭結(jié)點(diǎn)初始化
LTNode* BuyListNode(LTDateType x);//動(dòng)態(tài)申請(qǐng)結(jié)點(diǎn)
void ListPushBack(LTNode* phead, LTDateType x);//雙向鏈表尾插
void ListPopBack(LTNode* phead);//雙向鏈表尾刪
void ListPushFront(LTNode* phead, LTDateType x);//雙向鏈表頭插
void ListPopFront(LTNode* phead);//雙向鏈表頭刪
LTNode* ListFind(LTNode* phead, LTDateType x);//雙向鏈表查找
void ListInsert(LTNode* pos, LTDateType x);//在pos位置前插入
void ListErase(LTNode* pos);//刪除pos位置的結(jié)點(diǎn)
void ListPrint(LTNode* phead);//打印雙向鏈表
void ListDestroy(LTNode* phead);//銷毀雙向鏈表

3、接口函數(shù)實(shí)現(xiàn)

在上一篇博客中我們講到不帶頭的單非循環(huán)鏈表存在一定缺陷,就是無法訪問上一結(jié)點(diǎn),但是這一節(jié)講的帶頭雙向循環(huán)鏈表就很好的彌補(bǔ)了這一缺點(diǎn),帶頭雙向循環(huán)鏈表看來比單鏈表結(jié)構(gòu)要復(fù)雜很多,但其實(shí)實(shí)現(xiàn)起來要比單鏈表更簡(jiǎn)單,更高效;下面我們就來實(shí)現(xiàn)帶頭雙向循環(huán)鏈表的接口函數(shù)吧!

3.1 頭結(jié)點(diǎn)初始化

頭結(jié)點(diǎn)初始化(ListInit)
首先是我們的頭結(jié)點(diǎn)的定義,它是不存放數(shù)據(jù)的,起到一個(gè)哨兵的作用
代碼如下:

void ListInit(LTNode* phead)
{
	// 哨兵位頭結(jié)點(diǎn)
	LTNode* phead = (LTNode*)malloc(sizeof(LTNode));
	phead->next = phead;
	phead->prev = phead;

	return phead;
}

第一步當(dāng)然是先使用malloc函數(shù)申請(qǐng)內(nèi)存空間,然后就是兩個(gè)指針的建立,尾部指針指向頭結(jié)點(diǎn)頭部,頭部指針指向頭結(jié)點(diǎn)尾部,返回帶頭結(jié)點(diǎn),頭結(jié)點(diǎn)初始化完成。

3.2 結(jié)點(diǎn)動(dòng)態(tài)內(nèi)存申請(qǐng)

結(jié)點(diǎn)動(dòng)態(tài)內(nèi)存申請(qǐng)(BuyListNode)
這個(gè)函數(shù)和上一篇中的單鏈表的函數(shù)類似
代碼如下:

LTNode* BuyListNode(LTDateType x)
{
	LTNode* newnode = (LTNode*)malloc(sizeof(LTNode));
	newnode->data = x;
	newnode->next = NULL;
	newnode->prev = NULL;
	return newnode;
}

第一步也是先使用malloc函數(shù)申請(qǐng)內(nèi)存空間,然后就是初始化這個(gè)結(jié)點(diǎn)的操作,將元素插入,兩個(gè)指針指向空,返回新結(jié)點(diǎn),完成結(jié)點(diǎn)初始化操作。

3.3 雙向鏈表尾插

雙向鏈表尾插(ListPushBack)
代碼如下:

void ListPushBack(LTNode* phead, LTDateType x)
{
	assert(phead);

	LTNode* tail = phead->prev;
	LTNode* newnode = BuyListNode(x);

	tail->next = newnode;
	newnode->prev = tail;
	newnode->next = phead;
	phead->prev = newnode;
}

這里我們先是把phead的上一級(jí)指針賦給tail
再將要插入的元素賦給臨時(shí)結(jié)點(diǎn)newnode
接著將tail的下一級(jí)指針指向newnode
再將newnode上一級(jí)指針指向tail
newnode下一級(jí)指針指向被插入結(jié)點(diǎn)phead
最后將phead的上一級(jí)指針再指向newnode完成尾插操作

3.4 雙向鏈表尾刪

雙向鏈表尾刪(ListPopBack)
代碼如下:

void ListPopBack(LTNode* phead)
{
	assert(phead);
	assert(phead->next != phead);//防止鏈表中無元素繼續(xù)刪除的斷言

	LTNode* tail = phead->prev;
	phead->prev = tail->prev;
	tail->prev->next = phead;

	free(tail);
}

上述代碼中第二個(gè)斷言是為了防止鏈表中無元素繼續(xù)刪除
這里我們也是先把phead的上一級(jí)指針賦給tail
再將tail的上一級(jí)指針賦給phead的上一級(jí)指針
也就是指向要?jiǎng)h除結(jié)點(diǎn)的上一結(jié)點(diǎn)
最后將要?jiǎng)h除結(jié)點(diǎn)的前一個(gè)結(jié)點(diǎn)的下一級(jí)指針指向頭結(jié)點(diǎn)
然后釋放掉tail的內(nèi)存空間完成尾刪

3.5 雙向鏈表頭插

雙向鏈表頭插(ListPushFront)
代碼如下:

void ListPushFront(LTNode* phead, LTDateType x)
{
	assert(phead);
	LTNode* newnode = BuyListNode(x);
	LTNode* next = phead->next;

	phead->next = newnode;
	newnode->prev = phead;

	newnode->next = next;
	next->prev = newnode;
}

這里我們先和尾插一樣將要插入的元素值賦給臨時(shí)結(jié)點(diǎn)newnode
將phead下一級(jí)指針賦給臨時(shí)結(jié)點(diǎn)next
再將newnode賦給phead下一級(jí)指針
也就是把phead的尾部指針指向newnode
把phead賦給newnode的上一級(jí)指針
再將next賦給newnode的下一級(jí)指針
最后把newnode賦給next的上一級(jí)指針,完成頭插

3.6 雙向鏈表頭刪

雙向鏈表頭刪(ListPopFront)
代碼如下:

void ListPopFront(LTNode* phead)
{
	assert(phead);
	assert(phead->next != phead);//防止鏈表中無元素繼續(xù)刪除的斷言

	LTNode* next = phead->next;
	LTNode* nextNext = next->next;

	phead->next = nextNext;
	nextNext->prev = phead;
	free(next);
}

和尾刪一樣這里的第二個(gè)斷言也是為了防止鏈表中無元素繼續(xù)刪除
頭刪的第一步就是將phead的下一級(jí)指針賦給next
再將next的下一級(jí)指針賦給nextNext
再將nextNext賦給phead的下一級(jí)指針
最后將phead賦給nextNext的上一指針
把next的內(nèi)存空間釋放完成頭刪

3.7 雙向鏈表查找

雙向鏈表查找(ListFind)
代碼如下:

LTNode* ListFind(LTNode* phead, LTDateType x)
{
	assert(phead);

	LTNode* cur = phead->next;
	while (cur != phead)
	{
		if (cur->data == x)
		{
			return cur;
		}
		cur = cur->next;
	}
	return NULL;
}

這里的查找就是使用一個(gè)while循環(huán)遍歷鏈表找到某節(jié)點(diǎn)的data符合要查找的值
找到了便返回結(jié)點(diǎn),如果遍歷一遍沒找到,則返回空(NULL)。

3.8 在pos位置前插入

pos位置前插入(ListInsert)
代碼如下:

void ListInsert(LTNode* pos, LTDateType x)
{
	assert(pos);
	LTNode* posPrev = pos->prev;
	LTNode* newnode = BuyListNode(x);

	posPrev->next = newnode;
	newnode->prev = posPrev;
	newnode->next = pos;
	pos->prev = newnode;
}

插入函數(shù)的實(shí)現(xiàn)首先創(chuàng)建第一個(gè)臨時(shí)結(jié)點(diǎn)posPrev
把pos的上一級(jí)指針賦給posPrev
將要插入的元素x賦給newnode
再將newnode賦給posPrev的下一級(jí)指針
再將posPrev賦給newnode的上一級(jí)指針
再將pos賦給newnode的下一級(jí)指針
最后將再將newnode賦給pos的上一級(jí)指針完成插入操作
在這里我們可以利用ListInsert函數(shù)將前面的尾插和頭插進(jìn)行同義替換
雙向鏈表尾插(ListPushBack)同義替換
代碼如下:

void ListPushBack(LTNode* phead, LTDateType x)
{
	assert(phead);
	ListInsert(phead, x);
}

雙向鏈表頭插(ListPushFront)同義替換
代碼如下:

void ListPushFront(LTNode* phead, LTDateType x)
{
	assert(phead);
	ListInsert(phead->next, x);
}

3.9 刪除pos位置的結(jié)點(diǎn)

刪除pos位置的結(jié)點(diǎn)(ListErase)
代碼如下:

void ListErase(LTNode* pos)
{
	assert(pos);

	LTNode* posPrev = pos->prev;
	LTNode* posNext = pos->next;

	posPrev->next = posNext;
	posNext->prev = posPrev;
	free(pos);
	pos = NULL;
}

首先將pos的上一級(jí)指針賦給posPrev
再將將pos的下一級(jí)指針賦給posNext
再將posNext賦給posPrev下一級(jí)指針
最后把posPrev賦給posNext上一級(jí)指針
將pos內(nèi)存空間釋放,使pos等于空(NULL),完成刪除。
同樣的,我們也可以利用這個(gè)ListErase函數(shù)對(duì)尾刪和頭刪進(jìn)行同義替換
雙向鏈表尾刪(ListPopBack)同義替換
代碼如下:

void ListPopBack(LTNode* phead)
{
	assert(phead);
	assert(phead->next != phead);
	ListErase(phead->prev);
}

雙向鏈表頭刪(ListPopFront)同義替換
代碼如下:

void ListPopFront(LTNode* phead)
{
	assert(phead);
	assert(phead->next != phead);
	ListErase(phead->next);
}

3.10 打印雙向鏈表

打印雙向鏈表(ListPrint)
代碼如下:

void ListPrint(LTNode* phead)
{
	assert(phead);

	LTNode* cur = phead->next;
	while (cur != phead)
	{
		printf("%d ", cur->data);
		cur = cur->next;
	}
	printf("\n");
}

這里的打印操作同樣是利用while循環(huán)進(jìn)行一遍遍歷打印輸出

3.11 銷毀雙向鏈表

銷毀雙向鏈表(ListDestroy)
代碼如下:

void ListDestroy(LTNode* phead)
{
	assert(phead);
	LTNode* cur = phead->next;
	while (cur != phead)
	{
		LTNode* next = cur->next;
		free(cur);
		cur = next;
	}

	free(phead);
	phead = NULL;
}

和打印函數(shù)原理一樣,只不過這里是再進(jìn)行遍歷的同時(shí)進(jìn)行逐個(gè)刪除
最后將phead內(nèi)存空間釋放,令phead等于空(NULL)完成鏈表銷毀操作。
在這里最后講一下斷言,在之前的單鏈表那一節(jié)的接口函數(shù)都有,寫斷言是為了讓代碼更健壯
一旦出現(xiàn)了編譯錯(cuò)誤,我們可以立馬排查出問題出在哪里,這是一個(gè)不錯(cuò)的代碼習(xí)慣
帶頭雙向循環(huán)鏈表接口代碼可能不是那么好理解,但是實(shí)現(xiàn)起來時(shí),卻更方便,所以帶頭雙向循環(huán)鏈表對(duì)于我們來說是非常必要的知識(shí)點(diǎn)!

4、順序表和鏈表的區(qū)別

特征 順序表 鏈表
存儲(chǔ)空間 物理上一定連續(xù) 邏輯上連續(xù)物理上不一定連續(xù)
隨機(jī)訪問 支持:O(1) 不支持:O(N)
任意位置插入或刪除元素 可能需要搬移元素,效率低O(N) 只需修改指針指向
插入 動(dòng)態(tài)順序表,空間不夠時(shí)需要擴(kuò)容 沒有容量的概念
應(yīng)用場(chǎng)景 元素高效存儲(chǔ)+頻繁訪問 任意位置插入和刪除頻繁
緩存利用率

5、結(jié)語

順序表到這一篇就結(jié)束了,這里的帶頭雙向循環(huán)鏈表可能在代碼體現(xiàn)上不是那么容易理解,這需要我們不斷的去進(jìn)行學(xué)習(xí)和實(shí)操,如果知識(shí)光看,在數(shù)據(jù)結(jié)構(gòu)這門課的學(xué)習(xí)上是不會(huì)有提高的,最重要的還是練習(xí)!?。?mark hidden color="red">文章來源:http://www.zghlxwxcb.cn/news/detail-410927.html

制作不易,如有不正之處敬請(qǐng)指出,感謝大家的來訪,UU們的觀看是我堅(jiān)持下去的動(dòng)力,在時(shí)間的催化劑下,讓我們彼此都成為更優(yōu)秀的人吧?。?!不要忘了一鍵三連呦!文章來源地址http://www.zghlxwxcb.cn/news/detail-410927.html

到了這里,關(guān)于數(shù)據(jù)結(jié)構(gòu)入門(C語言版)線性表帶頭雙向循環(huán)鏈表接口實(shí)現(xiàn)的文章就介紹完了。如果您還想了解更多內(nèi)容,請(qǐng)?jiān)谟疑辖撬阉鱐OY模板網(wǎng)以前的文章或繼續(xù)瀏覽下面的相關(guān)文章,希望大家以后多多支持TOY模板網(wǎng)!

本文來自互聯(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)文章

覺得文章有用就打賞一下文章作者

支付寶掃一掃打賞

博客贊助

微信掃一掃打賞

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

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

二維碼1

領(lǐng)取紅包

二維碼2

領(lǐng)紅包