最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

C語言編程數(shù)據(jù)結(jié)構(gòu)帶頭雙向循環(huán)鏈表全面詳解

 更新時(shí)間:2021年10月22日 14:25:36   作者:高郵吳少  
這篇文章主要為大家介紹了C語言編程的數(shù)據(jù)結(jié)構(gòu)中帶頭雙向循環(huán)鏈表全面詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助祝大家多多進(jìn)步,早日升職加薪

前言

上一篇數(shù)據(jù)結(jié)構(gòu)專欄:C語言數(shù)據(jù)結(jié)構(gòu)單鏈表接口函數(shù)全面講解教程

我們介紹了單鏈表的各個(gè)接口函數(shù),大家可能會(huì)發(fā)現(xiàn)單鏈表存在一些缺陷:比如它一個(gè)節(jié)點(diǎn)要存儲(chǔ)數(shù)據(jù)+下一個(gè)節(jié)點(diǎn)地址,占用的空間要遠(yuǎn)多于順序表;并且由于單鏈表是無法從后往前找的,如果你想進(jìn)行尾刪這樣的操作,你必須從第一個(gè)節(jié)點(diǎn)往后找,你的時(shí)間復(fù)雜度一定是O(n)。

為了解決上面的一些缺陷,我們今天來介紹帶頭雙向循環(huán)鏈表

一、什么是帶頭循環(huán)雙向鏈表

在這里插入圖片描述

這種鏈表會(huì)有一個(gè)哨兵位head節(jié)點(diǎn)指向d1,然后d1指向d2…這和單鏈表非常相似。
但和單鏈表最大的區(qū)別就是:這種鏈表的每個(gè)節(jié)點(diǎn)不僅會(huì)存儲(chǔ)下一個(gè)節(jié)點(diǎn)地址而且會(huì)存儲(chǔ)上一個(gè)節(jié)點(diǎn)的地址,然后尾節(jié)點(diǎn)會(huì)存儲(chǔ)一個(gè)指向哨兵位head的地址,然后哨兵位head會(huì)存儲(chǔ)一個(gè)指向尾結(jié)點(diǎn)的地址。
具體代碼如下:

typedef int LTDataType;//萬一以后需要改鏈表數(shù)據(jù)類型,可以直接在這里更改(int)
typedef struct ListNode
{
	struct ListNode*next;
	struct ListNode*prev;
	LTDataType data;
}ListNode;//結(jié)構(gòu)體重命名

示例:pandas 是基于NumPy 的一種工具,該工具是為了解決數(shù)據(jù)分析任務(wù)而創(chuàng)建的。

二、鏈表初始化

在這里插入圖片描述

類似于上圖的效果,剛開始創(chuàng)建只有一個(gè)節(jié)點(diǎn),它儲(chǔ)存的前地址和后地址都指向自己

代碼如下(示例):

#include<stdlib.h>//malloc函數(shù)頭文件
ListNode* BuyListNode(LTDataType x)//創(chuàng)建一個(gè)節(jié)點(diǎn)
{
	ListNode*newnode = (ListNode*)malloc(sizeof(ListNode));
	newnode->data = x;
	newnode->next = NULL;
	newnode->prev = NULL;
	return newnode;
}
ListNode* ListInit()//鏈表初始化
{
	ListNode*phead = BuyListNode(0);
	phead->next = phead;
	phead->prev = phead;
	return phead;
}

ps:這里L(fēng)istInit函數(shù)用的是返回值的方法,你也可以用二級(jí)指針傳參來進(jìn)行初始化操作

三、鏈表接口函數(shù)

1.尾插

在這里插入圖片描述

我們以上圖為例,原先鏈表的head節(jié)點(diǎn)的前驅(qū)指向3,然后3的后驅(qū)指向head節(jié)點(diǎn),那在3后面怎么進(jìn)行尾插呢?由于head節(jié)點(diǎn)里存放了3節(jié)點(diǎn)的地址,所以我們可以直接找到3節(jié)點(diǎn),找到之后怎么辦?把head節(jié)點(diǎn)的前驅(qū)改成4節(jié)點(diǎn)地址,3節(jié)點(diǎn)后驅(qū)改為4節(jié)點(diǎn)地址,最后4節(jié)點(diǎn)后驅(qū)指向head節(jié)點(diǎn)。如下圖:

