C語(yǔ)言的那些小秘密之鏈表(二)
除了個(gè)別天才程序員外,沒(méi)有人一開(kāi)始就能寫(xiě)出讓人驚嘆的代碼,都是從模仿開(kāi)始的!不要相信你身邊的人說(shuō)他能很輕松的自己編寫(xiě)出讓人驚嘆的代碼而不用任何的參考資料,因?yàn)槲蚁嘈旁谀阄业纳磉厸](méi)有這樣的天才程序員,所以我們都選擇從模仿和閱讀源代碼開(kāi)始。就好比一個(gè)優(yōu)秀的作家不是一開(kāi)始就能寫(xiě)出好的文章,他也是閱讀了很多優(yōu)秀的文章之后才能寫(xiě)出優(yōu)秀作品的。一開(kāi)始我想詳細(xì)的講解雙鏈表部分,但是我發(fā)現(xiàn)由于代碼的原因,使得文章的篇幅過(guò)大,所以在此就選擇一些易錯(cuò)和場(chǎng)用的知識(shí)點(diǎn)來(lái)進(jìn)行講解,如果一開(kāi)始你發(fā)現(xiàn)閱讀代碼時(shí)很吃力,請(qǐng)不要放棄!我們要有毅力去把它消化掉,融會(huì)貫通之后再寫(xiě)出我們自己的雙鏈表,當(dāng)然我給出的僅僅只是一個(gè)參考而已。
本文引用地址:http://www.ex-cimer.com/article/272382.htm在此也要特地感謝下編程浪子朱云翔老師,閱讀我博客后提出的寶貴意見(jiàn),根據(jù)你的建議我接下來(lái)的博客中都把代碼部分放到了代碼框中,使得代碼看起來(lái)更加的悅目。
前一篇博客中我們講解了單鏈表,那么接下來(lái)還是按照我們之前的安排講解雙鏈表部分, 在開(kāi)始講解之前,我們先來(lái)簡(jiǎn)單的回顧下上一篇博客中的雙鏈表,雙鏈表是鏈表的一種,它的每個(gè)數(shù)據(jù)結(jié)點(diǎn)中都有兩個(gè)指針,分別指向直接后繼和直接前驅(qū)。所以,從雙向鏈表中的任意一個(gè)結(jié)點(diǎn)開(kāi)始,都可以很方便地訪(fǎng)問(wèn)它的前驅(qū)結(jié)點(diǎn)和后繼結(jié)點(diǎn)。對(duì)雙鏈表做了一個(gè)簡(jiǎn)單的回顧之后那么接下來(lái)我們就來(lái)開(kāi)始講解雙鏈表了,在這里我們也同樣遵循一個(gè)原則,就是用簡(jiǎn)單易懂的代碼和文字描述來(lái)講解,我們要突出代碼的重點(diǎn)是在編程的過(guò)程中我們的易錯(cuò)點(diǎn)。
因?yàn)殡p鏈表的使用相對(duì)于單鏈表操作來(lái)說(shuō)要復(fù)雜和常用些,所以在這里我采用逐漸添加功能模塊的方法來(lái)進(jìn)行講解,從易到難,讓讀者理解起來(lái)更加輕松,同時(shí)我們?cè)谶@里也使用我前面博客中提到的一些方法,學(xué)以致用嘛,學(xué)了就要在代碼中盡可能的使用起來(lái),要不然學(xué)了有什么用呢,接下來(lái)我們先來(lái)看看一個(gè)最為簡(jiǎn)單的雙鏈表的創(chuàng)建。
特此說(shuō)明:
1、如果在接下來(lái)的代碼中發(fā)現(xiàn)一些不懂而我又沒(méi)有給出提示信息的,如自己定義枚舉型的數(shù)據(jù)結(jié)構(gòu)DListReturn作為返回類(lèi)型等,那么請(qǐng)你看我的前一篇博客《C語(yǔ)言的那些小秘密之鏈表(一)》。
2、由于文章在編輯的時(shí)候可以對(duì)代碼部分使用顏色標(biāo)記,但是發(fā)表后好像顯示不出來(lái),我試圖修改,但還是不行,所以在此說(shuō)明下,代碼中被“” 和“ ”框起來(lái)的部分為有色部分。讀者自己在閱讀代碼的時(shí)候注意下,自己對(duì)比也能找到新加入的代碼。
#include <stdio.h>
#include <stdlib.h>
typedef enum _DListReturn
{
DLIST_RETURN_OK,
DLIST_RETURN_FAIL
}DListReturn;
typedef struct _DStu
{
int score;
}DStu;
typedef struct _DListNode
{
struct _DListNode* prev;
struct _DListNode* next;
DStu* data;
}DListNode;
typedef struct _DList
{
DListNode* head;
}DList;
typedef DListReturn (*DListPrintFunction)(void* data);
DListNode* dlist_node_create(void* data)
{
DListNode* node;
if((node = (DListNode*) malloc(sizeof(DListNode)))==NULL)
{
printf("分配空間失敗!");
exit(0);
}
if(node != NULL)
{
node->prev = NULL;
node->next = NULL;
node->data =(DStu*)data;
}
return node;
}
DList* dlist_head_create(void)
{
DList* thiz;
if((thiz = (DList*)malloc(sizeof(DList)))==NULL)
{
printf("分配空間失敗!");
exit(0);
}
if(thiz != NULL)
{
thiz->head = NULL;
}
return thiz;
}
DListReturn dlist_append(DList* thiz, void* data)
{
DListNode* node = NULL;
DListNode* cursor = NULL;
if((node = dlist_node_create(data)) == NULL)
{
return DLIST_RETURN_OK;
}
if(thiz->head == NULL)
{
thiz->head = node;
return DLIST_RETURN_OK;
}
cursor = thiz->head;
while(cursor != NULL && cursor->next != NULL)
{
cursor = cursor->next;
}
cursor->next = node;
node->prev = cursor;
return DLIST_RETURN_OK;
}
DListReturn dlist_print(DList* thiz, DListPrintFunction print)
{
DListNode* iter = thiz->head;
while(iter != NULL)
{
print(iter->data);
iter = iter->next;
}
printf("n");
return DLIST_RETURN_OK;
}
DListReturn print_int(void* data)
{
DStu* ss=(DStu*)data;
printf("%dt ", ss->score);
return DLIST_RETURN_OK;
}
int main(int argc, char* argv[])
{
int i = 0;
DList* dlist = dlist_head_create();
for(i = 0; i < 7; i++)
{
DStu* stu =(DStu*) malloc(sizeof(DStu));
stu->score = i;
dlist_append(dlist, (void*)stu);
}
dlist_print(dlist, print_int);
return 0;
}
運(yùn)行結(jié)果為:
0 1 2 3 4 5 6
Press any key to continue
可能有的讀者認(rèn)為上面得代碼有點(diǎn)復(fù)雜化了,其實(shí)不然,我們僅僅是寫(xiě)出了我們要講解的雙鏈表實(shí)現(xiàn)中最簡(jiǎn)單的部分,其實(shí)現(xiàn)的功能是創(chuàng)建一個(gè)鏈表,在鏈表末端添加結(jié)點(diǎn),然后打印出鏈表中結(jié)點(diǎn)里存放的數(shù)據(jù)項(xiàng),對(duì)代碼的總體動(dòng)能有了一個(gè)大概的了解之后,現(xiàn)在我們來(lái)逐一分析代碼,為接下來(lái)添加功能模塊打開(kāi)思路。
評(píng)論