在线观看www成人影院-在线观看www日本免费网站-在线观看www视频-在线观看操-欧美18在线-欧美1级

0
  • 聊天消息
  • 系統(tǒng)消息
  • 評(píng)論與回復(fù)
登錄后你可以
  • 下載海量資料
  • 學(xué)習(xí)在線課程
  • 觀看技術(shù)視頻
  • 寫文章/發(fā)帖/加入社區(qū)
會(huì)員中心
电子发烧友
开通电子发烧友VIP会员 尊享10大特权
海量资料免费下载
精品直播免费看
优质内容免费畅学
课程9折专享价
創(chuàng)作中心

完善資料讓更多小伙伴認(rèn)識(shí)你,還能領(lǐng)取20積分哦,立即完善>

3天內(nèi)不再提示

搞懂鏈表 看一文就夠了!

工程師 ? 來(lái)源:大魚機(jī)器人 ? 作者:大魚機(jī)器人 ? 2020-09-15 15:20 ? 次閱讀

來(lái)源:大魚機(jī)器人

數(shù)組—順序存儲(chǔ)

數(shù)組作為一個(gè)順序儲(chǔ)存方式的數(shù)據(jù)結(jié)構(gòu),可是有大作為的,它的靈活使用為我們的程序設(shè)計(jì)帶來(lái)了大量的便利;

但是,但是,數(shù)組最大的缺點(diǎn)就是我們的插入和刪除時(shí)需要移動(dòng)大量的元素,所以呢,大量的消耗時(shí)間,以及冗余度難以接受了。

C語(yǔ)言數(shù)組插入一個(gè)元素為例,當(dāng)我們需要在一個(gè)數(shù)組{1,2,3,4}的第1個(gè)元素后的位置插入一個(gè)’A’時(shí),我們需要做的有:

將第1個(gè)元素后的整體元素后移,形成新的數(shù)組{1,2,2,3,4}

再將第2個(gè)元素位置的元素替換為我們所需要的元素’A’

最終形成我們的預(yù)期,這需要很多的操作喔。

上圖可以看出,使用數(shù)組都有這兩大缺點(diǎn):

插入刪除操作所需要移動(dòng)的元素很多,浪費(fèi)算力。

必須為數(shù)組開足夠的空間,否則有溢出風(fēng)險(xiǎn)。

鏈表—鏈?zhǔn)酱鎯?chǔ)

由于數(shù)組的這些缺點(diǎn),自然而然的就產(chǎn)生鏈表的思想了。

鏈表通過(guò)不連續(xù)的儲(chǔ)存方式,自適應(yīng)內(nèi)存大小,以及指針的靈活使用,巧妙的簡(jiǎn)化了上述的內(nèi)容。

鏈表的基本思維是,利用結(jié)構(gòu)體的設(shè)置,額外開辟出一份內(nèi)存空間去作指針,它總是指向下一個(gè)結(jié)點(diǎn),一個(gè)個(gè)結(jié)點(diǎn)通過(guò)NEXT指針相互串聯(lián),就形成了鏈表。

其中DATA為自定義的數(shù)據(jù)類型,NEXT為指向下一個(gè)鏈表結(jié)點(diǎn)的指針,通過(guò)訪問NEXT,可以引導(dǎo)我們?nèi)ピL問鏈表的下一個(gè)結(jié)點(diǎn)。

對(duì)于一連串的結(jié)點(diǎn)而言,就形成了鏈表如下圖:

上文所說(shuō)的插入刪除操作只需要修改指針?biāo)赶虻膮^(qū)域就可以了,不需要進(jìn)行大量的數(shù)據(jù)移動(dòng)操作。如下圖:

相比起數(shù)組,鏈表解決了數(shù)組不方便移動(dòng),插入,刪除元素的弊端,但相應(yīng)的,鏈表付出了更加大的內(nèi)存犧牲換來(lái)的這些功能的實(shí)現(xiàn)。

鏈表概述

包含單鏈表,雙鏈表,循環(huán)單鏈表,實(shí)際應(yīng)用中的功能不同,但實(shí)現(xiàn)方式都差不多。

單鏈表就像是美國(guó)男籃,一代一代往下傳;

雙鏈表像是中國(guó)男足,你傳球給我,我傳球給你,最終傳給了守門員;

循環(huán)鏈表就像是中國(guó)男籃,火炬從姚明傳給王治郅,王治郅傳給易建聯(lián),現(xiàn)在易建聯(lián)傷了,又傳給了姚明

單鏈表

單鏈表概念和簡(jiǎn)單的設(shè)計(jì)

單鏈表是一種鏈?zhǔn)酱嫒〉臄?shù)據(jù)結(jié)構(gòu),鏈表中的數(shù)據(jù)是以結(jié)點(diǎn)來(lái)表示的,每個(gè)結(jié)點(diǎn)由元素和指針構(gòu)成。

元素表示數(shù)據(jù)元素的映象,就是存儲(chǔ)數(shù)據(jù)的存儲(chǔ)單元;指針指示出后繼元素存儲(chǔ)位置,就是連接每個(gè)結(jié)點(diǎn)的地址數(shù)據(jù)。

以結(jié)點(diǎn)的序列表示的線性表稱作線性鏈表,也就是單鏈表,單鏈表是鏈?zhǔn)酱嫒〉慕Y(jié)構(gòu)。

對(duì)于鏈表的每一個(gè)結(jié)點(diǎn),我們使用結(jié)構(gòu)體進(jìn)行設(shè)計(jì),其主要內(nèi)容有:

其中,DATA數(shù)據(jù)元素,可以為你想要儲(chǔ)存的任何數(shù)據(jù)格式,可以是數(shù)組,可以是int,甚至可以是結(jié)構(gòu)體(這就是傳說(shuō)中的結(jié)構(gòu)體套結(jié)構(gòu)體)

