数据结构链表
THEDI链表
链表(Linked List):一种线性表数据结构,通过一组任意可连续或不连续的存储单元,存储同类型数据。
简而言之,链表 是线性表的链式存储实现。
链表的优缺点:
- 优点:链表无需预先分配存储空间,按需
动态申请,能够有效避免空间浪费;在插入、删除等操作上,链表通常比数组更高效,尤其是在需要频繁修改数据结构时表现突出。
- 缺点:链表除了存储数据本身外,还需额外存储指针信息,因此整体空间
开销大于数组;同时,链表不支持随机访问,查找元素时需要从头遍历,效率较低。
单向链表
介绍
单向链表:是一种基本的数据结构,它由一系列节点组成,每个节点包含数据部分和指向下一个节点的指针。在物理存储上,节点可连续也可能不连续,但逻辑上它们是顺序连接的。单向链表的操作包括创建、插入、删除、查找和销毁等。
优势:
- 动态大小、按需分配
- 头部插入/删除为 O(1)
- 不需要连续内存
劣势:
- 随机访问为 O(n)
- 额外指针开销
- 遍历删除需维护前驱
单向链表的结构如下图:链表通过指针将一组任意的存储单元串联起来。每个数据元素及其所在的存储单元构成一个「链节点」。为了将所有节点连接成链,每个链节点除了存放数据元素本身,还需要额外存储一个指向其直接后继节点的指针,称为后继指针next。

