RM新时代网站-首页

0
  • 聊天消息
  • 系統(tǒng)消息
  • 評(píng)論與回復(fù)
登錄后你可以
  • 下載海量資料
  • 學(xué)習(xí)在線課程
  • 觀看技術(shù)視頻
  • 寫文章/發(fā)帖/加入社區(qū)
會(huì)員中心
創(chuàng)作中心

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

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

雙向循環(huán)鏈表函數(shù)是什么?如何去實(shí)現(xiàn)它?

Android編程精選 ? 來源:編程學(xué)習(xí)總站 ? 作者:寫代碼的牛頓 ? 2021-06-17 12:50 ? 次閱讀

1、雙向循環(huán)鏈表結(jié)點(diǎn)定義和函數(shù)聲明

雙向循環(huán)鏈表結(jié)點(diǎn)內(nèi)部有2個(gè)指針prev和next分別指向前后的結(jié)點(diǎn),結(jié)點(diǎn)定義代碼如下:

typedefstructdlist{ intdata; structdlist*next; structdlist*prev; }dlist_t;

現(xiàn)在我們聲明一些雙向循環(huán)鏈表操作函數(shù),代碼如下:

externdlist_t *new_dlist_node(intdata); //新建一個(gè)結(jié)點(diǎn) externdlist_t *dlist_add(dlist_t*list, intdata); //插入一個(gè)結(jié)點(diǎn) externdlist_t *dlist_delete(dlist_t*list, intindex); //刪除索引對(duì)應(yīng)的結(jié)點(diǎn)(索引從0開始) externdlist_t *dlist_index_of(dlist_t*list, intindex); //查找索引對(duì)應(yīng)的結(jié)點(diǎn) externvoiddlist_destroy(dlist_t*list); //銷毀雙向循環(huán)鏈表 externvoiddlist_print(dlist_t*list); //打印鏈表數(shù)據(jù)

可以看到很多函數(shù)都會(huì)返回一個(gè)dlist_t類型的指針,其實(shí)這是頭結(jié)點(diǎn)。很多時(shí)候?yàn)榱藭鴮懛奖阄覀儠?huì)采用typedef定義自己的數(shù)據(jù)類型,結(jié)點(diǎn)定義里為什么next和prev指針可以那樣寫,參考我上一篇文章,后面會(huì)大量這樣使用。

2、雙向循環(huán)鏈表函數(shù)實(shí)現(xiàn)

為了更方便釋放一個(gè)結(jié)點(diǎn)內(nèi)存,我們定義了一個(gè)文件作用域靜態(tài)函數(shù)free_dlist_node。

voidfree_dlist_node(dlist_t*node){ if(node == NULL){ return; } node->next = NULL; node->prev = NULL; free(node); node = NULL; }

該函數(shù)只負(fù)責(zé)釋放內(nèi)存的操作。

新建鏈表結(jié)點(diǎn)

dlist_t*new_dlist_node(intdata){ dlist_t*node = (dlist_t*)malloc(sizeof(dlist_t)); if(node == NULL){ returnNULL; } node->data = data; node->next = node; node->prev = node; returnnode; }

這里我們主要注意一點(diǎn)就是新建立的結(jié)點(diǎn)next和prev指針會(huì)初始化為指向自身,事實(shí)上雙向循環(huán)鏈表頭結(jié)點(diǎn)必須這樣初始化才能更好的利用雙向循環(huán)鏈表特性執(zhí)行插入、刪除和查詢等操作。

插入結(jié)點(diǎn)