NEXT為一個(gè)指針,其代表了一個(gè)可以指向的區(qū)域,通常是用來(lái)指向下一個(gè)結(jié)點(diǎn),鏈表的尾部NEXT指向NULL(空),因?yàn)槲膊繘]有任何可以指向的空間了

故,對(duì)于一個(gè)單鏈表的結(jié)點(diǎn)定義,可以代碼描述成:

//定義結(jié)點(diǎn)類型typedef struct Node { int data; //數(shù)據(jù)類型,你可以把int型的data換成任意數(shù)據(jù)類型,包括結(jié)構(gòu)體struct等復(fù)合類型 struct Node *next; //單鏈表的指針域} Node,*LinkedList; //Node表示結(jié)點(diǎn)的類型,LinkedList表示指向Node結(jié)點(diǎn)類型的指針類型

鏈表的初始化

初始化主要完成以下工作:創(chuàng)建一個(gè)單鏈表的前置節(jié)點(diǎn)并向后逐步添加節(jié)點(diǎn),一般指的是申請(qǐng)結(jié)點(diǎn)的空間,同時(shí)對(duì)一個(gè)結(jié)點(diǎn)賦空值(NULL),其代碼可以表示為:

LinkedList listinit(){ Node *L; L=(Node*)malloc(sizeof(Node)); //開辟空間 if(L==NULL){ //判斷是否開辟空間失敗,這一步很有必要 printf(“申請(qǐng)空間失敗”); //exit(0); //開辟空間失敗可以考慮直接結(jié)束程序 } L-》next=NULL; //指針指向空}

注意:一定要判斷是否開辟空間失敗,否則生產(chǎn)中由于未知的情況造成空間開辟失敗,仍然在繼續(xù)執(zhí)行代碼,后果將不堪設(shè)想啦,因此養(yǎng)成這樣的判斷是很有必要的。

頭插入法創(chuàng)建單鏈表

利用指針指向下一個(gè)結(jié)點(diǎn)元素的方式進(jìn)行逐個(gè)創(chuàng)建,使用頭插入法最終得到的結(jié)果是逆序的。如圖所示:

從一個(gè)空表開始,生成新結(jié)點(diǎn),并將讀取到的數(shù)據(jù)存放到新結(jié)點(diǎn)的數(shù)據(jù)域中,然后將新結(jié)點(diǎn)插入到當(dāng)前鏈表的表頭,即頭結(jié)點(diǎn)之后。

//頭插法建立單鏈表LinkedList LinkedListCreatH() { Node *L; L = (Node *)malloc(sizeof(Node)); //申請(qǐng)頭結(jié)點(diǎn)空間 L-》next = NULL; //初始化一個(gè)空鏈表 int x; //x為鏈表數(shù)據(jù)域中的數(shù)據(jù) while(scanf(“%d”,&x) != EOF) { Node *p; p = (Node *)malloc(sizeof(Node)); //申請(qǐng)新的結(jié)點(diǎn) p-》data = x; //結(jié)點(diǎn)數(shù)據(jù)域賦值 p-》next = L-》next; //將結(jié)點(diǎn)插入到表頭L--》|2|--》|1|--》NULL L-》next = p; } return L;}

尾插入法創(chuàng)建單鏈表

如圖所示為尾插入法的創(chuàng)建過(guò)程。

頭插法生成的鏈表中,結(jié)點(diǎn)的次序和輸入數(shù)據(jù)的順序不一致。若希望兩者次序一致,則需要尾插法。

該方法是將新結(jié)點(diǎn)逐個(gè)插入到當(dāng)前鏈表的表尾上,為此必須增加一個(gè)尾指針r, 使其始終指向當(dāng)前鏈表的尾結(jié)點(diǎn),代碼如下:

//尾插法建立單鏈表 LinkedList LinkedListCreatT() { Node *L; L = (Node *)malloc(sizeof(Node)); //申請(qǐng)頭結(jié)點(diǎn)空間 L-》next = NULL; //初始化一個(gè)空鏈表 Node *r; r = L; //r始終指向終端結(jié)點(diǎn),開始時(shí)指向頭結(jié)點(diǎn) int x; //x為鏈表數(shù)據(jù)域中的數(shù)據(jù) while(scanf(“%d”,&x) != EOF) { Node *p; p = (Node *)malloc(sizeof(Node)); //申請(qǐng)新的結(jié)點(diǎn) p-》data = x; //結(jié)點(diǎn)數(shù)據(jù)域賦值 r-》next = p; //將結(jié)點(diǎn)插入到表頭L--》|1|--》|2|--》NULL r = p; } r-》next = NULL; return L;}

遍歷單鏈表如打印、修改

從鏈表的頭開始,逐步向后進(jìn)行每一個(gè)元素的訪問,稱為遍歷。

對(duì)于遍歷操作,我們可以衍生出很多常用的數(shù)據(jù)操作,比如查詢?cè)兀薷脑兀@取元素個(gè)數(shù),打印整個(gè)鏈表數(shù)據(jù)等等。

進(jìn)行遍歷的思路極其簡(jiǎn)單,只需要建立一個(gè)指向鏈表L的結(jié)點(diǎn),然后沿著鏈表L逐個(gè)向后搜索即可,代碼如下:

//便利輸出單鏈表void printList(LinkedList L){ Node *p=L-》next; int i=0; while(p){ printf(“第%d個(gè)元素的值為:%d\n”,++i,p-》data); p=p-》next; }}

對(duì)于元素修改操作,以下是代碼實(shí)現(xiàn):

//鏈表內(nèi)容的修改,在鏈表中修改值為x的元素變?yōu)闉閗。LinkedList LinkedListReplace(LinkedList L,int x,int k) { Node *p=L-》next; int i=0; while(p){ if(p-》data==x){ p-》data=k; } p=p-》next; } return L;}

