数据结构与算法——第2章-双向链表基本操作(2.7.2)

一 概述

1
2
3
4
1.添加节点
2.删除节点
3.查找节点
4.更改节点

二 双向链表图示

三 添加节点

3.1 图示

一、添加至表头

1
2
3
4
5
将新数据元素添加到表头只需要将该元素与表头元素建立双层逻辑关系即可。
假设新元素节点为 temp,表头节点为 head,则需要做以下 2 步操作:
1.temp->next=head; head->prior=temp;
2.将 head 移至 temp,重新指向新的表头
例如,将新元素 7 添加至双链表的表头

图示

二、添加至表的中间位置

1
2
3
同单链表添加数据类似,双向链表中间位置添加数据需要经过以下 2 个步骤:
1.新节点先与其直接后继节点建立双层逻辑关系
2.新节点的直接前驱节点与之建立双层逻辑关系

图示

三、添加至表尾

1
2
3
与添加到表头是一个道理,实现过程如下:
1.找到双链表中最后一个节点
2.让新节点与最后一个节点进行双层逻辑关系

图示

3.2 代码示例

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
line * insertLine(line * head,int data,int add){
// 新建数据域为 data 的结点
line * temp=(line*)malloc(sizeof(line));
temp->data=data;
temp->prior=NULL;
temp->next=NULL;
// 插入到链表头, 要特殊考虑
if (add==1) {
temp->next=head;
head->prior=temp;
head=temp;
}else{
line * body=head;
// 找到要插入位置的前一个结点
for (int i=1; i<add-1; i++) {
body=body->next;
}
// 判断条件为真, 说明插入位置为链表尾
if (body->next==NULL) {
body->next=temp;
temp->prior=body;
}else{
body->next->prior=temp;
temp->next=body->next;
body->next=temp;
temp->prior=body;
}
}
return head;
}

四 删除节点

4.1 图示

1
双链表删除结点时,只需遍历链表找到要删除的结点,然后将该节点从表中摘除即可。

图示

五 查找节点

5.1 说明

1
2
通常,双向链表同单链表一样,都仅有一个头指针。
因此,双链表查找指定元素的实现同单链表类似,都是从表头依次遍历表中元素。

5.2 代码示例

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
// head 为原双链表, elem 表示被查找元素
int selectElem(line * head,int elem){
// 新建一个指针 t, 初始化为头指针 head
line * t=head;
int i=1;
while (t) {
if (t->data==elem) {
return i;
}
i++;
t=t->next;
}
// 程序执行至此处, 表示查找失败
return -1;
}

六 更改节点

6.1 说明

1
2
更改双链表中指定结点数据域的操作是在查找的基础上完成的。
实现过程:通过遍历找到存储有该数据元素的结点,直接更改其数据域即可

6.2 示例

1
2
3
4
5
6
7
8
9
10
// 更新函数, 其中, add 表示更改结点在双链表中的位置, newElem 为新数据的值
line *amendElem(line * p,int add,int newElem){
line * temp=p;
// 遍历到被删除结点
for (int i=1; i<add; i++) {
temp=temp->next;
}
temp->data=newElem;
return p;
}

七 增删查改

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
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
#include <stdio.h>
#include <stdlib.h>

typedef struct line{
struct line * prior;
int data;
struct line * next;
}line;

// 双链表的创建
line* initLine(line * head);
// 双链表插入元素, add 表示插入位置
line * insertLine(line * head,int data,int add);
// 双链表删除指定元素
line * delLine(line * head,int data);
// 双链表中查找指定元素
int selectElem(line * head,int elem);
// 双链表中更改指定位置节点中存储的数据, add 表示更改位置
line *amendElem(line * p,int add,int newElem);
// 输出双链表的实现函数
void display(line * head);

int main() {
line * head=NULL;
// 创建双链表
head=initLine(head);
display(head);
// 在表中第 3 的位置插入元素 7
head=insertLine(head, 7, 3);
display(head);
// 表中删除元素 2
head=delLine(head, 2);
display(head);
printf("元素 3 的位置是:%d\n",selectElem(head,3));
// 表中第 3 个节点中的数据改为存储 6
head = amendElem(head,3,6);
display(head);
return 0;
}

line* initLine(line * head){
head=(line*)malloc(sizeof(line));
head->prior=NULL;
head->next=NULL;
head->data=1;
line * list=head;
for (int i=2; i<=5; i++) {
line * body=(line*)malloc(sizeof(line));
body->prior=NULL;
body->next=NULL;
body->data=i;
list->next=body;
body->prior=list;
list=list->next;
}
return head;
}

line * insertLine(line * head,int data,int add){
// 新建数据域为 data 的结点
line * temp=(line*)malloc(sizeof(line));
temp->data=data;
temp->prior=NULL;
temp->next=NULL;
// 插入到链表头, 要特殊考虑
if (add==1) {
temp->next=head;
head->prior=temp;
head=temp;
}else{
line * body=head;
// 找到要插入位置的前一个结点
for (int i=1; i<add-1; i++) {
body=body->next;
}
// 判断条件为真, 说明插入位置为链表尾
if (body->next==NULL) {
body->next=temp;
temp->prior=body;
}else{
body->next->prior=temp;
temp->next=body->next;
body->next=temp;
temp->prior=body;
}
}
return head;
}

line * delLine(line * head,int data){
line * temp=head;
// 遍历链表
while (temp) {
// 判断当前结点中数据域和 data 是否相等, 若相等, 摘除该结点
if (temp->data==data) {
temp->prior->next=temp->next;
temp->next->prior=temp->prior;
free(temp);
return head;
}
temp=temp->next;
}
printf("链表中无该数据元素");
return head;
}

// head 为原双链表, elem 表示被查找元素
int selectElem(line * head,int elem){
// 新建一个指针 t, 初始化为头指针 head
line * t=head;
int i=1;
while (t) {
if (t->data==elem) {
return i;
}
i++;
t=t->next;
}
// 程序执行至此处, 表示查找失败
return -1;
}

// 更新函数, 其中, add 表示更改结点在双链表中的位置, newElem 为新数据的值
line *amendElem(line * p,int add,int newElem){
line * temp=p;
// 遍历到被删除结点
for (int i=1; i<add; i++) {
temp=temp->next;
}
temp->data=newElem;
return p;
}

// 输出链表的功能函数
void display(line * head){
line * temp=head;
while (temp) {
if (temp->next==NULL) {
printf("%d\n",temp->data);
}else{
printf("%d->",temp->data);
}
temp=temp->next;
}
}

/*
1->2->3->4->5
1->2->7->3->4->5
1->7->3->4->5
元素 3 的位置是:3
1->7->6->4->5
*/

八 参考

  • CSDN—双向链表基本操作