在這里插入圖片描述

代碼如下(示例):

#include<assert.h>//assert函數(shù)頭文件
void ListPushBack(ListNode*phead, LTDataType x)//尾插
{
    assert(phead);//對(duì)傳過來的指針進(jìn)行斷言,因?yàn)槟阋M(jìn)行尾插至少得有個(gè)頭節(jié)點(diǎn)啊
    //如果傳過來的是空指針會(huì)進(jìn)行報(bào)錯(cuò)
	ListNode*tail = phead->prev;
	ListNode*newnode = BuyListNode(x);
	tail->next = newnode;
	newnode->prev = tail;
	newnode->data = phead;
	phead->prev = newnode;
}

2.頭插

在這里插入圖片描述

如上圖,先要在head和d1之間進(jìn)行頭插,怎么操作?非常簡(jiǎn)單,思路和尾插一模一樣
head的后驅(qū)指向newnode,newnode的前驅(qū)和后驅(qū)分別指向phead和d1,d1前驅(qū)指向newnode如下圖:

在這里插入圖片描述

代碼如下(示例):

void ListPushFront(ListNode*phead,LTDataType x)
{
	assert(phead);
	ListNode*first = phead->next;
	ListNode*newnode = BuyListNode(x);
	phead->next = newnode;
	newnode->prev = phead;
	newnode->next = first;
	first->prev = newnode;
}

注意?。?!這里是先定義了一個(gè)first來存放d1這個(gè)地址,如果不事先定義的話,phead->next = newnode;head不再存儲(chǔ)d1地址,你就找不到d1了。當(dāng)然了,如果你就是不想先定義一個(gè)first來存放d1地址也可以。怎么做呢?“先連后斷”,newnode后驅(qū)先接上d1節(jié)點(diǎn),然后你head節(jié)點(diǎn)后驅(qū)接上newnode。

3.頭刪

頭刪也是和前面兩個(gè)類似的思想

在這里插入圖片描述

頭刪也就是把d1節(jié)點(diǎn)刪掉,我們定義2個(gè)指針分別指向d1和d2,然后把head節(jié)點(diǎn)后驅(qū)接指向d2,d2前驅(qū)指向head即可,如下圖:

在這里插入圖片描述

代碼如下(示例):

void ListPopFront(ListNode*phead)
{
	assert(phead);
	ListNode*first = phead->next;
	ListNode*second = first->next;
	phead->next = second;
	second->prev = phead;
}

4.尾刪

在這里插入圖片描述

現(xiàn)在要?jiǎng)h除d3這個(gè)節(jié)點(diǎn),我們定義一個(gè)tail和prev指針分別指向d3和d2,然后把d2后驅(qū)接上head,head前驅(qū)接上d2即可,如下圖:

在這里插入圖片描述

代碼如下(示例):

void ListPopBack(ListNode*phead)
{
	assert(phead);
	assert(phead->next != phead);//要進(jìn)行尾刪至少保證有一個(gè)節(jié)點(diǎn)可刪(非head節(jié)點(diǎn))
	ListNode*tail = phead->prev;//頭節(jié)點(diǎn)前驅(qū)指向尾部
	ListNode*prev = tail->prev;//通過尾部得到d2地址
	prev->next = phead;//d2后驅(qū)head節(jié)點(diǎn)
	phead->prev = prev;//head前驅(qū)指向d2節(jié)點(diǎn)
}

5.任意位置插入數(shù)據(jù)

要在某個(gè)位置前插入數(shù)據(jù),你需要先找到那個(gè)位置在哪里,我們先寫一個(gè)查找函數(shù)

在這里插入圖片描述

怎么個(gè)找法呢?很簡(jiǎn)單,定義一個(gè)cur指針,然后從d1開始遍歷看有沒有我們想要找的數(shù)據(jù),遍歷到head節(jié)點(diǎn)結(jié)束。
代碼如下(示例):