簡(jiǎn)單的遍歷設(shè)計(jì)的函數(shù)只需要void無(wú)參即可,而當(dāng)涉及到元素操作時(shí),可以設(shè)計(jì)一個(gè)LinkedList類型的函數(shù),使其返回一個(gè)操作后的新鏈表。

插入操作

鏈表的插入操作主要分為查找到第i個(gè)位置,將該位置的next指針修改為指向我們新插入的結(jié)點(diǎn),而新插入的結(jié)點(diǎn)next指針指向我們i+1個(gè)位置的結(jié)點(diǎn)。

其操作方式可以設(shè)置一個(gè)前驅(qū)結(jié)點(diǎn),利用循環(huán)找到第i個(gè)位置,再進(jìn)行插入。

如圖,在DATA1和DATA2數(shù)據(jù)結(jié)點(diǎn)之中插入一個(gè)NEW_DATA數(shù)據(jù)結(jié)點(diǎn):

從原來(lái)的鏈表狀態(tài)

到新的鏈表狀態(tài):

代碼實(shí)現(xiàn)如下:

//單鏈表的插入,在鏈表的第i個(gè)位置插入x的元素 LinkedList LinkedListInsert(LinkedList L,int i,int x) { Node *pre; //pre為前驅(qū)結(jié)點(diǎn) pre = L; int tempi = 0; for (tempi = 1; tempi 《 i; tempi++) { pre = pre-》next; //查找第i個(gè)位置的前驅(qū)結(jié)點(diǎn) } Node *p; //插入的結(jié)點(diǎn)為p p = (Node *)malloc(sizeof(Node)); p-》data = x; p-》next = pre-》next; pre-》next = p; return L;}

刪除操作

刪除元素要建立一個(gè)前驅(qū)結(jié)點(diǎn)和一個(gè)當(dāng)前結(jié)點(diǎn),當(dāng)找到了我們需要?jiǎng)h除的數(shù)據(jù)時(shí),直接使用前驅(qū)結(jié)點(diǎn)跳過(guò)要?jiǎng)h除的結(jié)點(diǎn)指向要?jiǎng)h除結(jié)點(diǎn)的后一個(gè)結(jié)點(diǎn),再將原有的結(jié)點(diǎn)通過(guò)free函數(shù)釋放掉。如圖所示:

代碼如下:

//單鏈表的刪除,在鏈表中刪除值為x的元素 LinkedList LinkedListDelete(LinkedList L,int x) { Node *p,*pre; //pre為前驅(qū)結(jié)點(diǎn),p為查找的結(jié)點(diǎn)。 p = L-》next; while(p-》data != x) { //查找值為x的元素 pre = p; p = p-》next; } pre-》next = p-》next; //刪除操作,將其前驅(qū)next指向其后繼。 free(p); return L;}

雙向鏈表

雙向鏈表的簡(jiǎn)介以及概念

單鏈表是指結(jié)點(diǎn)中只有一個(gè)指向其后繼的指針,具有單向性,但是有時(shí)需要搜索大量數(shù)據(jù)的時(shí)候,就需要多次進(jìn)行從頭開始的遍歷,這樣的搜索就不是很高效了。

在單鏈表的基礎(chǔ)上,對(duì)于每一個(gè)結(jié)點(diǎn)設(shè)計(jì)一個(gè)前驅(qū)結(jié)點(diǎn),前驅(qū)結(jié)點(diǎn)與前一個(gè)結(jié)點(diǎn)相互連接,構(gòu)成一個(gè)鏈表,就產(chǎn)生了雙向鏈表的概念了。

雙向鏈表可以簡(jiǎn)稱為雙鏈表,是鏈表的一種,它的每個(gè)數(shù)據(jù)結(jié)點(diǎn)中都有兩個(gè)指針,分別指向直接后繼和直接前驅(qū)。所以,從雙向鏈表中的任意一個(gè)結(jié)點(diǎn)開始,都可以很方便地訪問它的前驅(qū)結(jié)點(diǎn)和后繼結(jié)點(diǎn)。

雙向鏈表示意圖

一個(gè)完整的雙向鏈表應(yīng)該是頭結(jié)點(diǎn)的pre指針指為空,尾結(jié)點(diǎn)的next指針指向空,其余結(jié)點(diǎn)前后相鏈。

雙向鏈表的結(jié)點(diǎn)設(shè)計(jì)

對(duì)于每一個(gè)結(jié)點(diǎn)而言,有:

其中,DATA表示數(shù)據(jù),其可以是簡(jiǎn)單的類型也可以是復(fù)雜的結(jié)構(gòu)體;

pre代表的是前驅(qū)指針,它總是指向當(dāng)前結(jié)點(diǎn)的前一個(gè)結(jié)點(diǎn),如果當(dāng)前結(jié)點(diǎn)是頭結(jié)點(diǎn),則pre指針為空;

next代表的是后繼指針,它總是指向當(dāng)前結(jié)點(diǎn)的下一個(gè)結(jié)點(diǎn),如果當(dāng)前結(jié)點(diǎn)是尾結(jié)點(diǎn),則next指針為空

其代碼設(shè)計(jì)如下:

