链表的基本概念
链表是一种线性数据结构,由一系列节点组成,每个节点包含数据域和指针域。数据域存储实际数据,指针域存储指向下一个节点的地址。链表通过指针将节点串联起来,形成链式结构。
链表与数组不同,数组在内存中是连续存储的,而链表的节点可以分散在内存中的任何位置。链表的优势在于动态内存分配,插入和删除操作效率较高,但访问元素时需要从头节点开始遍历。
链表的类型
单链表
单链表是最简单的链表形式,每个节点包含数据和一个指向下一个节点的指针。链表的最后一个节点指向NULL,表示链表的结束。
双向链表
双向链表的每个节点包含两个指针,一个指向前一个节点,另一个指向后一个节点。这种结构允许从任意方向遍历链表,但占用更多内存。
循环链表
循环链表的最后一个节点指向头节点,形成一个闭环。循环链表可以是单向或双向的,适用于需要循环访问数据的场景。
链表的基本操作
插入节点
在链表中插入节点分为头部插入、尾部插入和中间插入。头部插入只需将新节点的指针指向原头节点,并更新头节点为新节点。尾部插入需要遍历到链表末尾,将最后一个节点的指针指向新节点。中间插入需要找到插入位置的前驱节点,调整指针指向。
删除节点
删除节点时,需要找到待删除节点的前驱节点,将其指针指向待删除节点的后继节点。如果是双向链表,还需要调整后继节点的前驱指针。
遍历链表
遍历链表从头节点开始,依次访问每个节点,直到遇到NULL指针。遍历过程中可以读取或修改节点的数据。
链表的应用场景
链表适用于需要频繁插入和删除操作的场景,如实现栈、队列、哈希表等数据结构。链表还常用于内存管理、文件系统等领域。
链表的实现示例(C语言)
#include <stdio.h>
#include <stdlib.h>
// 定义链表节点
struct Node {
int data;
struct Node* next;
};
// 创建新节点
struct Node* createNode(int data) {
struct Node* newNode = (struct Node*)malloc(sizeof(struct Node));
newNode->data = data;
newNode->next = NULL;
return newNode;
}
// 在链表头部插入节点
void insertAtHead(struct Node** head, int data) {
struct Node* newNode = createNode(data);
newNode->next = *head;
*head = newNode;
}
// 在链表尾部插入节点
void insertAtTail(struct Node** head, int data) {
struct Node* newNode = createNode(data);
if (*head == NULL) {
*head = newNode;
return;
}
struct Node* temp = *head;
while (temp->next != NULL) {
temp = temp->next;
}
temp->next = 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;
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("\n");
}
int main() {
struct Node* head = NULL;
insertAtHead(&head, 1);
insertAtTail(&head, 2);
insertAtTail(&head, 3);
printList(head);
deleteNode(&head, 2);
printList(head);
return 0;
}
链表的优缺点
优点
- 动态内存分配,无需预先知道数据规模。
- 插入和删除操作效率高,时间复杂度为O(1)(已知位置时)。
- 内存利用率高,节点可以分散存储。
缺点
- 访问元素需要从头遍历,时间复杂度为O(n)。
- 需要额外空间存储指针,占用更多内存。
- 不支持随机访问,无法像数组一样通过索引直接访问元素。
503

被折叠的 条评论
为什么被折叠?



