数据结构-双链表

数据结构:双链表

双向链表也叫双链表,是链表的一种,它的每个数据结点中都有两个指针,分别指向直接后继和直接前驱。所以,从双向链表中的任意一个结点开始,都可以很方便地访问它的前驱结点和后继结点

双链表

双链表和单链表的区别

  • 单链表对于一个节点,有储存数据的data。和next后驱节点(指针)。也就是这个单链表想要一些遍历的操作都得通过前节点—>后节点。
  • 双链表对于一个节点,有些和单链表一样有存储数据的data,指向后方的next(指针)。它拥有单链表的所有操作和内容。但是他还有一个前驱节点front(指针)。
  • 单链表一般都有一个头结点,双向链表可以没有头结点。

本次创建的为一个没有头结点的双链表

双链表的创建

1
2
3
4
5
6
7
8
9
typedef struct dlinklist
{
/*数据域*/
int number;
/*前驱指针*/
struct dlinklist *front;
/*后驱指针*/
struct dlinklist *next;
}DLlinkList;

正因为拥有两个指针,所以双链表可以正向遍历也可以反向遍历。

双链表的初始化

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
DLlinkList* init_list(int n)
{
int i;
DLlinkList *head,*node,*end;

if(n <= 0)
{
return NULL;
}

node = (DLlinkList*)malloc(sizeof(DLlinkList));
scanf("%d",&node->number);
head = node;
end = node;
for (i = 1; i < n; i++)
{
node = (DLlinkList*)malloc(sizeof(DLlinkList));
scanf("%d",&node->number);
end->next = node;
node->front = end;
end = node;
}
head->front = NULL;
end->next = NULL;
return head;
}

相比单链表,他们的操作基本一样,双链表多了前驱指针的操作。

增加节点

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
DLlinkList * add_node(DLlinkList *list, int n)
{
DLlinkList *temp = list;
DLlinkList *in;
int i = 0;
if (temp == NULL)
{
printf("list is empty!\n");
return;
}

while (i < (n-1) && temp != NULL)
{
i++;
temp = temp->next;
}

if (temp != NULL)
{
in = (DLlinkList*)malloc(sizeof(DLlinkList));
scanf("%d",&in->number);
if (temp->front == NULL) /*头插*/
{
in->next = list;
in->front = NULL;
list = in;
}
else if (temp->next == NULL) /*尾插*/
{
temp->next = in;
in->front = temp;
in->next = NULL;
}
else /*中间插入*/
{
in->next = temp->next;
in->front = temp;
temp->next = in;
}
}
else
{
printf("The %d node is empty,list has %d node\n",n,i);
}
}

因为没有头结点,第一个节点可能会改变(头插时),所以返回值是一个节点的指针。

此函数包括了头插,尾插,和中间插入的逻辑。

删除节点

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
DLlinkList * del_node(DLlinkList *list, int n)
{
DLlinkList *temp = list;
DLlinkList *out;
int i = 0;
if (temp == NULL)
{
printf("list is empty!\n");
return;
}
if (n <= 0)
{
printf("n is error!\n");
return;
}

while (i < (n - 1) && temp != NULL)
{
i++;
temp = temp->next;
}

if (temp != NULL)
{
if (temp->front == NULL) /*删除头部*/
{
out = list;
list = list->next;
list->front = NULL;
}
else if (temp->next == NULL) /*删除尾部*/
{
out = temp;
out->front->next = NULL;
}
else /*删除中间*/
{
out = temp;
out->front->next = out->next;
out->next->front = out->front;
out = NULL;
}

free(out);
}
else
{
printf("The %d node is empty,list has %d node\n",n,i);
}
return list;
}

删除节点和增加节点一样,包含了三个逻辑:删除头,删除尾,删除中间

修改节点

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
void modify_num(LINKLIST *list,int n)
{
LINKLIST *temp = list;
int i = 0;
if (temp == NULL)
{
printf("list is empty!");
return;
}

while (i < n && temp != NULL)
{
i++;
temp = temp->next;
}

if (temp != NULL)
{
scanf("%d",&temp->number);
}
else
{
printf("the %d node is empty!\n",n);
}

修改节点比较简单,遍历修改number就可以

输出双链表

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
void printf_list(DLlinkList *list)
{
DLlinkList *temp = list;
if (temp == NULL)
{
printf("list is empty!");
return;
}

if (temp->front == NULL && temp->next == NULL) /*只有一个节点*/
{
printf("list number:%d\n",temp->number);
return;
}
else if (temp->front == NULL) /*从头部开始*/
{
while (temp != NULL)
{
printf("list number:%d\n",temp->number);
temp = temp->next;
}
}
else
{
while (temp != NULL) /*从尾部开始*/
{
printf("list number:%d\n",temp->number);
temp = temp->front;
}
}

return;
}

输出操作包含了从头部输出和从尾部输出两个逻辑


数据结构-双链表
https://carl-5535.github.io/2020/11/23/数据结构/数据结构-双链表/
作者
Carl Chen
发布于
2020年11月23日
许可协议