typedef struct line{ int data; //data struct line *pre; //pre node struct line *next; //next node}line,*a;//分別表示該結(jié)點(diǎn)的前驅(qū)(pre),后繼(next),以及當(dāng)前數(shù)據(jù)(data)

雙鏈表的創(chuàng)建

創(chuàng)建雙向鏈表需要先創(chuàng)建頭結(jié)點(diǎn),然后逐步的進(jìn)行添加雙向鏈表的頭結(jié)點(diǎn)是有數(shù)據(jù)元素的,也就是頭結(jié)點(diǎn)的data域中是存有數(shù)據(jù)的,這與一般的單鏈表是不同的。

對(duì)于逐步添加數(shù)據(jù),先開辟一段新的內(nèi)存空間作為新的結(jié)點(diǎn),為這個(gè)結(jié)點(diǎn)進(jìn)行的data進(jìn)行賦值,然后將已成鏈表的上一個(gè)結(jié)點(diǎn)的next指針指向自身,自身的pre指針指向上一個(gè)結(jié)點(diǎn)。

其代碼可以設(shè)計(jì)為:

//創(chuàng)建雙鏈表line* initLine(line * head){ int number,pos=1,input_data; //三個(gè)變量分別代表結(jié)點(diǎn)數(shù)量,當(dāng)前位置,輸入的數(shù)據(jù) printf(“請(qǐng)輸入創(chuàng)建結(jié)點(diǎn)的大小\n”); scanf(“%d”,&number); if(number《1){return NULL;} //輸入非法直接結(jié)束 //////頭結(jié)點(diǎn)創(chuàng)建/////// head=(line*)malloc(sizeof(line)); head-》pre=NULL; head-》next=NULL; printf(“輸入第%d個(gè)數(shù)據(jù)\n”,pos++); scanf(“%d”,&input_data); head-》data=input_data; line * list=head; while (pos《=number) { line * body=(line*)malloc(sizeof(line)); body-》pre=NULL; body-》next=NULL; printf(“輸入第%d個(gè)數(shù)據(jù)\n”,pos++); scanf(“%d”,&input_data); body-》data=input_data; list-》next=body; body-》pre=list; list=list-》next; } return head;}

雙向鏈表創(chuàng)建的過(guò)程可以分為:創(chuàng)建頭結(jié)點(diǎn)-》創(chuàng)建一個(gè)新的結(jié)點(diǎn)-》將頭結(jié)點(diǎn)和新結(jié)點(diǎn)相互鏈接-》再度創(chuàng)建新結(jié)點(diǎn),這樣會(huì)有助于理解。

雙向鏈表的插入操作

如圖所示:

對(duì)于每一次的雙向鏈表的插入操作,首先需要?jiǎng)?chuàng)建一個(gè)獨(dú)立的結(jié)點(diǎn),并通過(guò)malloc操作開辟相應(yīng)的空間;

其次我們選中這個(gè)新創(chuàng)建的獨(dú)立節(jié)點(diǎn),將其的pre指針指向所需插入位置的前一個(gè)結(jié)點(diǎn);

同時(shí),其所需插入的前一個(gè)結(jié)點(diǎn)的next指針修改指向?yàn)樵撔碌慕Y(jié)點(diǎn),該新的結(jié)點(diǎn)的next指針將會(huì)指向一個(gè)原本的下一個(gè)結(jié)點(diǎn),而修改下一個(gè)結(jié)點(diǎn)的pre指針為指向新結(jié)點(diǎn)自身,這樣的一個(gè)操作我們稱之為雙向鏈表的插入操作。

其代碼可以表示為:

//插入數(shù)據(jù)line * insertLine(line * head,int data,int add){ //三個(gè)參數(shù)分別為:進(jìn)行此操作的雙鏈表,插入的數(shù)據(jù),插入的位置 //新建數(shù)據(jù)域?yàn)閐ata的結(jié)點(diǎn) line * temp=(line*)malloc(sizeof(line)); temp-》data=data; temp-》pre=NULL; temp-》next=NULL; //插入到鏈表頭,要特殊考慮 if (add==1) { temp-》next=head; head-》pre=temp; head=temp; }else{ line * body=head; //找到要插入位置的前一個(gè)結(jié)點(diǎn) for (int i=1; i《add-1; i++) { body=body-》next; } //判斷條件為真,說(shuō)明插入位置為鏈表尾 if (body-》next==NULL) { body-》next=temp; temp-》pre=body; }else{ body-》next-》pre=temp; temp-》next=body-》next; body-》next=temp; temp-》pre=body; } } return head;}

雙向鏈表的刪除操作

如圖:

刪除操作的過(guò)程是:選擇需要?jiǎng)h除的結(jié)點(diǎn)-》選中這個(gè)結(jié)點(diǎn)的前一個(gè)結(jié)點(diǎn)-》將前一個(gè)結(jié)點(diǎn)的next指針指向自己的下一個(gè)結(jié)點(diǎn)-》選中該節(jié)點(diǎn)的下一個(gè)結(jié)點(diǎn)-》將下一個(gè)結(jié)點(diǎn)的pre指針修改指向?yàn)樽约旱纳弦粋€(gè)結(jié)點(diǎn)。

在進(jìn)行遍歷的時(shí)候直接將這一個(gè)結(jié)點(diǎn)給跳過(guò)了,之后,我們釋放刪除結(jié)點(diǎn),歸還空間給內(nèi)存,這樣的操作我們稱之為雙鏈表的刪除操作。

其代碼可以表示為:

//刪除元素line * deleteLine(line * head,int data){ //輸入的參數(shù)分別為進(jìn)行此操作的雙鏈表,需要?jiǎng)h除的數(shù)據(jù) line * list=head; //遍歷鏈表 while (list) { //判斷是否與此元素相等 //刪除該點(diǎn)方法為將該結(jié)點(diǎn)前一結(jié)點(diǎn)的next指向該節(jié)點(diǎn)后一結(jié)點(diǎn) //同時(shí)將該結(jié)點(diǎn)的后一結(jié)點(diǎn)的pre指向該節(jié)點(diǎn)的前一結(jié)點(diǎn) if (list-》data==data) { list-》pre-》next=list-》next; list-》next-》pre=list-》pre; free(list); printf(“--刪除成功--\n”); return head; } list=list-》next; } printf(“Error:沒有找到該元素,沒有產(chǎn)生刪除\n”); return head;}

雙向鏈表的遍歷