链表与结点结构体定义
1 2 3 4 5 6 7 8 9 10 11
| typedef struct ListNode { int value; struct ListNode* next; } ListNode;
typedef struct List { ListNode* head; size_t size; } List;
|
关键点:
head == NULL 表示空链表。
size 便于 O(1) 获取长度,也用于边界检查。
API设计与实现思路
按功能分组(本实现以int为元素类型,默认线程不安全)
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
| void list_init(List* list); void list_destroy(List* list); void list_clear(List* list); size_t list_size(const List* list); bool list_empty(const List* list);
bool list_push_front(List* list, int value); bool list_push_back(List* list, int value); bool list_pop_front(List* list, int* out_value); bool list_pop_back(List* list, int* out_value);
bool list_insert(List* list, size_t index, int value); bool list_remove_at(List* list, size_t index, int* out_value); size_t list_remove_value(List* list, int value, bool remove_all);
long list_find_first(const List* list, int value); void list_foreach(const List* list, void (*fn)(int value, void* user), void* user);
void list_reverse(List* list); void list_print(const List* list);
|
术语:cur 当前节点,prev 前驱节点,nxt 保存的后继节点;“重连指针”指修改 next 指向以保持链表连通。
| API |
原型 |
作用 |
核心实现思路/步骤 |
时间复杂度 |
边界/注意点 |
create_node |
static ListNode* create_node(int value) |
内部工具:创建新节点 |
malloc 分配节点;赋值 value;next 置 NULL;返回指针(失败返回 NULL) |
O(1) |
仅内部使用;检查分配失败 |
list_size |
size_t list_size(const List* list) |
获取链表元素个数 |
返回 list->size;若 list 为 NULL 返回 0 |
O(1) |
只读,不修改结构 |
list_empty |
bool list_empty(const List* list) |
判断链表是否为空 |
返回 list_size(list) == 0 |
O(1) |
list 为 NULL 视为空 |
list_init |
void list_init(List* list) |
初始化链表对象 |
将 head 置 NULL,size 置 0 |
O(1) |
传入指针不能为空;栈上对象使用前必须 init |
list_clear |
void list_clear(List* list) |
清空所有节点 |
从 head 线性遍历,逐个 free;最后 head=NULL, size=0 |
O(n) |
可多次调用;对空表安全 |
list_add_front |
bool list_add_front(List* list, int value) |
头插 |
create_node;node->next = head;head = node;size++ |
O(1) |
list==NULL 或分配失败返回 false |
list_add_back |
bool list_add_back(List* list, int value) |
尾插 |
create_node;若空表 head=node;否则从 head 遍历到尾,尾->next=node;size++ |
O(n) |
单向链表无 tail 时需要遍历 |
list_delete_front |
bool list_delete_front(List* list, int* out_value) |
头删 |
判空;保存 head 值到 out_value(可选);head=head->next;free(旧头);size– |
O(1) |
空表返回 false |
list_delete_back |
bool list_delete_back(List* list, int* out_value) |
尾删 |
判空;用 previous/current 遍历到尾;写回 out_value;若前驱为 NULL 表示单节点,head=NULL;否则 previous->next=NULL;free(尾);size– |
O(n) |
仅一个节点时要特殊处理 |
list_insert |
bool list_insert(List* list, size_t index, int value) |
指定位置插入 |
边界:index>size 返回 false;index=0 调用头插;index=size 调用尾插;否则遍历到 index-1,node->next=cur->next;cur->next=node;size++ |
O(n) |
合法范围 0..size(含 size) |
list_remove_at |
bool list_remove_at(List* list, size_t index, int* out_value) |
指定位置删除 |
越界:index>=size 返回 false;index0 调头删;index=size-1 调尾删;否则遍历到 index-1,目标=cur->next;写回 out_value;cur->next=目标->next;free(目标);size– |
O(n) |
合法范围 0..size-1 |
list_remove_value |
size_t list_remove_value(List* list, int value, bool remove_all) |
按值删除(删一个或删全部) |
先处理连续头部命中:移动 head、free、size–、计数++,若不删全则返回;再从头遍历,用 current->next 作为候选,命中则跳过并 free,计数++,若不删全则 break,否则继续 |
O(n) |
返回删除数量;空表返回 0;避免变量名使用 delete |
list_find_first |
long list_find_first(const List* list, int value) |
查找首个等于 value 的索引 |
从 head 线性扫描,命中返回索引(从 0 开始);未找到返回 -1 |
O(n) |
返回类型为 long;list==NULL 返回 -1 |
list_foreach |
void list_foreach(const List* list, void (fn)(int, void), void* user) |
遍历回调 |
逐节点调用 fn(current->value, user) |
O(n) |
fn 不能为空;回调中若修改链表需谨慎 |
list_reverse |
void list_reverse(List* list) |
原地反转 |
迭代三指针:previous=NULL, current=head;循环内保存 next=current->next;current->next=previous;previous=current;current=next;结束后 head=previous |
O(n),额外 O(1) |
对空表/单节点安全 |
list_print |
void list_print(const List* list) |
打印链表 |
以 [a, b, c] (size=n) 形式遍历输出 |
O(n) |
调试用途;list==NULL 打印空 |
单向链表源码实现
github仓库:https://github.com/keqiudi/LinkList/tree/master/single_linklist
list.h
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 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183
|
#ifndef LIST_H #define LIST_H
#include <stddef.h> #include <stdbool.h>
#ifdef __cplusplus extern "C" { #endif
typedef struct ListNode { int value; struct ListNode* next; } ListNode;
typedef struct List { ListNode* head; size_t size; } List;
void list_init(List* list);
void list_destroy(List* list);
void list_clear(List* list);
size_t list_size(const List* list);
bool list_empty(const List* list);
bool list_add_front(List* list, int value);
bool list_add_back(List* list, int value);
bool list_delete_front(List* list, int* out_value);
bool list_delete_back(List* list, int* out_value);
bool list_insert(List* list, size_t index, int value);
bool list_remove_at(List* list, size_t index, int* out_value);
size_t list_remove_value(List* list, int value, bool remove_all);
long list_find_first(const List* list, int value);
void list_foreach(const List* list, void (*fn)(int value, void* user), void* user);
void list_reverse(List* list);
void list_print(const List* list);
#ifdef __cplusplus } #endif
#endif
|
list.c
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 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342
|
#include "list.h" #include <stdio.h> #include <stdlib.h>
static ListNode* create_node(int value) { ListNode* node = (ListNode*)malloc(sizeof(ListNode)); if (node == NULL) { return NULL; } node->value = value; node->next = NULL;
return node; }
void list_init(List* list) { if (list == NULL){ return; } list->head = NULL; list->size = 0; }
void list_clear(List* list) { if (list == NULL){ return; } ListNode* current = list->head; while (current) { ListNode* next = current->next; free(current); current = next; } list->head = NULL; list->size = 0; }
bool list_add_front(List* list,int value) { if (list == NULL){ return false; }
ListNode* node = create_node(value); if (node == NULL){ return false; }
node->next = list->head; list->head = node; list->size++; return true; }
bool list_add_back(List* list,int value) { if (list == NULL){ return false; } ListNode* node = create_node(value); if (node == NULL){ return false; } if (list->head == NULL){ list->head = node; } else { ListNode* current = list->head; while (current->next) { current = current->next; } current->next = node; } list->size++; return true; }
bool list_delete_front(List* list, int* out_value) { if (list == NULL || list->head == NULL){ return false; }
ListNode* head = list->head; if (out_value != NULL) { *out_value = head->value; } list->head = head->next; free(head); list->size--; return true; }
bool list_delete_back(List* list, int* out_value) { if (list == NULL || list->head == NULL){ return false; }
ListNode* current = list->head; ListNode* previous = NULL; while (current->next) { previous = current; current = current->next; }
if (out_value != NULL){ *out_value = current->value; }
if (previous == NULL) { list->head = NULL; } else { previous->next = NULL; }
free(current); list->size--; return true;
}
bool list_insert(List* list, size_t index, int value) { if (list == NULL){ return false; }
if (index > list->size){ return false; }
if (index == 0){ return list_add_front(list,value); } if (index == list->size){ return list_add_back(list,value); }
ListNode* node = create_node(value); if (node == NULL){ return false; }
ListNode* current = list->head; for (int i=0;i<index-1;i++) { current = current->next; } node->next = current->next; current->next = node; list->size++; return true; }
bool list_remove_at(List* list,size_t index,int* out_value) { if (list == NULL || index >= list->size){ return false; }
if (index == 0){ return list_delete_front(list,out_value); } if (index == list->size-1){ return list_delete_back(list,out_value); }
ListNode* current = list->head; for (int i=0;i<index-1;i++) { current = current->next; }
ListNode* target = current->next; if (out_value != NULL) { *out_value = target->value; }
current->next = target->next; free(target); list->size--; return true; }
size_t list_remove_value(List* list, int value, bool remove_all) { if (list == NULL) { return 0; }
size_t removed_num = 0;
while (list->head && list->head->value == value) { ListNode* head = list->head; list->head = head->next; free(head); list->size--; removed_num++; if (!remove_all) { return removed_num; } }
ListNode* current = list->head; while (current && current->next) { if (current->next->value == value) { ListNode* delete = current->next; current->next = delete->next; free(delete); list->size--; removed_num++; if (!remove_all) { break; } } else { current = current->next; }
}
return removed_num; }
long list_find_first(const List* list, int value) { if (list == NULL) { return -1; }
int node_index = 0; ListNode* current = list->head;
while (current) { if (current->value == value) { return node_index; }
current = current->next; node_index++; }
return -1; }
void list_foreach(const List* list, void (*fn)(int value, void* user), void* user) { if (list == NULL || !fn) { return; } const ListNode* current = list->head; while (current) { fn(current->value, user); current = current->next; } }
void list_reverse(List* list) { if (list == NULL) { return; }
ListNode* current = list->head; ListNode* previous = NULL; while (current) { ListNode* next = current->next; current->next = previous; previous = current; current = next; } list->head = previous; }
void list_print(const List* list) { if (list ==NULL) { printf("[]\n"); return; }
const ListNode* cur = list->head; printf("["); while (cur) { printf("%d", cur->value); if (cur->next) printf(", "); cur = cur->next; } printf("] (size=%zu)\n", list->size); }
size_t list_size(const List* list) { return list ? list->size:0; }
void list_destroy(List* list) { list_clear(list); }
bool list_empty(const List* list) { return list ? (list->size == 0) : true; }
|
测试代码
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
| #include "list.h" #include <stdio.h> #include <assert.h>
static void sum_cb(int v, void* user) { int* acc = (int*)user; *acc += v; }
int main(void) { List ls; list_init(&ls);
assert(list_empty(&ls) == true); assert(list_size(&ls) == 0); int tmp; assert(list_delete_front(&ls, &tmp) == false); assert(list_delete_back(&ls, &tmp) == false); assert(list_remove_at(&ls, 0, &tmp) == false); assert(list_remove_value(&ls, 123, true) == 0);
assert(list_add_back(&ls, 1) == true); assert(list_add_back(&ls, 2) == true); assert(list_add_back(&ls, 3) == true); list_print(&ls); assert(list_size(&ls) == 3); assert(list_empty(&ls) == false);
assert(list_add_front(&ls, 0) == true); list_print(&ls); assert(list_size(&ls) == 4);
assert(list_insert(&ls, 2, 99) == true); list_print(&ls); assert(list_insert(&ls, list_size(&ls), 42) == true); list_print(&ls);
long idx = list_find_first(&ls, 99); printf("find 99 at index = %ld\n", idx); assert(idx == 2); assert(list_find_first(&ls, -7) == -1);
int val = 0; assert(list_remove_at(&ls, 2, &val) == true); assert(val == 99); list_print(&ls);
assert(list_remove_at(&ls, list_size(&ls) - 1, &val) == true); assert(val == 42); list_print(&ls);
assert(list_add_back(&ls, 2) == true); assert(list_add_back(&ls, 2) == true); list_print(&ls);
size_t removed = list_remove_value(&ls, 2, false); printf("removed one 2 count=%zu\n", removed); assert(removed == 1); list_print(&ls);
removed = list_remove_value(&ls, 2, true); printf("removed all 2 count=%zu\n", removed); assert(removed >= 1); list_print(&ls);
assert(list_delete_front(&ls, &val) == true); printf("delete_front=%d\n", val); list_print(&ls);
assert(list_delete_back(&ls, &val) == true); printf("delete_back=%d\n", val); list_print(&ls);
assert(list_add_back(&ls, 10) == true); assert(list_add_back(&ls, 20) == true); assert(list_add_back(&ls, 30) == true); list_print(&ls);
list_reverse(&ls); printf("reversed: "); list_print(&ls);
list_clear(&ls); list_reverse(&ls); assert(list_empty(&ls));
assert(list_add_back(&ls, 7) == true); list_reverse(&ls); assert(list_size(&ls) == 1); list_print(&ls);
int sum = 0; list_foreach(&ls, sum_cb, &sum); printf("sum=%d\n", sum); assert(sum == 7);
list_clear(&ls); printf("cleared: "); list_print(&ls); assert(list_empty(&ls)); list_destroy(&ls);
printf("All tests passed!\n"); return 0; }
|
输出结果:
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
| C:\Users\keqiu\myProjects\CLionProjects\C++\test\cmake-build-debug-mingw\test.exe [1, 2, 3] (size=3) [0, 1, 2, 3] (size=4) [0, 1, 99, 2, 3] (size=5) [0, 1, 99, 2, 3, 42] (size=6) find 99 at index = 2 [0, 1, 2, 3, 42] (size=5) [0, 1, 2, 3] (size=4) [0, 1, 2, 3, 2, 2] (size=6) removed one 2 count=1 [0, 1, 3, 2, 2] (size=5) removed all 2 count=2 [0, 1, 3] (size=3) delete_front=0 [1, 3] (size=2) delete_back=3 [1] (size=1) [1, 10, 20, 30] (size=4) reversed: [30, 20, 10, 1] (size=4) [7] (size=1) sum=7 cleared: [] (size=0) All tests passed!
|
双向链表
介绍
双向链表(Doubly Linked List):链表的一种,也称为双链表。每个节点包含两条指针:后继指针 next 指向直接后继节点,前驱指针 prev 指向直接前驱节点;容器常维护首尾指针 head 与 tail,支持从两端高效操作与双向遍历。
- 双向链表的特点:可以从任意节点高效地访问其前驱和后继节点,支持
双向遍历,插入和删除操作更加灵活。

