一、基本概念
单向链表属于一种线性的数据结构,由多个节点串联而成。每个节点包含两个部分:一部分用于存储实际数据(即数据域),另一部分为指针域,保存指向下一个节点的内存地址。链表中最后一个节点的指针域指向空值,表示链表到此终止。
NULL
与数组相比,单向链表采用动态内存分配方式,使得在进行插入和删除操作时更加高效;但其不支持直接访问任意位置元素,因此随机访问性能较差。
二、核心特性
- 动态容量:链表不需要在创建时就确定大小,能够根据运行时需求灵活地扩展或缩减内存使用。
- 高效的增删操作:当已知目标位置时,插入和删除的时间复杂度仅为O(1)。相比之下,数组需要移动大量元素以保持连续性。
- 非连续内存布局:各个节点在物理内存中不必相邻,依靠指针相互连接形成逻辑上的顺序结构。
- 无法随机存取:要访问第n个节点,必须从头节点开始逐个遍历,导致时间复杂度为O(n)。
三、常见操作实现
1. 节点结构定义
typedef struct Node {
int data; // 数据域
struct Node *next; // 指针域
} Node;
每个节点通常包含一个数据字段和一个指向下一节点的指针,在程序中可通过结构体或类来实现。
2. 链表初始化
构建链表的第一步是创建一个头节点或者初始化一个空链表,作为后续操作的基础。
Node* createList() {
return NULL; // 返回空链表
}
3. 节点插入方式
(1)头部插入法:将新节点设置为新的首节点,原链表整体后移一位。
Node* insertAtHead(Node *head, int value) {
Node *newNode = (Node*)malloc(sizeof(Node));
newNode->data = value;
newNode->next = head;
return newNode; // 返回新头节点
}
(2)尾部插入法:通过遍历找到当前链表的末尾节点,并在其后添加新节点。
Node* insertAtTail(Node *head, int value) {
Node *newNode = (Node*)malloc(sizeof(Node));
newNode->data = value;
newNode->next = NULL;
if (head == NULL) return newNode;
Node *current = head;
while (current->next != NULL) {
current = current->next;
}
current->next = newNode;
return head;
}
4. 删除指定节点
查找具有特定值的节点并将其从链表中断开连接,同时释放其所占内存。
Node* deleteNode(Node *head, int value) {
if (head == NULL) return NULL;
if (head->data == value) {
Node *temp = head->next;
free(head);
return temp;
}
Node *current = head;
while (current->next != NULL && current->next->data != value) {
current = current->next;
}
if (current->next != NULL) {
Node *temp = current->next;
current->next = temp->next;
free(temp);
}
return head;
}
5. 链表遍历过程
从头节点出发,依次访问每一个节点直至到达末尾,常用于打印内容或查找匹配项。
void traverseList(Node *head) {
Node *current = head;
while (current != NULL) {
printf("%d -> ", current->data);
current = current->next;
}
printf("NULL\n");
}
四、优势与局限性分析
优点:
- 在已知位置的情况下,插入与删除操作效率极高。
- 内存按需分配,避免了空间浪费,提高了利用率。
缺点:
- 访问任意节点必须顺序进行,不具备随机访问能力,影响查询效率。
- 每个节点额外维护一个指针,增加了内存开销。


雷达卡


京公网安备 11010802022788号







