目录
1.链表的性质
动态内存分配
链表的节点在运行时动态分配内存,链表的大小可以在插入或删除节点时动态变化,不需要预先分配固定大小的内存。
节点结构
每个节点通常包含两部分:
数据域:存储实际数据。
指针域:存储指向下一个节点的指针(单向链表)或指向前一个和下一个节点的指针(双向链表)。
链接特性
节点通过指针链接在一起,形成一个线性结构。第一个节点称为头节点,最后一个节点的指针指向空(NULL)。
访问时间
链表的节点不连续存储,访问节点时需要从头节点开始逐一遍历,时间复杂度为 O(n)。与数组不同,链表不支持通过索引直接访问某个节点。
插入和删除操作
在链表中插入和删除节点非常高效,只需改变节点的指针,时间复杂度为 O(1)。但是,找到插入或删除的位置需要遍历,时间复杂度为 O(n)。
类型
链表有多种类型,根据指针域的数量和结构的不同,常见的有:
单向链表(Singly Linked List):每个节点只有一个指向下一个节点的指针。
双向链表(Doubly Linked List):每个节点有两个指针,分别指向前一个和后一个节点。
循环链表(Circular Linked List):单向或双向链表的变种,最后一个节点的指针指向头节点,形成一个环。
双向循环链表(Doubly Circular Linked List):双向链表的变种,最后一个节点的指针指向头节点,头节点的前一个指针指向最后一个节点。
应用场景
链表适用于以下应用场景:
需要频繁插入和删除的场景:链表插入和删除节点的效率高,不需要移动其他节点。
不需要随机访问的场景:链表访问节点需要遍历,不适合频繁的随机访问。
实现抽象数据类型(ADT):如队列、栈等,可以用链表高效实现。
2.链表的定义
typedef struct ListNode {
int data;
struct ListNode* next;
} ListNode;
3.链表的创建
ListNode* createNode(int data) {
ListNode* newNode = (ListNode*)malloc(sizeof(ListNode));
if (!newNode) {
printf("Memory allocation failed\n");
exit(1);
}
newNode->data = data;
newNode->next = NULL;
return newNode;
}
4.链表的插入
4.1 头插法
// 头插法插入节点
void headInsert(ListNode* list, int data) {
ListNode* newNode = createNode(data);
newNode->next = list->next;
list->next = newNode;
}
4.2 尾插法
// 尾插法插入节点
void tailInsert(ListNode* list, int data) {
ListNode* newNode = createNode(data);
while (list->next) {
list = list->next;
}
list->next = newNode;
}
5.链表的遍历
// 打印链表
void printList(ListNode* list) {
ListNode* current = list->next; // 跳过哨兵节点
while (current) {
printf("%d ", current->data);
current = current->next;
}
printf("\n");
}
6.链表的资源释放
// 释放链表内存
void freeList(ListNode* list) {
ListNode* current = list;
while (current) {
ListNode* next = current->next;
free(current);
current = next;
}
}
7.链表的源代码
#include <stdio.h>
#include <stdlib.h>
typedef struct ListNode {
int data;
struct ListNode* next;
} ListNode;
// 创建一个新的节点
ListNode* createNode(int data) {
ListNode* newNode = (ListNode*)malloc(sizeof(ListNode));
if (!newNode) {
printf("Memory allocation failed\n");
exit(1);
}
newNode->data = data;
newNode->next = NULL;
return newNode;
}
// 初始化链表
ListNode* initList() {
return createNode(0); // 哨兵节点,简化插入操作
}
// 头插法插入节点
void headInsert(ListNode* list, int data) {
ListNode* newNode = createNode(data);
newNode->next = list->next;
list->next = newNode;
}
// 尾插法插入节点
void tailInsert(ListNode* list, int data) {
ListNode* newNode = createNode(data);
while (list->next) {
list = list->next;
}
list->next = newNode;
}
// 打印链表
void printList(ListNode* list) {
ListNode* current = list->next; // 跳过哨兵节点
while (current) {
printf("%d ", current->data);
current = current->next;
}
printf("\n");
}
// 释放链表内存
void freeList(ListNode* list) {
ListNode* current = list;
while (current) {
ListNode* next = current->next;
free(current);
current = next;
}
}
int main() {
ListNode* list = initList();
headInsert(list, 3);
headInsert(list, 2);
headInsert(list, 1);
tailInsert(list, 4);
printList(list);
freeList(list);
return 0;
}
1738

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