雙向鏈表的遍歷利用next指針逐步向后進(jìn)行索引即可。

注意,在判斷這里,我們既可以用while(list)的操作直接判斷是否鏈表為空,也可以使用while(list-》next)的操作判斷該鏈表是否為空,其下一節(jié)點(diǎn)為空和本結(jié)點(diǎn)是否為空的判斷條件是一樣的效果。

其簡(jiǎn)單的代碼可以表示為:

//遍歷雙鏈表,同時(shí)打印元素?cái)?shù)據(jù)void printLine(line *head){ line *list = head; int pos=1; while(list){ printf(“第%d個(gè)數(shù)據(jù)是:%d\n”,pos++,list-》data); list=list-》next; }}

循環(huán)鏈表

循環(huán)鏈表概念

對(duì)于單鏈表以及雙向鏈表,就像一個(gè)小巷,無(wú)論怎么走最終都能從一端走到另一端,顧名思義,循環(huán)鏈表則像一個(gè)有傳送門的小巷,當(dāng)你以為你走到結(jié)尾的時(shí)候,其實(shí)這就是開頭。

循環(huán)鏈表和非循環(huán)鏈表其實(shí)創(chuàng)建的過(guò)程唯一不同的是,非循環(huán)鏈表的尾結(jié)點(diǎn)指向空(NULL),而循環(huán)鏈表的尾指針指向的是鏈表的開頭。

通過(guò)將單鏈表的尾結(jié)點(diǎn)指向頭結(jié)點(diǎn)的鏈表稱之為循環(huán)單鏈表(Circular linkedlist)

一個(gè)完整的循環(huán)單鏈表如圖:

循環(huán)鏈表結(jié)點(diǎn)設(shè)計(jì)(以單循環(huán)鏈表為例)

對(duì)于循環(huán)單鏈表的結(jié)點(diǎn),可以完全參照于單鏈表的結(jié)點(diǎn)設(shè)計(jì),如圖:

單向循環(huán)鏈表結(jié)點(diǎn)

data表示數(shù)據(jù);

next表示指針,它總是指向自身的下一個(gè)結(jié)點(diǎn),對(duì)于只有一個(gè)結(jié)點(diǎn)的存在,這個(gè)next指針則永遠(yuǎn)指向自身,對(duì)于一個(gè)鏈表的尾部結(jié)點(diǎn),next永遠(yuǎn)指向開頭。

其代碼如下:

typedef struct list{ int data; struct list *next;}list;//data為存儲(chǔ)的數(shù)據(jù),next指針為指向下一個(gè)結(jié)點(diǎn)

循環(huán)單鏈表初始化

先創(chuàng)建一個(gè)頭結(jié)點(diǎn)并且給其開辟內(nèi)存空間,在開辟內(nèi)存空間成功之后,將頭結(jié)點(diǎn)的next指向head自身,創(chuàng)建一個(gè)init函數(shù)來(lái)完成;

為了重復(fù)創(chuàng)建和插入,我們可以在init函數(shù)重新創(chuàng)建的結(jié)點(diǎn)next指向空,而在主函數(shù)調(diào)用創(chuàng)建之后,將head頭結(jié)點(diǎn)的next指針指向自身。

這樣的操作方式可以方便過(guò)后的創(chuàng)建單鏈表,直接利用多次調(diào)用的插入函數(shù)即可完成整體創(chuàng)建。

其代碼如下:

//初始結(jié)點(diǎn)list *initlist(){ list *head=(list*)malloc(sizeof(list)); if(head==NULL){ printf(“創(chuàng)建失敗,退出程序”); exit(0); }else{ head-》next=NULL; return head; }}

在主函數(shù)重調(diào)用可以是這樣

//////////初始化頭結(jié)點(diǎn)////////////// list *head=initlist(); head-》next=head;

循環(huán)鏈表的創(chuàng)建操作

如圖所示:

單向循環(huán)鏈表的創(chuàng)建

通過(guò)逐步的插入操作,創(chuàng)建一個(gè)新的節(jié)點(diǎn),將原有鏈表尾結(jié)點(diǎn)的next指針修改指向到新的結(jié)點(diǎn),新的結(jié)點(diǎn)的next指針再重新指向頭部結(jié)點(diǎn),然后逐步進(jìn)行這樣的插入操作,最終完成整個(gè)單項(xiàng)循環(huán)鏈表的創(chuàng)建。

其代碼如下:

//創(chuàng)建——插入數(shù)據(jù)int insert_list(list *head){ int data; //插入的數(shù)據(jù)類型 printf(“請(qǐng)輸入要插入的元素:”); scanf(“%d”,&data); list *node=initlist(); node-》data=data; //初始化一個(gè)新的結(jié)點(diǎn),準(zhǔn)備進(jìn)行鏈接 if(head!=NULL){ list *p=head; //找到最后一個(gè)數(shù)據(jù) while(p-》next!=head){ p=p-》next; } p-》next=node; node-》next=head; return 1; }else{ printf(“頭結(jié)點(diǎn)已無(wú)元素\n”); return 0; } }

循環(huán)單鏈表的插入操作

如圖,對(duì)于插入數(shù)據(jù)的操作,可以創(chuàng)建一個(gè)獨(dú)立的結(jié)點(diǎn),通過(guò)將需要插入的結(jié)點(diǎn)的上一個(gè)結(jié)點(diǎn)的next指針指向該節(jié)點(diǎn),再由需要插入的結(jié)點(diǎn)的next指針指向下一個(gè)結(jié)點(diǎn)的方式完成插入操作。

其代碼如下:

//插入元素list *insert_list(list *head,int pos,int data){ //三個(gè)參數(shù)分別是鏈表,位置,參數(shù) list *node=initlist(); //新建結(jié)點(diǎn) list *p=head; //p表示新的鏈表 list *t; t=p; node-》data=data; if(head!=NULL){ for(int i=1;i《pos;i++){ t=t-》next; //走到需要插入的位置處 } node-》next=t-》next; t-》next=node; return p; } return p;}