链表结构体定义
双向链表与单向链表的区别就是:
1.每个结点结构体中新增一个前驱指针prev,指向上一个结点
2.在List结构体中新增一个tail尾指针,使尾插/尾删变为O(1)
1 2 3 4 5 6 7 8 9 10 11 12 13
| typedef struct ListNode { int value; struct ListNode* next; struct ListNode* prev; } ListNode;
typedef struct List { ListNode* head; ListNode* tail; size_t size; } List;
|
API设计与实现思路
双向链表的api设计与上方单向链表相同,这里具体说明双向链表哪些API与单向链表实现不同
| 与单向链表实现不同的 API |
原型 |
作用 |
核心实现思路/步骤(与单向差异) |
时间复杂度(双向 vs 单向) |
边界/注意点 |
create_node |
static ListNode* create_node(int value) |
内部工具:创建新节点 |
在单向基础上,新增初始化 prev=NULL |
O(1) / O(1) |
失败返回 NULL;仅内部使用 |
list_clear |
void list_clear(List* list) |
清空所有节点 |
同样逐个 free;额外将 tail 也置为 NULL |
O(n) / O(n) |
清空后需满足 headtailNULL |
list_add_front |
bool list_add_front(List* list, int value) |
头插 |
node->next=head;若原表非空,head->prev=node;否则 tail=node;更新 head=node |
O(1) / O(1) |
维护端点与双向指针 head->prev==NULL |
list_add_back |
bool list_add_back(List* list, int value) |
尾插 |
node->prev=tail;若原表非空,tail->next=node;否则 head=node;更新 tail=node |
O(1) / O(n) |
借助 tail 将尾插从 O(n) 降为 O(1) |
list_delete_front |
bool list_delete_front(List* list, int* out_value) |
头删 |
head=head->next;若新 head 非空则 head->prev=NULL;否则 tail=NULL;free 旧头 |
O(1) / O(1) |
删到空表需同步置空 tail |
list_delete_back |
bool list_delete_back(List* list, int* out_value) |
尾删 |
tail=tail->prev;若新 tail 非空则 tail->next=NULL;否则 head=NULL;free 旧尾 |
O(1) / O(n) |
借助 prev 将尾删从 O(n) 降为 O(1) |
list_insert |
bool list_insert(List* list, size_t index, int value) |
指定位置插入 |
越界:index>size false;index=0 头插;index=size 尾插;否则在 index 位置前插:node->next=cur;node->prev=cur->prev;cur->prev->next=node;cur->prev=node |
O(min(i,n−i)) / O(n) |
可从近端起步(head/tail)降低步数 |
list_remove_at |
bool list_remove_at(List* list, size_t index, int* out_value) |
指定位置删除 |
越界:index>=size false;index=0 头删;index=size−1 尾删;否则 target->prev->next=target->next;target->next->prev=target->prev;free(target) |
O(min(i,n−i)) / O(n) |
同时重连前驱与后继 |
list_remove_value |
size_t list_remove_value(List* list, int value, bool remove_all) |
按值删除(删一/删全) |
线性扫描,命中时同时维护两向链接:若有前驱则前驱->next=cur->next 否则 head=cur->next;若有后继则后继->prev=cur->prev 否则 tail=cur->prev;free(cur) |
O(n) / O(n) |
一次处理头/尾/中间/唯一节点四种情况 |
list_reverse |
void list_reverse(List* list) |
原地反转 |
逐节点交换 next/prev:nxt=cur->next;cur->next=cur->prev;cur->prev=nxt;cur=nxt;结束后交换 head 与 tail |
O(n)/O(n),额外 O(1) |
反转逻辑与单向“三指针法”不同 |
list_print |
void list_print(const List* list) |
打印链表 |
从 head 到 tail 遍历,常用 “a <-> b <-> c” 体现双向 |
O(n) / O(n) |
调试用途;仅显示风格差异 |
双向链表源码实现
github仓库:https://github.com/keqiudi/LinkList/tree/master/double_linklist
doublelist.h
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 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187
|
#ifndef DOUBLELIST_H #define DOUBLELIST_H
#include <stddef.h> #include <stdbool.h>
#ifdef __cplusplus extern "C" { #endif
typedef struct ListNode { int value; struct ListNode* next; struct ListNode* prev; } ListNode;
typedef struct List { ListNode* head; ListNode* tail; size_t size; } List;
void list_init(List* list);
void list_destroy(List* list);
void list_clear(List* list);
size_t list_size(const List* list);
bool list_empty(const List* list);
bool list_add_front(List* list, int value);
bool list_add_back(List* list, int value);
bool list_delete_front(List* list, int* out_value);
bool list_delete_back(List* list, int* out_value);
bool list_insert(List* list, size_t index, int value);
bool list_remove_at(List* list, size_t index, int* out_value);
size_t list_remove_value(List* list, int value, bool remove_all);
long list_find_first(const List* list, int value);
void list_foreach(const List* list, void (*fn)(int value, void* user), void* user);
void list_reverse(List* list);
void list_print(const List* list);
#ifdef __cplusplus } #endif
#endif
|
doublelist.c
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 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389
| #include "doublelist.h" #include <stdio.h> #include <stdlib.h>
static ListNode* create_node(int value) { ListNode* node = (ListNode*)malloc(sizeof(ListNode)); if (node == NULL) { return NULL; } node->value = value; node->next = NULL; node->prev = NULL; return node; }
void list_init(List* list) { if (list == NULL){ return; } list->head = NULL; list->tail = NULL; list->size = 0; }
void list_clear(List* list) { if (list == NULL){ return; } ListNode* current = list->head; while (current) { ListNode* next = current->next; free(current); current = next; } list->head = NULL; list->tail = NULL; list->size = 0; }
void list_destroy(List* list) { list_clear(list); }
size_t list_size(const List* list) { return list ? list->size:0; }
bool list_empty(const List* list) { return list ? (list->size == 0) : true; }
bool list_add_front(List* list,int value) { if (list == NULL){ return false; }
ListNode* node = create_node(value); if (node == NULL){ return false; }
node->next = list->head;
if (list->head == NULL) { list->tail = node; } else { list->head->prev = node; }
list->head = node; list->size++; return true; }
bool list_add_back(List* list,int value) { if (list == NULL){ return false; } ListNode* node = create_node(value); if (node == NULL){ return false; }
node->prev = list->tail; if (list->tail == NULL) { list->head = node; } else { list->tail->next = node; }
list->tail = node; list->size++; return true; }
bool list_delete_front(List* list, int* out_value) { if (list == NULL || list->head == NULL){ return false; }
ListNode* head = list->head; if (out_value != NULL) { *out_value = head->value; }
list->head = head->next; if (list->head == NULL) { list->tail = NULL; } else { list->head->prev = NULL; }
free(head); list->size--; return true; }
bool list_delete_back(List* list, int* out_value) { if (list == NULL || list->head == NULL){ return false; }
ListNode* tail = list->tail; if (out_value != NULL) { *out_value = tail->value; }
list->tail = tail->prev; if (list->tail == NULL) { list->head = NULL; } else { list->tail->next = NULL; }
free(tail); list->size--; return true;
}
static ListNode* list_node_at(List* list, size_t index) { if (list == NULL || index >= list->size) { return NULL; }
if (index <= list->size/2) { ListNode* current = list->head; for (size_t i = 0;i<index;i++) { current = current->next; } return current; } else { ListNode* current = list->tail; for (size_t i = list->size-1 ;i>index;i--) { current = current->prev; } return current; }
}
bool list_insert(List* list, size_t index, int value) { if (list == NULL || index > list->size){ return false; }
if (index == 0){ return list_add_front(list,value); } if (index == list->size){ return list_add_back(list,value); }
ListNode* current = list_node_at(list,index); if (current == NULL) { return false; }
ListNode* node = create_node(value); if (node == NULL){ return false; }
node->next = current; node->prev = current->prev; current->prev->next = node; current->prev = node;
list->size++; return true; }
bool list_remove_at(List* list,size_t index,int* out_value) { if (list == NULL || index >= list->size){ return false; }
if (index == 0){ return list_delete_front(list,out_value); } if (index == list->size-1){ return list_delete_back(list,out_value); }
ListNode* target = list_node_at(list,index); if (target == NULL) { return false; } if (out_value != NULL) { *out_value = target->value; }
target->prev->next = target->next; target->next->prev = target->prev; free(target); list->size--; return true; }
size_t list_remove_value(List* list, int value, bool remove_all) { if (list == NULL) { return 0; }
size_t removed_num = 0;
ListNode* current = list->head;
while (current) { if (current->value == value) { ListNode* delete = current; ListNode* delete_next = current->next;
if (delete->prev == NULL) { list->head = delete->next; } else { delete->prev->next = delete->next; }
if (delete->next == NULL) { list->tail = delete->prev; } else { delete->next->prev = delete->prev; }
free(delete); list->size--; removed_num++; if (!remove_all) { break; } current = delete_next; } else { current = current->next; } }
return removed_num; }
long list_find_first(const List* list, int value) { if (list == NULL) { return -1; }
int node_index = 0; ListNode* current = list->head;
while (current) { if (current->value == value) { return node_index; }
current = current->next; node_index++; }
return -1; }
void list_foreach(const List* list, void (*fn)(int value, void* user), void* user) { if (list == NULL || !fn) { return; } const ListNode* current = list->head; while (current) { fn(current->value, user); current = current->next; } }
void list_reverse(List* list) { if (list == NULL) { return; }
ListNode* current = list->head; while (current) { ListNode* next = current->next; current->next = current->prev; current->prev = next; current = next; }
ListNode* temp = list->head; list->head = list->tail; list->tail = temp; }
void list_print(const List* list) { if (list ==NULL) { printf("[]\n"); return; }
const ListNode* cur = list->head; printf("["); while (cur) { printf("%d", cur->value); if (cur->next) printf(", "); cur = cur->next; } printf("] (size=%zu)\n", list->size); }
|
测试代码
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
| #include "doublelist.h" #include <stdio.h> #include <assert.h>
static void sum_cb(int v, void* user) { int* acc = (int*)user; *acc += v; }
static void print_banner(const char* title) { printf("\n==== %s ====\n", title); }
int main(void) { List ls; list_init(&ls); assert(list_empty(&ls)); assert(list_size(&ls) == 0);
int out = 0;
print_banner("空表操作"); assert(!list_delete_front(&ls, &out)); assert(!list_delete_back(&ls, &out)); assert(list_remove_value(&ls, 123, true) == 0);
print_banner("首尾插入"); assert(list_add_front(&ls, 1)); assert(list_add_front(&ls, 0)); assert(list_add_back(&ls, 2)); assert(list_add_back(&ls, 3)); list_print(&ls); assert(list_size(&ls) == 4);
print_banner("按位插入"); assert(list_insert(&ls, 2, 99)); list_print(&ls); assert(list_insert(&ls, list_size(&ls), 42)); list_print(&ls);
print_banner("查找"); long idx = list_find_first(&ls, 99); printf("find 99 at index=%ld\n", idx); assert(idx == 2); assert(list_find_first(&ls, -7) == -1);
print_banner("按位删除(头/中/尾)"); assert(list_remove_at(&ls, 0, &out)); assert(out == 0); list_print(&ls);
assert(list_remove_at(&ls, 1, &out)); assert(out == 99); list_print(&ls);
assert(list_remove_at(&ls, list_size(&ls) - 1, &out)); assert(out == 42); list_print(&ls);
print_banner("按值删除(删一个/删全部)"); assert(list_add_back(&ls, 2)); assert(list_add_back(&ls, 2)); list_print(&ls);
size_t removed = list_remove_value(&ls, 2, false); printf("removed one 2 = %zu\n", removed); assert(removed == 1); list_print(&ls);
removed = list_remove_value(&ls, 2, true); printf("removed all 2 = %zu\n", removed); assert(removed >= 1); list_print(&ls);
print_banner("反转与遍历"); assert(list_add_front(&ls, -1)); assert(list_add_back(&ls, 10)); list_print(&ls);
list_reverse(&ls); printf("reversed: "); list_print(&ls);
int sum = 0; list_foreach(&ls, sum_cb, &sum); printf("sum=%d\n", sum);
print_banner("清空与复用"); list_clear(&ls); assert(list_empty(&ls)); list_print(&ls);
assert(list_add_back(&ls, 7)); assert(list_add_back(&ls, 8)); list_print(&ls); list_destroy(&ls); assert(list_size(&ls) == 0);
printf("\nAll tests passed!\n"); return 0; }
|
输出结果:
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
| C:\Users\keqiu\myProjects\CLionProjects\C\LinkList\double_linklist\build\double_linklist.exe
==== 空表操作 ====
==== 首尾插入 ==== [0, 1, 2, 3] (size=4)
==== 按位插入 ==== [0, 1, 99, 2, 3] (size=5) [0, 1, 99, 2, 3, 42] (size=6)
==== 查找 ==== find 99 at index=2
==== 按位删除(头/中/尾) ==== [1, 99, 2, 3, 42] (size=5) [1, 2, 3, 42] (size=4) [1, 2, 3] (size=3)
==== 按值删除(删一个/删全部) ==== [1, 2, 3, 2, 2] (size=5) removed one 2 = 1 [1, 3, 2, 2] (size=4) removed all 2 = 2 [1, 3] (size=2)
==== 反转与遍历 ==== [-1, 1, 3, 10] (size=4) reversed: [10, 3, 1, -1] (size=4) sum=13
==== 清空与复用 ==== [] (size=0) [7, 8] (size=2)
All tests passed!
进程已结束,退出代码为 0
|
循环单向链表
介绍
循环链表(Circular Linked List):链表的一种变体。最后一个节点的后继指针指回到链表的“首元素”,形成一个环。最常见的工程实现是“单向循环链表 + tail 指针”(仅保存尾指针,首元素可由 head = tail->next 得到),常用于循环队列、轮询调度等。
- 循环链表的特点:无论从哪个节点出发,都可以遍历到链表中的任意节点,实现了节点间的循环访问。

