4.双向链表

4.双向链表

明廷盛 嘻嘻😁

第一章 自测&关键词回顾


第二章 手撕

只实现了带头的双向链表 【不带头的和单链表不带头一样】

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
// 带头节点
#include <assert.h>
#include <stdio.h>
#include <stdlib.h>

typedef int DataType;

typedef struct DoubleLinkListNode {
DataType data;
struct DoubleLinkListNode *prev;
struct DoubleLinkListNode *next;
} DListNode;

// 初始化
DListNode *initDoubleLinkList(void);
// 销毁
void destoryDoubleLinkList(DListNode *dlist);
// 遍历
void traverseDoubleLinkeList(DListNode* dlist);
// 指定位置插入
void insert(DListNode* dlist, DataType data, int posIndex);
// 指定位置删除
void earse(DListNode* dlist, int posIndex);

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
#include "doubleLinkList.h"

// 初始化
DListNode *initDoubleLinkList(void) {
// 创建头节点
DListNode *phead = (DListNode *)malloc(sizeof(DListNode));
phead->data = 0; // 头节点的值域维护链表长度
phead->prev = NULL;

DListNode *pmove = phead;

DataType input;
while (scanf("%d", &input) == 1 && input != -1) {
DListNode *newNode = (DListNode *)malloc(sizeof(DListNode));
newNode->data = input;
// 相互指
newNode->prev = pmove;
pmove->next = newNode;
// 移动到新创建的节点
pmove = pmove->next;
phead->data++;
}
pmove->next = NULL; // 最后一个置空
return phead;
}
// 销毁
void destoryDoubleLinkList(DListNode *dlist) {
DListNode *temp = dlist;
while (dlist) {
temp = dlist;
dlist = dlist->next;
free(temp);
}
}
// 遍历
void traverseDoubleLinkeList(DListNode *dlist) {
// 正向遍历
int flag = 1;
DListNode *pmove = dlist->next;
DListNode *backward = NULL;
while (pmove) {
if (flag) printf("%d->", pmove->data);
if (pmove->next == NULL) backward = pmove; // 记录下反向指针
pmove = pmove->next;
}
// 反向遍历 (为了确定, 链表生成没有问题)
while (backward && backward->prev) {
if (!flag) printf("%d->", backward->data);
backward = backward->prev;
}

printf("NULL Length:%d\n", dlist->data);
}
// 指定位置插入
void insert(DListNode *dlist, DataType data, int posIndex) {
assert(!(posIndex < 0 || posIndex > dlist->data) && "insert posIndex is illegal");
DListNode *newNode = (DListNode *)malloc(sizeof(DListNode));
newNode->data = data;

DListNode *pmove = dlist; // 临时变量

while (posIndex-- > 0) pmove = pmove->next;
if (pmove->next != NULL) pmove->next->prev = newNode;
newNode->next = pmove->next;
pmove->next = newNode;
newNode->prev = pmove;
dlist->data++;
}
// 指定位置删除
void earse(DListNode *dlist, int posIndex) {
assert(!(posIndex < 0 || posIndex >= dlist->data) && "earse posIndex is illegal");
DListNode *pmove = dlist;

while (posIndex-- > 0) pmove = pmove->next;
DListNode *temp = pmove->next; // 存储中间节点,得会释放
pmove->next = pmove->next->next;
if (pmove->next != NULL) pmove->next->prev = pmove;
free(temp);
dlist->data--;
}
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
154
155
156
157
#include "doubleLinkList.h"
#include <stdbool.h>
#include <string.h>
#include <time.h>

// 辅助函数:创建指定数组内容的链表
DListNode *createTestList(int *arr, int size) {
DListNode *head = (DListNode *)malloc(sizeof(DListNode));
head->data = 0;
head->prev = NULL;
head->next = NULL;

DListNode *pmove = head;
for (int i = 0; i < size; i++) {
DListNode *newNode = (DListNode *)malloc(sizeof(DListNode));
newNode->data = arr[i];
newNode->prev = pmove;
newNode->next = NULL;
pmove->next = newNode;
pmove = newNode;
head->data++;
}

return head;
}