dlist_t *dlist_add(dlist_t *list, int data){ if(list== NULL){ returnNULL; } //新建一個(gè)結(jié)點(diǎn) dlist_t *node = new_dlist_node(data); if(node == NULL){ returnlist; } //將結(jié)點(diǎn)插入雙向循環(huán)鏈表 list->prev->next = node; //最后的結(jié)點(diǎn)next指針指向node node->next = list; //node的next指針指向頭結(jié)點(diǎn) node->prev = list->prev; //node的prev指針指向原尾結(jié)點(diǎn) list->prev = node; //頭結(jié)點(diǎn)的prev指針指向新尾結(jié)點(diǎn) returnlist; }

這里list是傳入的頭結(jié)點(diǎn),我們采用尾插法插入一個(gè)結(jié)點(diǎn),最后返回頭結(jié)點(diǎn)。這里需要注意:每次插入結(jié)點(diǎn)都要更新頭結(jié)點(diǎn)的prev指針。

刪除指定位置的結(jié)點(diǎn)

dlist_t *dlist_delete(dlist_t *list, int index){ if(list== NULL|| index < 0){ ????????return?list; ????} ????dlist_t *head = list; ????int list_index = 0; ????//刪除鏈表頭結(jié)點(diǎn) ????if(index == 0){ ????????//鏈表只有一個(gè)結(jié)點(diǎn) ????????if(head == list->next){ free_dlist_node(list); list= NULL; returnNULL; }else{ //鏈表有大于1個(gè)結(jié)點(diǎn) head = head->next; //頭結(jié)點(diǎn)往后移一個(gè) head->prev = list->prev; //頭結(jié)點(diǎn)的prev指向尾部結(jié)點(diǎn) list->prev->next = head; //尾部結(jié)點(diǎn)的next指針指向頭結(jié)點(diǎn) free_dlist_node(list); //釋放結(jié)點(diǎn)內(nèi)存 returnhead; } } list= list->next; list_index++; //查詢目標(biāo)結(jié)點(diǎn),通過檢查當(dāng)前結(jié)點(diǎn)是否是頭結(jié)點(diǎn)判斷是否已經(jīng)把雙線循環(huán)鏈表遍歷了一遍 while(list_index < index && head != list){ ????????list?= list->next; list_index++; } //沒有找到即將刪除的結(jié)點(diǎn) if(head == list){ returnhead; } //找到即將刪除的結(jié)點(diǎn) else{ list->prev->next = list->next; //目標(biāo)結(jié)點(diǎn)的上一個(gè)結(jié)點(diǎn)的next指針指向目標(biāo)結(jié)點(diǎn)的下一個(gè)結(jié)點(diǎn) list->next->prev = list->prev; //目標(biāo)結(jié)點(diǎn)的下一個(gè)結(jié)點(diǎn)的prev指針指向目標(biāo)結(jié)點(diǎn)的上一個(gè)結(jié)點(diǎn) free_dlist_node(list); //釋放結(jié)點(diǎn)內(nèi)存 returnhead; //返回頭結(jié)點(diǎn) } }

刪除結(jié)點(diǎn)一定要注意:

判斷被刪除的結(jié)點(diǎn)是否是頭結(jié)點(diǎn)

指定的位置是否超出了鏈表的長度。

查找指定位置的結(jié)點(diǎn)

dlist_t*dlist_index_of(dlist_t*list, intindex){ if(list== NULL|| index < 0){ ????????return?NULL; ????} ????//如果想要獲取頭結(jié)點(diǎn),則直接返回頭結(jié)點(diǎn) ????if(index == 0){ ????????return?list; ????} ????dlist_t?*head = list; ????list?= list->next; intlist_index = 1; //遍歷鏈表查找指定的索引,通過檢查當(dāng)前結(jié)點(diǎn)是否等于頭結(jié)點(diǎn)判斷是否已遍歷完畢 while(list_index < index && list?!= head){ ????????list_index++; ????????list?= list->next; } //沒有找到索引對(duì)應(yīng)的結(jié)點(diǎn) if(list== head){ returnNULL; } //找到了索引對(duì)應(yīng)的結(jié)點(diǎn) returnlist; }

查找指定位置結(jié)點(diǎn)要注意幾個(gè)地方:

是否是頭結(jié)點(diǎn)

是否超出了鏈表長度

銷毀鏈表

void dlist_destroy(dlist_t *list){ if(list== NULL){ return; } //如果只有一個(gè)結(jié)點(diǎn) if(list->next == list){ free_dlist_node(list); return; } dlist_t *temp = list; list= list->next; while(list!= temp){ list= list->next; //遍歷下一個(gè)結(jié)點(diǎn) temp->prev->next = list; list->prev = temp->prev; temp->next = NULL; temp->prev = NULL; free(temp); temp = list; } free_dlist_node(list); }

打印鏈表數(shù)據(jù)

voiddlist_print(dlist_t*list){ if(list== NULL){ return; } dlist_t*head = list; printf("%d, ", list->data); list= list->next; while(list!= head){ printf("%d, ", list->data); list= list->next; } printf(" "); }

最后我們寫個(gè)小程序驗(yàn)證一下雙向循環(huán)鏈表函數(shù)實(shí)現(xiàn)是否正確。

#include #include"dlist.h" intmain(){ dlist_t*list= new_dlist_node(2); inti = 0; for(i = 0; i < 7; i++){ ????????list?= dlist_add(list, 3?+ i); ????} ????printf("打印未處理過的完整鏈表 "); ????dlist_print(list); ????list?= dlist_delete(list, 0); //刪除第一個(gè)結(jié)點(diǎn) ????list?= dlist_delete(list, 3); //刪除第四個(gè)結(jié)點(diǎn) ????printf("打印刪除2個(gè)結(jié)點(diǎn)后的鏈表 "); ????dlist_print(list); ????dlist_t?*node = dlist_index_of(list, 2); ????printf("第3個(gè)結(jié)點(diǎn)是:%d ", node->data); printf("銷毀鏈表 "); dlist_destroy(list); list= NULL; return0; }

編譯運(yùn)行輸出:

打印未處理過的完整鏈表 2, 3, 4, 5, 6, 7, 8, 9, 打印刪除2個(gè)結(jié)點(diǎn)后的鏈表 3, 4, 5, 7, 8, 9, 第3個(gè)結(jié)點(diǎn)是:5 銷毀鏈表

驗(yàn)證完全正確。

責(zé)任編輯:lq6

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

    關(guān)注

    3

    文章

    4327

    瀏覽量

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

    關(guān)注

    0

    文章

    80

    瀏覽量

    10558

原文標(biāo)題:數(shù)據(jù)結(jié)構(gòu)與算法篇-雙向循環(huán)鏈表

文章出處:【微信號(hào):AndroidPush,微信公眾號(hào):Android編程精選】歡迎添加關(guān)注!文章轉(zhuǎn)載請注明出處。

收藏 人收藏

    評(píng)論

    相關(guān)推薦

    stdio.h實(shí)現(xiàn)了printf函數(shù)?

    我們平時(shí)包含的 stdio.h 頭文件,里面是不是實(shí)現(xiàn)了 printf 函數(shù)? 為什么會(huì)有這個(gè)疑問?因?yàn)槊看问褂?printf,就得包含 stdio.h ,這就導(dǎo)致很多同學(xué)誤以為,stdio.h
    的頭像 發(fā)表于 12-18 10:28 ?80次閱讀

    利用位反轉(zhuǎn)尋址實(shí)現(xiàn)循環(huán)緩沖器

    電子發(fā)燒友網(wǎng)站提供《利用位反轉(zhuǎn)尋址實(shí)現(xiàn)循環(huán)緩沖器.pdf》資料免費(fèi)下載
    發(fā)表于 10-28 10:01 ?0次下載
    利用位反轉(zhuǎn)尋址<b class='flag-5'>實(shí)現(xiàn)</b><b class='flag-5'>循環(huán)</b>緩沖器

    雙向晶閘管交流調(diào)壓的工作原理

    雙向晶閘管(Bidirectional Thyristor,簡稱Triac)交流調(diào)壓技術(shù)是一種重要的電力電子技術(shù),利用雙向晶閘管的特性來實(shí)現(xiàn)對(duì)交流電壓的精確控制。
    的頭像 發(fā)表于 10-18 17:51 ?1212次閱讀

    什么是雙向散射分布函數(shù)?新思科技BSDF測量解決方案

    質(zhì)地不同,在表面產(chǎn)生了優(yōu)化和不同效果。這些現(xiàn)象背后都可以使用一個(gè)科學(xué)概念──雙向散射分布函數(shù)(BSDF)來進(jìn)行解釋和描述。通過測量散射數(shù)據(jù),我們可以更深入地了解材料如何影響光線的散射,并進(jìn)一步優(yōu)化產(chǎn)品設(shè)計(jì)以提升視覺體驗(yàn)。
    的頭像 發(fā)表于 08-12 09:56 ?560次閱讀
    什么是<b class='flag-5'>雙向</b>散射分布<b class='flag-5'>函數(shù)</b>?新思科技BSDF測量解決方案

    TS3DV621雙向復(fù)用器/復(fù)用器數(shù)據(jù)表

    電子發(fā)燒友網(wǎng)站提供《TS3DV621雙向復(fù)用器/復(fù)用器數(shù)據(jù)表.pdf》資料免費(fèi)下載
    發(fā)表于 07-10 09:14 ?0次下載
    TS3DV621<b class='flag-5'>雙向</b>復(fù)用器/<b class='flag-5'>去</b>復(fù)用器數(shù)據(jù)表

    DS64BR401帶均衡和加重功能的四路雙向中繼器數(shù)據(jù)表

    電子發(fā)燒友網(wǎng)站提供《DS64BR401帶均衡和加重功能的四路雙向中繼器數(shù)據(jù)表.pdf》資料免費(fèi)下載
    發(fā)表于 07-05 09:37 ?0次下載
    DS64BR401帶均衡和<b class='flag-5'>去</b>加重功能的四路<b class='flag-5'>雙向</b>中繼器數(shù)據(jù)表

    OpenHarmony語言基礎(chǔ)類庫【@ohos.util.LinkedList (線性容器LinkedList)】

    LinkedList底層通過雙向鏈表實(shí)現(xiàn),雙向鏈表的每個(gè)節(jié)點(diǎn)都包含對(duì)前一個(gè)元素和后一個(gè)元素的引用。當(dāng)需要查詢元素時(shí),可以從頭遍歷,也可以從尾
    的頭像 發(fā)表于 05-11 16:16 ?529次閱讀
    OpenHarmony語言基礎(chǔ)類庫【@ohos.util.LinkedList (線性容器LinkedList)】

    雙向儲(chǔ)能變流器的工作原理

    雙向儲(chǔ)能變流器(PCS),又稱雙向儲(chǔ)能逆變器,是儲(chǔ)能系統(tǒng)與電網(wǎng)之間實(shí)現(xiàn)電能雙向流動(dòng)的核心部件。的主要功能包括控制電池的充電和放電過程,并進(jìn)
    的頭像 發(fā)表于 05-06 17:30 ?1604次閱讀

    電流監(jiān)控如何實(shí)現(xiàn)高效雙向電流檢測

    為避免上述情況發(fā)生,設(shè)計(jì)人員可以采用集成、高速、精確的雙向 CSA。設(shè)計(jì)人員可以選擇帶有內(nèi)部低電感分流電阻的集成雙向 CSA 構(gòu)成最緊湊的解決方案,或者選擇使用外部分流器的 CSA 實(shí)現(xiàn)更靈活的設(shè)計(jì)和布局。
    發(fā)表于 04-11 09:14 ?399次閱讀
    電流監(jiān)控如何<b class='flag-5'>實(shí)現(xiàn)</b>高效<b class='flag-5'>雙向</b>電流檢測

    關(guān)于stm32u575芯片作為usb device和PC實(shí)現(xiàn)雙向通信的疑問

    平臺(tái):STM32U575qii-EV板 模塊:USBX,ThreadX 目的:stm32u575芯片作為usb device和PC實(shí)現(xiàn)雙向通信,device為HID Custom類 現(xiàn)狀:當(dāng)前
    發(fā)表于 03-13 06:56

    回調(diào)函數(shù)(callback)是什么?回調(diào)函數(shù)實(shí)現(xiàn)方法

    回調(diào)函數(shù)是一種特殊的函數(shù)作為參數(shù)傳遞給另一個(gè)函數(shù),并在被調(diào)用函數(shù)執(zhí)行完畢后被調(diào)用?;卣{(diào)函數(shù)
    發(fā)表于 03-12 11:46 ?2903次閱讀

    數(shù)組和鏈表在內(nèi)存中的區(qū)別 數(shù)組和鏈表的優(yōu)缺點(diǎn)

    數(shù)組和鏈表在內(nèi)存中的區(qū)別 數(shù)組和鏈表的優(yōu)缺點(diǎn)? 數(shù)組和鏈表是常見的數(shù)據(jù)結(jié)構(gòu),用于組織和存儲(chǔ)數(shù)據(jù)。它們在內(nèi)存中的存儲(chǔ)方式以及優(yōu)缺點(diǎn)方面存在一些顯著的差異。本文將詳細(xì)探討這些差異以及它們的優(yōu)缺點(diǎn)。 1.
    的頭像 發(fā)表于 02-21 11:30 ?1021次閱讀

    數(shù)組和鏈表有何區(qū)別

    數(shù)組和鏈表的區(qū)別,這個(gè)問題,不僅面試中經(jīng)常遇到,考研的同學(xué)也得掌握才行。
    的頭像 發(fā)表于 02-19 15:33 ?502次閱讀
    數(shù)組和<b class='flag-5'>鏈表</b>有何區(qū)別

    循環(huán)指令loop規(guī)定循環(huán)次數(shù)

    循環(huán)指令是計(jì)算機(jī)編程中非常重要的概念,允許程序重復(fù)執(zhí)行一段代碼塊,使得程序可以更有效地處理大量數(shù)據(jù)和重復(fù)性任務(wù)。在本文中,我們將詳盡、詳實(shí)、細(xì)致地介紹循環(huán)指令的相關(guān)概念、語法和應(yīng)用場
    的頭像 發(fā)表于 02-14 16:10 ?1642次閱讀

    如何用Rust過程宏魔法簡化SQL函數(shù)呢?

    這是 RisingWave 中一個(gè) SQL 函數(shù)實(shí)現(xiàn)。只需短短幾行代碼,通過在 Rust 函數(shù)上加一行過程宏,我們就把包裝成了一個(gè) SQL 函數(shù)
    的頭像 發(fā)表于 01-23 09:43 ?944次閱讀
    如何用Rust過程宏魔法簡化SQL<b class='flag-5'>函數(shù)</b>呢?
    RM新时代网站-首页