链表结构体定义
循环链表不再保存头指针,而是仅保存tail指针,通过tail->next即可访问头结点
1 2 3 4 5 6 7 8 9 10 11
| typedef struct ListNode { int value; struct ListNode* next; } ListNode;
typedef struct List { ListNode* tail; size_t size; } List;
|
API设计与实现思路
单向循环链表的api设计与上方单向链表相同,这里具体说明单向循环链表哪些API与单向链表实现不同
| 与单向链表实现不同的 API |
原型 |
作用 |
核心实现思路/步骤(与单向差异) |
时间复杂度(循环 vs 单向) |
边界/注意点 |
list_init |
void list_init(List* list) |
初始化 |
置 tail=NULL, size=0(循环链表用 tail 表示端点) |
O(1) vs O(1) |
- |
list_clear |
void list_clear(List* list) |
清空 |
从 head=tail->next 开始,按“初始 size 次”释放,避免环上死循环;最后 tail=NULL |
O(n) vs O(n) |
不能用“走到 NULL 停止”;按计数释放 |
list_add_front |
bool list_add_front(List* list, int v) |
头插 |
空表:n->next=n; tail=n;非空:n->next=tail->next; tail->next=n(n 成为新 head) |
O(1) vs O(1) |
新 head 用 tail->next 表示;不必更新 tail |
list_add_back |
bool list_add_back(List* list, int v) |
尾插 |
空表同上;非空:n->next=tail->next; tail->next=n; tail=n |
O(1) vs O(n) |
借助 tail 将尾插降为 O(1) |
list_delete_front |
bool list_delete_front(List* list, int* out) |
头删 |
head=tail->next;单节点:free(tail), tail=NULL;否则:tail->next=head->next, free(head) |
O(1) vs O(1) |
单节点与非单节点分支;保持环连通 |
list_delete_back |
bool list_delete_back(List* list, int* out) |
尾删 |
单节点同头删;否则从 head 线性找到尾前驱 prev(prev->next==tail),prev->next=tail->next,free(tail),tail=prev |
O(n) vs O(n) |
必须线性找前驱;更新 tail |
list_insert |
bool list_insert(List* list, size_t idx, int v) |
按位插入 |
idx=0 调头插;idx=size 调尾插;否则从 head=tail->next 走到 idx-1,再线性插入 |
O(n) vs O(n) |
遍历不以 NULL 终止;从 head 起步 |
list_remove_at |
bool list_remove_at(List* list, size_t idx, int* out) |
按位删除 |
idx=0 调头删;idx=size-1 调尾删;否则从 head 走到 idx-1,删除其 next |
O(n) vs O(n) |
注意单节点与删尾时 tail 的更新 |
list_remove_value |
size_t list_remove_value(List* list, int v, bool all) |
按值删除 |
为避免死循环,用“初始 size 次计数”或“回到起点”终止;命中时 relink,若删尾则 tail=prev;删空则 tail=NULL |
O(n) vs O(n) |
不可用“while(cur)”以 NULL 终止;删空置 tail=NULL |
list_find_first |
long list_find_first(const List* list, int v) |
查找首个索引 |
非空从 head 起“走 size 次”或 do-while 回到 head 为止 |
O(n) vs O(n) |
终止条件为计数或回到起点,而非 cur==NULL |
list_foreach |
void list_foreach(const List* list, void (fn)(int, void), void* user) |
遍历回调 |
非空从 head 起遍历“size 次”调用回调 |
O(n) vs O(n) |
回调若改结构需谨慎,避免破坏计数遍历 |
list_reverse |
void list_reverse(List* list) |
原地反转 |
先“断环”(tail->next=NULL)→ 线性三指针反转 → “接回环”:新尾(原 head)->next=新头,tail=新尾 |
O(n) vs O(n) |
空/单节点直接返回;断环/接环和 tail 更新别遗漏 |
list_print |
void list_print(const List* list) |
打印 |
非空从 head 起“走 size 次”输出,常标注 circular |
O(n) vs O(n) |
打印不以 NULL 终止,按 size 控制次数 |
循环单向链表源码实现
github仓库:https://github.com/keqiudi/LinkList/tree/master/circular_linklist
circularlist.h
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 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187
|
#ifndef CIRCULARLIST_H #define CIRCULARLIST_H
#include <stddef.h> #include <stdbool.h>
#ifdef __cplusplus extern "C" { #endif
typedef struct ListNode { int value; struct ListNode* next; } ListNode;
typedef struct List { ListNode* tail; size_t size; } List;
void list_init(List* list);
void list_destroy(List* list);
void list_clear(List* list);
size_t list_size(const List* list);
bool list_empty(const List* list);
bool list_add_front(List* list, int value);
bool list_add_back(List* list, int value);
bool list_delete_front(List* list, int* out_value);
bool list_delete_back(List* list, int* out_value);
bool list_insert(List* list, size_t index, int value);
bool list_remove_at(List* list, size_t index, int* out_value);
size_t list_remove_value(List* list, int value, bool remove_all);
long list_find_first(const List* list, int value);
void list_foreach(const List* list, void (*fn)(int value, void* user), void* user);
void list_reverse(List* list);
void list_print(const List* list);
#ifdef __cplusplus } #endif
#endif
|
circularlist.c
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 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392
| #include "circular_list.h" #include <stdio.h> #include <stdlib.h>
static ListNode* create_node(int value) { ListNode* node = (ListNode*)malloc(sizeof(ListNode)); if (node == NULL) { return NULL; } node->value = value; node->next = NULL;
return node; }
void list_init(List* list) { if (list == NULL){ return; } list->tail = NULL; list->size = 0; }
void list_clear(List* list) { if (list == NULL || list->tail == NULL){ return; } ListNode* current = list->tail->next; for (size_t i=0;i<list->size;i++) { ListNode* next = current->next; free(current); current = next; }
list->tail = NULL; list->size = 0; }
void list_destroy(List* list) { list_clear(list); }
size_t list_size(const List* list) { return list ? list->size : 0; }
bool list_empty(const List* list) { return list ? (list->size == 0) : true; }
bool list_add_front(List* list,int value) { if (list == NULL){ return false; }
ListNode* node = create_node(value); if (node == NULL){ return false; }
if (list->tail == NULL) { node->next = node; list->tail = node; } else { node->next = list->tail->next; list->tail->next = node; } list->size++;
return true; }
bool list_add_back(List* list,int value) { if (list == NULL){ return false; } ListNode* node = create_node(value); if (node == NULL){ return false; }
if (list->tail == NULL) { node->next = node; list->tail = node; } else { node->next = list->tail->next; list->tail->next = node; list->tail = node;
} list->size++;
return true; }
bool list_delete_front(List* list, int* out_value) { if (list == NULL || list->tail == NULL){ return false; }
ListNode* head = list->tail->next; if (out_value != NULL) { *out_value = head->value; }
if (head == list->tail) { free(head); list->tail = NULL; } else { list->tail->next = head->next; free(head); }
list->size--; return true; }
bool list_delete_back(List* list, int* out_value) { if (list == NULL || list->tail == NULL){ return false; }
ListNode* tail = list->tail; if (out_value != NULL) { *out_value = tail->value; }
if (tail == tail->next) { free(tail); list->tail == NULL; } else { ListNode* prev = tail->next; while (prev->next != tail) { prev = prev->next; }
prev->next = tail->next; free(tail); list->tail = prev; }
list->size--; return true; }
bool list_insert(List* list, size_t index, int value) { if (list == NULL){ return false; }
if (index > list->size){ return false; }
if (index == 0){ return list_add_front(list,value);
} if (index == list->size){ return list_add_back(list,value); }
ListNode* node = create_node(value); if (node == NULL){ return false; }
ListNode* current = list->tail->next; for (int i=0;i<index-1;i++) { current = current->next; } node->next = current->next; current->next = node; list->size++; return true; }
bool list_remove_at(List* list,size_t index,int* out_value) { if (list == NULL || index >= list->size){ return false; }
if (index == 0){ return list_delete_front(list,out_value); } if (index == list->size-1){ return list_delete_back(list,out_value); }
ListNode* current = list->tail->next; for (int i=0;i<index-1;i++) { current = current->next; }
ListNode* target = current->next; if (out_value != NULL) { *out_value = target->value; }
current->next = target->next; free(target); list->size--; return true; }
size_t list_remove_value(List* list, int value, bool remove_all) { if (list == NULL || list->tail == NULL) { return 0; }
size_t removed_num = 0; size_t times = list->size;
ListNode* current = list->tail->next; ListNode* prev = list->tail;
for (size_t i=0;i<times;i++) { if (current == NULL) { break; }
if (current->value == value) { ListNode* target = current;
if (target == prev) { free(target); list->tail = NULL; list->size--; removed_num++; break; } else { prev->next = target->next; if (target == list->tail) { list->tail = prev; }
current = target->next; free(target); list->size--; removed_num++;
if (!remove_all) { break; } } } else { prev = current; current = current->next; }
}
return removed_num; }
long list_find_first(const List* list, int value) { if (list == NULL || list->tail == NULL) { return -1; }
ListNode* current = list->tail->next; for (long i=0;i<list->size;i++) { if (current->value == value) { return i; } current = current->next; }
return -1; }
void list_foreach(const List* list, void (*fn)(int value, void* user), void* user) { if (list== NULL || list->tail ==NULL || !fn) { return; }
const ListNode* cur = list->tail->next; for (size_t i = 0; i < list->size; ++i) { fn(cur->value, user); cur = cur->next; } }
void list_reverse(List* list) { if (list == NULL || list->tail == NULL) { return; }
if (list->tail->next == list->tail) { return; }
ListNode* head = list->tail->next; list->tail->next = NULL;
ListNode* prev = NULL; ListNode* cur = head; while (cur) { ListNode* nxt = cur->next; cur->next = prev; prev = cur; cur = nxt; } head->next = prev; list->tail = head; }
void list_print(const List* list) { if (list == NULL || list->tail == NULL) { printf("[] (circular, size=0)\n"); return; } const ListNode* cur = list->tail->next; printf("["); for (size_t i = 0; i < list->size; ++i) { printf("%d", cur->value); if (i + 1 < list->size) printf(" -> "); cur = cur->next; } printf("] (circular, size=%zu)\n", list->size); }
|
测试代码
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
| #include "circular_list.h" #include <stdio.h> #include <assert.h>
static void sum_cb(int v, void* user) { int* acc = (int*)user; *acc += v; }
int main(void) { List ls; list_init(&ls);
assert(list_empty(&ls) == true); assert(list_size(&ls) == 0); int tmp; assert(list_delete_front(&ls, &tmp) == false); assert(list_delete_back(&ls, &tmp) == false); assert(list_remove_at(&ls, 0, &tmp) == false); assert(list_remove_value(&ls, 123, true) == 0);
assert(list_add_back(&ls, 1) == true); assert(list_add_back(&ls, 2) == true); assert(list_add_back(&ls, 3) == true); list_print(&ls); assert(list_size(&ls) == 3); assert(list_empty(&ls) == false);
assert(list_add_front(&ls, 0) == true); list_print(&ls); assert(list_size(&ls) == 4);
assert(list_insert(&ls, 2, 99) == true); list_print(&ls); assert(list_insert(&ls, list_size(&ls), 42) == true); list_print(&ls);
long idx = list_find_first(&ls, 99); printf("find 99 at index = %ld\n", idx); assert(idx == 2); assert(list_find_first(&ls, -7) == -1);
int val = 0; assert(list_remove_at(&ls, 2, &val) == true); assert(val == 99); list_print(&ls);
assert(list_remove_at(&ls, list_size(&ls) - 1, &val) == true); assert(val == 42); list_print(&ls);
assert(list_add_back(&ls, 2) == true); assert(list_add_back(&ls, 2) == true); list_print(&ls);
size_t removed = list_remove_value(&ls, 2, false); printf("removed one 2 count=%zu\n", removed); assert(removed == 1); list_print(&ls);
removed = list_remove_value(&ls, 2, true); printf("removed all 2 count=%zu\n", removed); assert(removed >= 1); list_print(&ls);
assert(list_delete_front(&ls, &val) == true); printf("delete_front=%d\n", val); list_print(&ls);
assert(list_delete_back(&ls, &val) == true); printf("delete_back=%d\n", val); list_print(&ls);
assert(list_add_back(&ls, 10) == true); assert(list_add_back(&ls, 20) == true); assert(list_add_back(&ls, 30) == true); list_print(&ls);
list_reverse(&ls); printf("reversed: "); list_print(&ls);
list_clear(&ls); list_reverse(&ls); assert(list_empty(&ls));
assert(list_add_back(&ls, 7) == true); list_reverse(&ls); assert(list_size(&ls) == 1); list_print(&ls);
int sum = 0; list_foreach(&ls, sum_cb, &sum); printf("sum=%d\n", sum); assert(sum == 7);
list_clear(&ls); printf("cleared: "); list_print(&ls); assert(list_empty(&ls)); list_destroy(&ls);
printf("All tests passed!\n"); return 0; }
|
输出结果:
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
| C:\Users\keqiu\myProjects\CLionProjects\C\LinkList\circular_linklist\build\circular_linklist.exe [1 -> 2 -> 3] (circular, size=3) [0 -> 1 -> 2 -> 3] (circular, size=4) [0 -> 1 -> 99 -> 2 -> 3] (circular, size=5) [0 -> 1 -> 99 -> 2 -> 3 -> 42] (circular, size=6) find 99 at index = 2 [0 -> 1 -> 2 -> 3 -> 42] (circular, size=5) [0 -> 1 -> 2 -> 3] (circular, size=4) [0 -> 1 -> 2 -> 3 -> 2 -> 2] (circular, size=6) removed one 2 count=1 [0 -> 1 -> 3 -> 2 -> 2] (circular, size=5) removed all 2 count=2 [0 -> 1 -> 3] (circular, size=3) delete_front=0 [1 -> 3] (circular, size=2) delete_back=3 [1] (circular, size=1) [1 -> 10 -> 20 -> 30] (circular, size=4) reversed: [30 -> 20 -> 10 -> 1] (circular, size=4) [7] (circular, size=1) sum=7 cleared: [] (circular, size=0) All tests passed!
进程已结束,退出代码为 0
|
循环双向链表
这个在循环单向链表的基础上进行修改即可,使用的时候再说吧