数据结构与算法
前言
手写C语言链表
代码详解:
-
结构体
Node
:int data
:用于存储节点中的数据。struct Node* next
:指向下一个节点的指针。这是链表的核心,通过指针将各个节点串联起来。
-
指针的使用:
-
在 C 语言中,指针是链表实现的核心,因为链表中的节点是分散在内存中的,指针用于将它们连接起来。
-
struct Node** head
:在插入和删除操作中,使用双重指针(**head
)的原因是,我们可能需要修改头指针本身。双重指针允许我们在函数中改变原始的头指针。c 复制代码 insertAtHead(struct Node** head, int data);
通过
*head = newNode;
语句,我们可以将头指针指向新的节点,更新链表的头部。
-
-
createNode
函数:- 这是创建新节点的函数,通过
malloc
函数动态分配内存,确保链表节点在内存中正确分配。
c 复制代码 struct Node* newNode = (struct Node*)malloc(sizeof(struct Node));
- 动态分配内存后,我们将数据存储在节点中,并将
next
指针初始化为NULL
,因为新节点默认不指向任何后继节点。
- 这是创建新节点的函数,通过
-
insertAtHead
函数:- 该函数用于在链表头部插入新节点。通过
newNode->next = *head;
,我们将新节点的next
指针指向当前的头节点,然后通过*head = newNode;
将头指针指向新的节点。
- 该函数用于在链表头部插入新节点。通过
-
deleteNode
函数:- 该函数用于从链表中删除某个值对应的节点。如果要删除的节点是头节点,我们只需将头指针指向下一个节点;否则,我们需要找到要删除节点的前一个节点,并调整指针跳过要删除的节点。
-
printList
函数:- 该函数通过遍历链表,将每个节点的数据打印出来。使用临时指针
temp
从头节点开始,逐步遍历每个节点,直到temp
为NULL
(链表的末尾)。
- 该函数通过遍历链表,将每个节点的数据打印出来。使用临时指针
-
freeList
函数:- 这是释放链表内存的函数,避免内存泄漏。在这里,我们通过逐个释放节点来确保链表所占用的内存被完全释放。
c 复制代码 free(temp);
- 每次释放一个节点后,我们将头指针移动到下一个节点,直到整个链表被释放完毕。
亮点:
- 内存管理:确保所有分配的内存(
malloc
)在不使用时通过free
函数释放,避免内存泄漏。 - 双重指针的使用:通过使用
Node**
来操作头指针,确保能够修改原始头指针的值,尤其是在插入和删除操作中。 - 代码的可读性和性能:使用简洁的逻辑和遍历方式,保证操作链表时的效率和清晰度。
提示:以下是本篇文章正文内容,下面案例可供参考
#include <stdio.h>
#include <stdlib.h>
// 定义链表节点结构体
struct Node {
int data; // 存储数据
struct Node* next; // 指向下一个节点的指针
};
// 创建新节点
struct Node* createNode(int data);
// 头部插入节点
void insertAtHead(struct Node** head, int data);
// 在链表中删除某个值的节点
void deleteNode(struct Node** head, int key);
// 打印链表中的所有节点
void printList(struct Node* head);
// 释放链表占用的内存
void freeList(struct Node** head);
// 主函数
int main() {
struct Node* head = NULL; // 初始化链表为空
// 向链表头部插入一些数据
insertAtHead(&head, 10);
insertAtHead(&head, 20);
insertAtHead(&head, 30);
insertAtHead(&head, 40);
// 打印链表
printf("链表内容: ");
printList(head);
// 删除值为20的节点
printf("删除节点值为20后的链表: ");
deleteNode(&head, 20);
printList(head);
// 释放链表内存
freeList(&head);
return 0;
}
// 创建新节点
struct Node* createNode(int data) {
struct Node* newNode = (struct Node*)malloc(sizeof(struct Node));
if (!newNode) {
printf("内存分配失败\n");
exit(1); // 终止程序
}
newNode->data = data; // 将数据存储到节点中
newNode->next = NULL; // 初始化为无后继节点
return newNode;
}
// 头部插入节点
void insertAtHead(struct Node** head, int data) {
struct Node* newNode = createNode(data); // 创建新节点
newNode->next = *head; // 将新节点的next指针指向当前的头节点
*head = newNode; // 更新头指针,使之指向新节点
}
// 删除链表中某个值的节点
void deleteNode(struct Node** head, int key) {
struct Node* temp = *head; // 用于遍历链表的临时指针
struct Node* prev = NULL; // 用于保存前驱节点的指针
// 如果头节点就是要删除的节点
if (temp != NULL && temp->data == key) {
*head = temp->next; // 将头指针指向第二个节点
free(temp); // 释放头节点内存
return;
}
// 查找要删除的节点,同时保持前驱节点的记录
while (temp != NULL && temp->data != key) {
prev = temp; // 保存当前节点作为前驱节点
temp = temp->next; // 指向下一个节点
}
// 如果没有找到要删除的节点
if (temp == NULL) return;
// 前驱节点的 next 指向待删除节点的 next,跳过待删除节点
prev->next = temp->next;
free(temp); // 释放内存
}
// 打印链表中的所有节点
void printList(struct Node* head) {
struct Node* temp = head; // 临时指针用于遍历链表
while (temp != NULL) {
printf("%d -> ", temp->data);
temp = temp->next; // 移动到下一个节点
}
printf("NULL\n");
}
// 释放链表占用的内存
void freeList(struct Node** head) {
struct Node* temp;
while (*head != NULL) {
temp = *head; // 保存当前头节点
*head = (*head)->next; // 将头指针指向下一个节点
free(temp); // 释放当前节点内存
}
}