ListNode* ListFind(ListNode*phead, LTDataType x)
{
	assert(phead);
	ListNode*cur = phead->next;
	while (cur != phead)
	{
		if (cur->data == x)
		{
			return cur;
		}
		cur = cur->next;
	}
	return NULL;//遍歷完鏈表都沒有找到就返回空指針
}

找到所需位置后就是進(jìn)行,插入操作

void ListInsert(ListNode*pos, LTDataType x)
{
	assert(pos);
	ListNode*prev = pos->prev;
	ListNode*newnode = BuyListNode(x);
	prev->next = newnode;
	newnode->prev = prev;
	newnode->next = pos;
	pos->prev = newnode;
}

兩個(gè)函數(shù)一起調(diào)用也是很簡(jiǎn)單的,比如我現(xiàn)在要在鏈表里數(shù)據(jù)3的位置前插入300,下面兩行代碼即可完成兩個(gè)函數(shù)的運(yùn)用。

ListNode*pos = ListFind(plist, 3);
ListInsert(pos, 300);

ps:這里找到所需位置指針,你如果需要,也可以通過該指針對(duì)該位置的值進(jìn)行修改,比如(返回的指針)->data=n

6.任意位置刪除數(shù)據(jù)

在這里插入圖片描述

現(xiàn)在要?jiǎng)h除pos位置的數(shù)據(jù),怎么操作?非常簡(jiǎn)單!定義一個(gè)prev指向pos前一個(gè)節(jié)點(diǎn),定義一個(gè)next指向pos后一個(gè)節(jié)點(diǎn),然后prev和next連起來即可,如圖:

在這里插入圖片描述

代碼如下(示例):

void ListErase(ListNode*pos)//指定位置刪除
{
	assert(pos);
	ListNode*prev = pos->prev;
	ListNode*next = pos->next;
	prev->next = next;
	next->prev = prev;
	free(pos);//prev和next連起來了,pos就可以被釋放掉了
}

四、打印鏈表

在這里插入圖片描述

以上圖為例:要打印一個(gè)鏈表,head節(jié)點(diǎn)是不需要打印的,我們只需要打印存儲(chǔ)實(shí)際數(shù)據(jù)的d1,d2,d3即可,定義一個(gè)變量cur,讓它從d1開始遍歷,到head節(jié)點(diǎn)結(jié)束即可。
代碼如下(示例):

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

總結(jié)

本文介紹了帶頭循環(huán)雙向鏈表,包括其定義、各個(gè)接口函數(shù)、及其遍歷打印。雖然是鏈表中最復(fù)雜的結(jié)構(gòu),但它的代碼操作卻是最簡(jiǎn)單的,希望通過今天的學(xué)習(xí)讀者能有所收獲~更多關(guān)于帶頭雙向循環(huán)鏈表數(shù)據(jù)結(jié)構(gòu)的資料請(qǐng)關(guān)注腳本之家其它相關(guān)文章!

