一、链表的基本概念
链表是一种物理存储单元上非连续、非顺序的线性结构,数据元素之间的逻辑关系通过指针链接来实现。
优点:
动态内存分配,不需要预先分配连续空间
插入删除操作方便,时间复杂度O(1)
缺点:
不支持随机访问,查找需要O(n)
需要额外的指针存储空间
二、单链表
单链表是最基本的链表结构,由一系列节点组成,每个节点包含:
数据域:存储数据元素
指针域:存储指向下一个节点的指针
核心特点:节点之间是单向连接的,只能从头到尾依次访问,不能反向访问。
-
结构定义
typedef struct Node {
int data; // 数据域
struct Node* next; // 指针域
} Node, *LinkedList;
-
基本操作
初始化
LinkedList initList() {
LinkedList head = (Node*)malloc(sizeof(Node));
if (head == NULL) return NULL;
head->next = NULL;
return head;
}
头插法
void insertAtHead(LinkedList head, int value) {
Node* newNode = (Node*)malloc(sizeof(Node));
newNode->data = value;
newNode->next = head->next;
head->next = newNode;
}
尾插法
void insertAtTail(LinkedList head, int value) {
Node* newNode = (Node*)malloc(sizeof(Node));
newNode->data = value;
newNode->next = NULL;
Node* p = head;
while (p->next != NULL) {
p = p->next;
}
p->next = newNode;
}
删除节点
int deleteNode(LinkedList head, int value) {
Node* p = head;
while (p->next != NULL && p->next->data != value) {
p = p->next;
}
if (p->next == NULL) return -1; // 未找到
Node* temp = p->next;
p->next = temp->next;
free(temp);
return 0;
}
三、双向链表
双向链表是在单链表的基础上,每个节点增加一个指向前驱节点的指针,形成双向连接的结构。
核心特点:
每个节点有两个指针:prev(指向前一个节点)和next(指向后一个节点)
可以从两个方向遍历链表
支持双向查找,提高某些操作的效率
-
结构定义
typedef struct DoubleNode {
int data;
struct DoubleNode* prev; // 前驱指针
struct DoubleNode* next; // 后继指针
} DoubleNode, *DoubleList;
-
基本操作
初始化
DoubleList initDoubleList() {
DoubleList head = (DoubleNode*)malloc(sizeof(DoubleNode));
if (head == NULL) return NULL;
head->prev = NULL;
head->next = NULL;
return head;
}
插入(指定位置后)
void insertAfter(DoubleNode* pos, int value) {
if (pos == NULL) return;
DoubleNode* newNode = (DoubleNode*)malloc(sizeof(DoubleNode));
newNode->data = value;
newNode->next = pos->next;
newNode->prev = pos;
if (pos->next != NULL) {
pos->next->prev = newNode;
}
pos->next = newNode;
}
删除节点
void deleteNode(DoubleList head, DoubleNode* target) {
if (target == NULL) return;
target->prev->next = target->next;
if (target->next != NULL) {
target->next->prev = target->prev;
}
free(target);
}
四、循环链表
循环链表是链表的另一种形式,其最后一个节点的指针指向头结点(或第一个节点),形成一个环状结构。
核心特点:
没有NULL指针,链表中所有节点都首尾相连
从任意节点出发都可以访问到所有节点
可以无限遍历,需要设置终止条件
-
单循环链表
结构定义
typedef struct CircularNode {
int data;
struct CircularNode* next;
} CircularNode, CircularList;
初始化
CircularList initCircularList() {
CircularList head = (CircularNode )malloc(sizeof(CircularNode));if (head == NULL) return NULL;
head->next = head; // 指向自身,形成循环
return head;
}
插入
void insertCircular(CircularList head, int value) {
CircularNode* newNode = (CircularNode*)malloc(sizeof(CircularNode));
newNode->data = value;
newNode->next = head->next;
head->next = newNode;
}
遍历(需判断循环结束)
void printCircular(CircularList head) {
if (head->next == head) {
printf("空链表\n");
return;
}
CircularNode* p = head->next;
do {
printf("%d -> ", p->data);
p = p->next;
} while (p != head->next);
printf("(循环)\n");
}
-
双向循环链表
结构定义
typedef struct DCNode {
int data;
struct DCNode* prev;
struct DCNode* next;
} DCNode, DCList;
初始化
DCList initDCList() {
DCList head = (DCNode )malloc(sizeof(DCNode));if (head == NULL) return NULL;
head->prev = head;
head->next = head;
return head;
}
插入
void insertDC(DCList head, int value) {
DCNode* newNode = (DCNode*)malloc(sizeof(DCNode));
newNode->data = value;
newNode->next = head->next;
newNode->prev = head;
head->next->prev = newNode;
head->next = newNode;
}
五、常见应用场景
链表类型 适用场景
单链表 栈、队列的底层实现,邻接表
双向链表 LRU缓存淘汰算法,需要双向遍历的场景
循环链表 约瑟夫环问题,操作系统进程调度(时间片轮转)