循環(huán)單鏈表的刪除操作

如下圖所示,循環(huán)單鏈表的刪除操作是先找到需要?jiǎng)h除的結(jié)點(diǎn),將其前一個(gè)結(jié)點(diǎn)的next指針直接指向刪除結(jié)點(diǎn)的下一個(gè)結(jié)點(diǎn)即可。

需要注意的是尾結(jié)點(diǎn),因?yàn)閯h除尾節(jié)點(diǎn)后,尾節(jié)點(diǎn)前一個(gè)結(jié)點(diǎn)就成了新的尾節(jié)點(diǎn),這個(gè)新的尾節(jié)點(diǎn)需要指向的是頭結(jié)點(diǎn)而不是空。

其代碼如下:

//刪除元素int delete_list(list *head) { if(head == NULL) { printf(“鏈表為空!\n”); return 0; } //建立臨時(shí)結(jié)點(diǎn)存儲(chǔ)頭結(jié)點(diǎn)信息(目的為了找到退出點(diǎn)) //如果不這么建立的化需要使用一個(gè)數(shù)據(jù)進(jìn)行計(jì)數(shù)標(biāo)記,計(jì)數(shù)達(dá)到鏈表長(zhǎng)度時(shí)自動(dòng)退出 //循環(huán)鏈表當(dāng)找到最后一個(gè)元素的時(shí)候會(huì)自動(dòng)指向頭元素,這是我們不想讓他發(fā)生的 list *temp = head; list *ptr = head-》next; int del; printf(“請(qǐng)輸入你要?jiǎng)h除的元素:”); scanf(“%d”,&del); while(ptr != head) { if(ptr-》data == del) { if(ptr-》next == head) { temp-》next = head; free(ptr); return 1; } temp-》next = ptr-》next; //核心刪除操作代碼 free(ptr); //printf(“元素刪除成功!\n”); return 1; } temp = temp-》next; ptr = ptr-》next; } printf(“沒有找到要?jiǎng)h除的元素\n”); return 0;}

循環(huán)單鏈表的遍歷

與普通的單鏈表和雙向鏈表的遍歷不同,循環(huán)鏈表需要進(jìn)行結(jié)點(diǎn)的特殊判斷。

先找到尾節(jié)點(diǎn)的位置,由于尾節(jié)點(diǎn)的next指針是指向頭結(jié)點(diǎn)的,所以不能使用鏈表本身是否為空(NULL)的方法進(jìn)行簡(jiǎn)單的循環(huán)判斷,我們需要通過(guò)判斷結(jié)點(diǎn)的next指針是否等于頭結(jié)點(diǎn)的方式進(jìn)行是否完成循環(huán)的判斷。

此外還有一種計(jì)數(shù)的方法,即建立一個(gè)計(jì)數(shù)器count=0,每一次next指針指向下一個(gè)結(jié)點(diǎn)時(shí)計(jì)數(shù)器+1,當(dāng)count數(shù)字與鏈表的節(jié)點(diǎn)數(shù)相同的時(shí)候即完成循環(huán);

但是這樣做會(huì)有一個(gè)問題,就是獲取到鏈表的節(jié)點(diǎn)數(shù)同時(shí),也需要完成一次遍歷才可以達(dá)成目標(biāo)。

其代碼如下:

//遍歷元素int display(list *head) { if(head != NULL) { list *p = head; //遍歷頭節(jié)點(diǎn)到,最后一個(gè)數(shù)據(jù) while(p-》next != head ) { printf(“%d ”,p-》next-》data); p = p-》next; } printf(“\n”); //換行 //把最后一個(gè)節(jié)點(diǎn)賦新的節(jié)點(diǎn)過(guò)去 return 1; } else { printf(“頭結(jié)點(diǎn)為空!\n”); return 0; }}

進(jìn)階概念——雙向循環(huán)鏈表

循環(huán)單鏈表也有一個(gè)孿生兄弟——雙向循環(huán)鏈表,其設(shè)計(jì)思路與單鏈表和雙向鏈表的設(shè)計(jì)思路一樣,就是在原有的雙向鏈表的基礎(chǔ)上,將尾部結(jié)點(diǎn)和頭部結(jié)點(diǎn)進(jìn)行互相連接。交給大家了。

關(guān)于鏈表的總結(jié)

在順序表中做插入刪除操作時(shí),平均移動(dòng)大約表中一半的元素,因此對(duì)n較大的順序表效率低。并且需要預(yù)先分配足夠大的存儲(chǔ)空間,而鏈表恰恰是其中運(yùn)用的精華。

基于存儲(chǔ),運(yùn)算,環(huán)境這幾方面考慮,可以讓我們更好的在項(xiàng)目中使用鏈表。

今天鏈表基礎(chǔ)就講到這里,下一期,我們?cè)僖姡?/p>

聲明:本文內(nèi)容及配圖由入駐作者撰寫或者入駐合作網(wǎng)站授權(quán)轉(zhuǎn)載。文章觀點(diǎn)僅代表作者本人,不代表電子發(fā)燒友網(wǎng)立場(chǎng)。文章及其配圖僅供工程師學(xué)習(xí)之用,如有內(nèi)容侵權(quán)或者其他違規(guī)問題,請(qǐng)聯(lián)系本站處理。 舉報(bào)投訴
  • 元素
    +關(guān)注

    關(guān)注

    0

    文章

    47

    瀏覽量

    8560
  • 數(shù)組
    +關(guān)注

    關(guān)注

    1

    文章

    419

    瀏覽量

    26280
  • 鏈表
    +關(guān)注

    關(guān)注

    0

    文章

    80

    瀏覽量

    10752