相關(guān)文章

  • Qt跨平臺(tái)窗口選擇功能的實(shí)現(xiàn)過程

    Qt跨平臺(tái)窗口選擇功能的實(shí)現(xiàn)過程

    很多時(shí)候?yàn)榱朔奖丬浖氖褂?我們需要讓編寫的界面程序顯示在最上層,這時(shí)候就需要對(duì)窗口屬性進(jìn)行調(diào)整,下面這篇文章主要給大家介紹了關(guān)于Qt跨平臺(tái)窗口選擇功能的實(shí)現(xiàn)過程,需要的朋友可以參考下
    2022-12-12
  • 詳解C++11強(qiáng)類型枚舉

    詳解C++11強(qiáng)類型枚舉

    這篇文章主要介紹了C++11強(qiáng)類型枚舉的相關(guān)資料,幫助大家更好的理解和學(xué)習(xí)c++11,感興趣的朋友可以了解下
    2020-08-08
  • C語言的可變參數(shù)函數(shù)實(shí)現(xiàn)詳解

    C語言的可變參數(shù)函數(shù)實(shí)現(xiàn)詳解

    某些情況下我們希望函數(shù)的參數(shù)個(gè)數(shù)可以根據(jù)需要確定,因此c語言引入可變參數(shù)函數(shù)。典型的可變參數(shù)函數(shù)的例子有printf()、scanf()等,下面我就開始講解
    2021-08-08
  • C語言雙向鏈表的原理與使用操作

    C語言雙向鏈表的原理與使用操作

    雙向鏈表也叫雙鏈表,是鏈表的一種,它的每個(gè)數(shù)據(jù)結(jié)點(diǎn)中都有兩個(gè)指針,分別指向直接后繼和直接前驅(qū)。本文主要介紹了C語言算法中雙向鏈表的實(shí)現(xiàn),需要的可以參考一下
    2022-05-05
  • C語言進(jìn)程程序替換的實(shí)現(xiàn)詳解

    C語言進(jìn)程程序替換的實(shí)現(xiàn)詳解

    為什么要進(jìn)程替換?因?yàn)楦高M(jìn)程創(chuàng)建出來的子進(jìn)程和父進(jìn)程擁有相同的代碼段,所以,子進(jìn)程看到的代碼和父進(jìn)程是一樣的。當(dāng)我們想要讓子進(jìn)程執(zhí)行不同的程序時(shí)候,就需要讓子進(jìn)程調(diào)用進(jìn)程程序替換的接口,從而讓子進(jìn)程執(zhí)行不一樣的代碼
    2022-08-08
  • Windows窗口消息實(shí)例詳解

    Windows窗口消息實(shí)例詳解

    這篇文章主要介紹了Windows窗口消息,以實(shí)例形式詳細(xì)羅列了Windows窗口消息,非常具有實(shí)用價(jià)值,需要的朋友可以參考下
    2015-05-05
  • C++實(shí)現(xiàn)含附件的郵件發(fā)送功能

    C++實(shí)現(xiàn)含附件的郵件發(fā)送功能

    這篇文章主要為大家詳細(xì)介紹了C++實(shí)現(xiàn)含附件的郵件發(fā)送功能,具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下
    2018-05-05
  • Qt使用SQLite數(shù)據(jù)庫實(shí)現(xiàn)數(shù)據(jù)增刪改查

    Qt使用SQLite數(shù)據(jù)庫實(shí)現(xiàn)數(shù)據(jù)增刪改查

    這篇文章主要為大家詳細(xì)介紹了Qt如何使用SQLite數(shù)據(jù)庫實(shí)現(xiàn)數(shù)據(jù)增刪改查功能,文中的示例代碼講解詳細(xì),感興趣的小伙伴可以跟隨小編一起了解一下
    2023-06-06
  • C++深入刨析muduo中的抽象類Poller

    C++深入刨析muduo中的抽象類Poller

    muduo網(wǎng)絡(luò)庫中Poller類是一個(gè)抽象類,用戶使用PollPoller或者EPollPoller類,下面跟隨小編一起來詳細(xì)了解一下
    2022-04-04
  • 基于C++實(shí)現(xiàn)的線程休眠代碼

    基于C++實(shí)現(xiàn)的線程休眠代碼

    這篇文章主要介紹了基于C++實(shí)現(xiàn)的線程休眠代碼,包括了Linux平臺(tái)及基于boost庫的兩種實(shí)現(xiàn)方法,有不錯(cuò)的參考借鑒價(jià)值,需要的朋友可以參考下
    2014-10-10

最新評(píng)論

开原市| 甘孜| 泰来县| 松原市| 普洱| 克什克腾旗| 略阳县| 威信县| 安徽省| 泗洪县| 黔东| 马尔康县| 巢湖市| 府谷县| 中超| 禄丰县| 砚山县| 博兴县| 措美县| 沂南县| 崇礼县| 广元市| 锡林郭勒盟| 南充市| 湘乡市| 嵊州市| 贵定县| 繁昌县| 平塘县| 策勒县| 宁河县| 邮箱| 汪清县| 沾益县| 云林县| 陆良县| 新蔡县| 炉霍县| 雷州市| 潜江市| 河南省|