// 辅助函数:验证链表的双向性
bool verifyDoubleLinkList(DListNode *list) {
if (!list) return false;

// 正向遍历检查prev指针
DListNode *pmove = list->next;
while (pmove) {
if (pmove->prev->next != pmove) return false;
pmove = pmove->next;
}

// 反向遍历检查next指针
pmove = list;
while (pmove->next) pmove = pmove->next;
while (pmove != list) {
if (pmove->prev->next != pmove) return false;
pmove = pmove->prev;
}

return true;
}

// 测试初始化功能
bool testInit() {
printf("测试初始化功能:\n");
bool allPassed = true;

// 测试空链表
printf(" 测试创建空链表: ");
DListNode *list = createTestList(NULL, 0);
bool result = (list->data == 0 && list->next == NULL);
printf("%s\n", result ? "通过" : "失败");
allPassed &= result;
destoryDoubleLinkList(list);

// 测试单节点链表
printf(" 测试创建单节点链表: ");
int arr[] = {1};
list = createTestList(arr, 1);
result = (list->data == 1 && verifyDoubleLinkList(list));
printf("%s\n", result ? "通过" : "失败");
allPassed &= result;
destoryDoubleLinkList(list);

return allPassed;
}

// 测试插入功能
bool testInsert() {
printf("测试插入功能:\n");
bool allPassed = true;

// 创建测试链表
int arr[] = {1, 2, 3};
DListNode *list = createTestList(arr, 3);

// 测试头部插入
printf(" 测试头部插入: ");
insert(list, 0, 0);
bool result = (list->next->data == 0 && verifyDoubleLinkList(list));
printf("%s\n", result ? "通过" : "失败");
allPassed &= result;

// 测试尾部插入
printf(" 测试尾部插入: ");
insert(list, 4, list->data);
result = (list->data == 5 && verifyDoubleLinkList(list));
printf("%s\n", result ? "通过" : "失败");
allPassed &= result;

destoryDoubleLinkList(list);
return allPassed;
}

// 测试删除功能
bool testErase() {
printf("测试删除功能:\n");
bool allPassed = true;

// 创建测试链表
int arr[] = {1, 2, 3, 4};
DListNode *list = createTestList(arr, 4);

// 测试头部删除
printf(" 测试头部删除: ");
earse(list, 0);
bool result = (list->next->data == 2 && verifyDoubleLinkList(list));
printf("%s\n", result ? "通过" : "失败");
allPassed &= result;

// 测试尾部删除
printf(" 测试尾部删除: ");
earse(list, list->data - 1);
result = (list->data == 2 && verifyDoubleLinkList(list));
printf("%s\n", result ? "通过" : "失败");
allPassed &= result;

destoryDoubleLinkList(list);
return allPassed;
}

// 运行所有测试
void runAllTests() {
printf("============== 双向链表测试 ==============\n");

bool initTestPassed = testInit();
bool insertTestPassed = testInsert();
bool eraseTestPassed = testErase();

printf("\n============== 测试结果汇总 ==============\n");
printf("初始化测试: %s\n", initTestPassed ? "通过" : "失败");
printf("插入操作测试: %s\n", insertTestPassed ? "通过" : "失败");
printf("删除操作测试: %s\n", eraseTestPassed ? "通过" : "失败");
printf("总体结果: %s\n",
(initTestPassed && insertTestPassed && eraseTestPassed) ? "全部通过" : "存在失败");
}

void test01() {
DListNode *dlist = initDoubleLinkList();
traverseDoubleLinkeList(dlist);

earse(dlist, -7);
traverseDoubleLinkeList(dlist);

destoryDoubleLinkList(dlist);
}

int main() {
runAllTests();
return 0;
}

第三章 相关应用

第四章 上手真题

第五章 比赛怎么用

  • Title: 4.双向链表
  • Author: 明廷盛
  • Created at : 2025-03-24 21:07:32
  • Updated at : 2025-03-24 21:11:00
  • Link: https://blog.20040424.xyz/2025/03/24/🏫考研/第一部分 数据结构/4.双向链表/
  • License: All Rights Reserved © 明廷盛