C语言版本链表详解
前言
链表(Linked List)是一种常见的数据结构,它允许我们动态地分配内存,并通过指针将元素链接在一起。在C语言中,链表通常通过结构体(struct)和指针来实现。下面,我将为你详细解释链表的基本概念以及如何在C语言中实现链表。
链表的基本概念
- 节点(Node):链表中的每一个元素都称为一个节点。节点通常包含一个数据域(用于存储数据)和一个指针域(用于指向下一个节点)。
- 头节点(Head Node):链表的第一个节点,通常包含一个特殊的指针(如
NULL
)作为链表的结束标志。 - 尾节点(Tail Node):链表的最后一个节点,其指针域通常指向
NULL
。 - 单向链表(Single Linked List):每个节点只包含一个指向下一个节点的指针。
- 双向链表(Doubly Linked List):每个节点包含两个指针,一个指向下一个节点,另一个指向前一个节点。
示例
C语言实现单向链表
下面是一个简单的单向链表的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 | #include <stdio.h> #include <stdlib.h> // 定义链表节点结构体 typedef struct Node { int data; struct Node* next; } Node; // 创建新节点 Node* createNode( int data) { Node* newNode = (Node*)malloc(sizeof(Node)); if (!newNode) { printf( "Memory allocation failed\n" ); exit( 0 ); } newNode->data = data; newNode->next = NULL; return newNode; } // 在链表末尾添加节点 void appendNode(Node** head, int data) { Node* newNode = createNode(data); if (*head == NULL) { *head = newNode; } else { Node* temp = *head; while (temp->next != NULL) { temp = temp->next; } temp->next = newNode; } } // 打印链表 void printList(Node* head) { Node* temp = head; while (temp != NULL) { printf( "%d " , temp->data); temp = temp->next; } printf( "\n" ); } int main() { Node* head = NULL; appendNode(&head, 1 ); appendNode(&head, 2 ); appendNode(&head, 3 ); printList(head); // 输出: 1 2 3 return 0 ; } |
这个示例中,我们定义了一个Node
结构体来表示链表的节点,并提供了创建新节点、在链表末尾添加节点和打印链表的函数。在main
函数中,我们创建了一个链表并添加了三个节点,然后打印出链表的内容。
C语言实现双向链表
在C语言中实现双向链表(Doubly Linked List)与实现单向链表类似,但每个节点需要包含两个指针:一个指向下一个节点(next
),另一个指向前一个节点(prev
)。下面是一个简单的双向链表实现示例:
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 | #include <stdio.h> #include <stdlib.h> // 定义双向链表节点结构体 typedef struct Node { int data; struct Node* next; struct Node* prev; } Node; // 创建新节点 Node* createNode( int data) { Node* newNode = (Node*)malloc(sizeof(Node)); if (!newNode) { printf( "Memory allocation failed\n" ); exit( 0 ); } newNode->data = data; newNode->next = NULL; newNode->prev = NULL; // 双向链表节点还需要初始化prev为NULL return newNode; } // 在链表末尾添加节点 void appendNode(Node** head, int data) { Node* newNode = createNode(data); if (*head == NULL) { *head = newNode; } else { Node* temp = *head; while (temp->next != NULL) { temp = temp->next; } temp->next = newNode; newNode->prev = temp; // 双向链表需要设置prev指针 } } // 在链表开头添加节点 void prependNode(Node** head, int data) { Node* newNode = createNode(data); if (*head == NULL) { *head = newNode; } else { newNode->next = *head; (*head)->prev = newNode; // 更新头节点的prev指针 *head = newNode; // 更新头指针 } } // 打印链表 void printList(Node* head) { Node* temp = head; while (temp != NULL) { printf( "%d " , temp->data); temp = temp->next; } printf( "\n" ); } // 清理链表内存 void freeList(Node* head) { Node* temp; while (head != NULL) { temp = head; head = head->next; free(temp); } } int main() { Node* head = NULL; appendNode(&head, 1 ); appendNode(&head, 2 ); prependNode(&head, 0 ); // 在开头添加节点 printList(head); // 输出: 0 1 2 freeList(head); // 释放链表内存 return 0 ; } |
在这个示例中,我们定义了一个Node
结构体来表示双向链表的节点,包含了data
、next
和prev
三个成员。createNode
函数用于创建新节点,并初始化next
和prev
为NULL
。appendNode
函数用于在链表末尾添加节点,同时更新了新节点的prev
指针。prependNode
函数用于在链表开头添加节点,同时更新了新节点的next
指针和头节点的prev
指针。printList
函数用于打印链表的内容,只遍历next
指针。最后,freeList
函数用于释放链表占用的内存。
注意,在添加或删除节点时,需要确保正确更新相关节点的prev
和next
指针,以避免链表断开或形成环。同时,在释放链表内存时,也要确保遍历整个链表并释放每个节点的内存。
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 无需6万激活码!GitHub神秘组织3小时极速复刻Manus,手把手教你使用OpenManus搭建本
· C#/.NET/.NET Core优秀项目和框架2025年2月简报
· Manus爆火,是硬核还是营销?
· 一文读懂知识蒸馏
· 终于写完轮子一部分:tcp代理 了,记录一下