除了单个天才程序员外,没有人一开端就能写出让人惊叹的代码,都是从仿照开端的!不要信任你身边的人说他能很轻松的自己编写出让人惊叹的代码而不必任何的参阅资料,因为我信任在你我的身边没有这样的天才程序员,所以咱们都挑选从仿照和阅览源代码开端。就比如一个优异的作家不是一开端就能写出好的文章,他也是阅览了许多优异的文章之后才干写出优异作品的。一开端我想具体的解说双链表部分,可是我发现因为代码的原因,使得文章的篇幅过大,所以在此就挑选一些易错和场用的常识点来进行解说,假如一开端你发现阅览代码时很费劲,请不要抛弃!咱们要有意志去把它消化掉,融会贯通之后再写出咱们自己的双链表,当然我给出的仅仅只是一个参阅罢了。
在此也要特别感谢下编程浪子朱云翔教师,阅览我博客后提出的宝贵意见,依据你的主张我接下来的博客中都把代码部分放到了代码框中,使得代码看起来愈加的顺眼。
前一篇博客中咱们解说了单链表,那么接下来仍是依照咱们之前的组织解说双链表部分, 在开端解说之前,咱们先来简略的回忆下上一篇博客中的双链表,双链表是链表的一种,它的每个数据结点中都有两个指针,别离指向直接后继和直接前驱。所以,从双向链表中的恣意一个结点开端,都可以很方便地拜访它的前驱结点和后继结点。对双链表做了一个简略的回忆之后那么接下来咱们就来开端解说双链表了,在这里咱们也相同遵从一个准则,便是用简略易懂的代码和文字描述来解说,咱们要杰出代码的重点是在编程的过程中咱们的易错点。
因为双链表的运用相对于单链表操作来说要杂乱和常用些,所以在这里我选用逐步增加功用模块的办法来进行解说,从易到难,让读者了解起来愈加轻松,一起咱们在这里也运用我前面博客中说到的一些办法,学以致用嘛,学了就要在代码中尽或许的运用起来,要不然学了有什么用呢,接下来咱们先来看看一个最为简略的双链表的创立。
特此阐明:
1、假如在接下来的代码中发现一些不明白而我又没有给出提示信息的,如自己界说枚举型的数据结构DListReturn作为回来类型等,那么请你看我的前一篇博客《C言语的那些小秘密之链表(一)》。
2、因为文章在修正的时分可以对代码部分运用色彩符号,可是宣布后如同显现不出来,我企图修正,但仍是不可,所以在此阐明下,代码中被“” 和“ ”框起来的部分为有色部分。读者自己在阅览代码的时分注意下,自己比照也能找到新参加的代码。
#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("%d\t ", 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;
}
运转成果为:
0 1 2 3 4 5 6
Press any key to continue
或许有的读者以为上面得代码有点杂乱化了,其实不然,咱们仅仅是写出了咱们要解说的双链表完成中最简略的部分,其完成的功用是创立一个链表,在链表结尾增加结点,然后打印出链表中结点里寄存的数据项,对代码的整体动能有了一个大约的了解之后,现在咱们来逐个剖析代码,为接下来增加功用模块翻开思路。