收藏 0人收藏

    評(píng)論

    相關(guān)推薦

    搞懂波峰焊工藝及缺陷預(yù)防

    波峰焊接是種復(fù)雜的工藝過(guò)程,涉及到金屬表面、熔融焊料、空氣等多種因素。焊接質(zhì)量受到多種因素的影響,如印制板、元器件、焊料、焊劑、焊接溫度、時(shí)間等工藝參數(shù)以及設(shè)備條件等。 因此,要獲得個(gè)優(yōu)良的焊接
    的頭像 發(fā)表于 04-09 14:46 ?1006次閱讀
    <b class='flag-5'>一</b><b class='flag-5'>文</b><b class='flag-5'>搞懂</b>波峰焊工藝及缺陷預(yù)防

    搞懂波峰焊工藝及缺陷預(yù)防

    波峰焊接是種復(fù)雜的工藝過(guò)程,涉及到金屬表面、熔融焊料、空氣等多種因素。焊接質(zhì)量受到多種因素的影響,如印制板、元器件、焊料、焊劑、焊接溫度、時(shí)間等工藝參數(shù)以及設(shè)備條件等。 因此,要獲得個(gè)優(yōu)良的焊接
    發(fā)表于 04-09 14:44

    搞懂POL全光網(wǎng)絡(luò)

    在數(shù)字經(jīng)濟(jì)的浪潮中,企業(yè)積極擁抱人工智能、云計(jì)算、物聯(lián)網(wǎng)(IoT)等前沿科技,促使業(yè)務(wù)云端化、連接多元化以及信息接入普及化,加速推動(dòng)企業(yè)數(shù)智化進(jìn)程。伴隨轉(zhuǎn)型的持續(xù)深入,企業(yè)園區(qū)網(wǎng)絡(luò)遭遇前所未有的挑戰(zhàn):帶寬需求激增,流量模式由東西向?yàn)橹鬓D(zhuǎn)向南北向?yàn)橹鳎髨@區(qū)網(wǎng)絡(luò)介質(zhì)與架構(gòu)革新,以匹配數(shù)智化發(fā)展的新需求。
    的頭像 發(fā)表于 02-27 13:51 ?1156次閱讀
    <b class='flag-5'>一</b><b class='flag-5'>文</b><b class='flag-5'>搞懂</b>POL全光網(wǎng)絡(luò)

    搞懂先進(jìn)存儲(chǔ)技術(shù)

    高性能計(jì)算(High Performance Computing, HPC)以超高的計(jì)算性能廣泛應(yīng)用于國(guó)民經(jīng)濟(jì)的各個(gè)領(lǐng)域,不僅用于氣候模擬、石油勘探等傳統(tǒng)產(chǎn)業(yè),在生命科學(xué)、大數(shù)據(jù)等領(lǐng)域成為研究和解決挑戰(zhàn)性問題的重要工具。高性能計(jì)算需要配備超強(qiáng)儲(chǔ)存能力,本文對(duì)先進(jìn)的存儲(chǔ)技術(shù)做了簡(jiǎn)單介紹。
    的頭像 發(fā)表于 02-26 17:42 ?697次閱讀
    <b class='flag-5'>一</b><b class='flag-5'>文</b><b class='flag-5'>搞懂</b>先進(jìn)存儲(chǔ)技術(shù)

    解析工業(yè)互聯(lián)網(wǎng)

    電子發(fā)燒友網(wǎng)站提供《解析工業(yè)互聯(lián)網(wǎng).pptx》資料免費(fèi)下載
    發(fā)表于 02-20 16:42 ?1次下載

    搞懂汽車電控IGBT模塊

    想要從零了解汽車電控IGBT模塊看這篇就夠了!根據(jù)乘聯(lián)會(huì)數(shù)據(jù),2022年6月新能源車國(guó)內(nèi)零售滲透率27.4%,并且2022年6月29日歐盟對(duì)外宣布,歐盟27個(gè)成員國(guó)已經(jīng)初步達(dá)成致,歐洲將于
    的頭像 發(fā)表于 01-07 17:08 ?1142次閱讀
    <b class='flag-5'>一</b><b class='flag-5'>文</b><b class='flag-5'>搞懂</b>汽車電控IGBT模塊

    搞懂軟核的固化、啟動(dòng)和MultiBoot實(shí)現(xiàn)

    這也是《FPGA實(shí)現(xiàn)串口升級(jí)及MultiBoot》系列中的篇文章,作為個(gè)專題單獨(dú)出來(lái)說(shuō)明。 本篇文章分為三個(gè)主題:固化、啟動(dòng)和MultiBoot實(shí)現(xiàn)。 固化分為SPI和BPI FLASH兩種情況
    的頭像 發(fā)表于 12-07 11:23 ?1553次閱讀
    <b class='flag-5'>一</b><b class='flag-5'>文</b><b class='flag-5'>搞懂</b>軟核的固化、啟動(dòng)和MultiBoot實(shí)現(xiàn)

    解讀SPI

    讓我們回顧下,我們學(xué)習(xí)了串口通訊(優(yōu)點(diǎn)是全雙工,缺點(diǎn)是只能點(diǎn)對(duì)點(diǎn)通訊) 另外還學(xué)習(xí)了IIC通訊(優(yōu)點(diǎn)是主多從通訊,缺點(diǎn)是半雙工) 技巧:個(gè)總線是半雙工還是全雙工就看
    的頭像 發(fā)表于 11-19 11:37 ?767次閱讀
    <b class='flag-5'>一</b><b class='flag-5'>文</b>解讀SPI

    搞懂Linux進(jìn)程的睡眠和喚醒

    、常見的進(jìn)程狀態(tài)與理解 在操作系統(tǒng)內(nèi)部,有專門用來(lái)管理進(jìn)程的結(jié)構(gòu)體,叫做struct task_struct,也稱作進(jìn)程控制塊(PCB),主要包含描述進(jìn)程的相關(guān)信息,如進(jìn)程用戶、進(jìn)程狀態(tài)、進(jìn)程
    發(fā)表于 11-04 15:15

    小米su7核心零部件供應(yīng)商清單覽,雷布斯還虧錢嗎?

    提高能力應(yīng)該從哪些方面入手硬件工程師業(yè)余時(shí)間變現(xiàn),應(yīng)該從何處入手?硬件工程師就業(yè)前景和未來(lái)發(fā)展方向超值干貨|硬件工程師面試快問快答硬件工程師必須要學(xué)會(huì)的十種電路分析方法《搞懂》系列文章
    的頭像 發(fā)表于 11-01 11:18 ?4942次閱讀

    搞懂用ZPC輕松拿捏數(shù)據(jù)上云

    ZPC是ZLG全新研發(fā)的顯控體機(jī)。開源AWTK,版權(quán)無(wú)憂!AWFlow流圖編程,開發(fā)很簡(jiǎn)單!多種通信協(xié)議,設(shè)備互聯(lián)超便捷!更有ZWS,數(shù)據(jù)上云很輕松!本文將介紹ZPC輕松拿捏數(shù)據(jù)上云。ZPC簡(jiǎn)介
    的頭像 發(fā)表于 09-05 08:05 ?665次閱讀
    <b class='flag-5'>一</b><b class='flag-5'>文</b><b class='flag-5'>搞懂</b>用ZPC輕松拿捏數(shù)據(jù)上云

    徹底搞懂數(shù)字孿生、仿真與虛擬調(diào)試

    在項(xiàng)目實(shí)施之前對(duì)設(shè)備和系統(tǒng)進(jìn)行測(cè)試和驗(yàn)證的能力對(duì)于任何制造商來(lái)說(shuō)都 至關(guān)重要 。然而,在這項(xiàng)技術(shù)的早期階段,并非每個(gè)制造商都為數(shù)字化轉(zhuǎn)型做好了準(zhǔn)備。? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?
    的頭像 發(fā)表于 09-03 10:22 ?752次閱讀

    全面!搞懂黑體輻射源原理及選型

    所有物體都會(huì)在定波長(zhǎng)范圍內(nèi)發(fā)射電磁輻射。入射到物體上的輻射會(huì)被部分吸收和部分反射。在熱力學(xué)平衡下,物體吸收輻射的速率與其發(fā)射輻射的速率相同。因此,良好的輻射吸收器(任何吸收輻射的物體)也是很好
    的頭像 發(fā)表于 08-30 12:50 ?1372次閱讀
    全面!<b class='flag-5'>一</b><b class='flag-5'>文</b><b class='flag-5'>搞懂</b>黑體輻射源原理及選型

    ESP32-S3的LCD接口可以用DMA鏈表來(lái)觸發(fā)發(fā)送數(shù)據(jù)嗎?

    因?yàn)槭怯脕?lái)驅(qū)動(dòng)LED顯示屏,用原來(lái)的I2S那樣并行,通過(guò)鏈接自己組織數(shù)據(jù)列表,還是比較方便的,現(xiàn)在S3的I2S好像已經(jīng)不能并行發(fā)數(shù)據(jù)了,只能用LCD的接口了,所以想知道LCD接口的DMA能不能用鏈表來(lái)組織數(shù)據(jù)。
    發(fā)表于 06-17 07:25

    搞懂DDR內(nèi)存原理

    內(nèi)存(DRAM-RandomAccessMemory)作為當(dāng)代數(shù)字系統(tǒng)最主要的核心部件之,從各種終端設(shè)備到核心層數(shù)據(jù)處理和存儲(chǔ)設(shè)備,從各種消費(fèi)類電子設(shè)備到社會(huì)各行業(yè)專用設(shè)備,是各種級(jí)別的CPU進(jìn)行
    的頭像 發(fā)表于 05-09 17:09 ?4297次閱讀
    <b class='flag-5'>一</b><b class='flag-5'>文</b><b class='flag-5'>搞懂</b>DDR內(nèi)存原理
    主站蜘蛛池模板: 久久全国免费久久青青小草 | 亚洲人成网站在线 | 国产亚洲精品自在久久77 | 欧美式free群乱 | 依人成人| 色老二精品视频在线观看 | 国产福利不卡一区二区三区 | 天天射日日射 | 免费爱爱网 | 五月情网 | 日韩精品亚洲一级在线观看 | 日本经典在线三级视频 | 九九热精品在线视频 | 黄色毛片播放 | 日本成人资源 | 午夜伦理片在线观看 | 天天色天天碰 | 亚洲涩综合 | 日韩精品你懂的在线播放 | 中国女人a毛片免费全部播放 | 午夜欧美精品 | 午夜老司机永久免费看片 | 秋霞麻豆| 在线亚洲日产一区二区 | 手机看片日韩国产 | 日本卡一卡2卡3卡4精品卡无人区 | 精品一区二区影院在线 | 中国一级做a爰片久久毛片 中韩日欧美电影免费看 | 456主播喷水在线观看 | 全国男人的天堂天堂网 | 亚洲国产婷婷香蕉久久久久久 | 中日韩黄色大片 | 欧美一级欧美三级在线 | 久久久五月| 51精品国产| 一日本道加勒比高清一二三 | 国产一级特黄生活片 | ak福利午夜在线观看 | 一区| 毛片新网址 | 中年艳妇乱小玩 |

    電子發(fā)燒友

    中國(guó)電子工程師最喜歡的網(wǎng)站

    • 2931785位工程師會(huì)員交流學(xué)習(xí)
    • 獲取您個(gè)性化的科技前沿技術(shù)信息
    • 參加活動(dòng)獲取豐厚的禮品