C语言需要掌握的基础知识点之链表
链表是一种动态数据结构,它通过指针将一系列节点连接成一个序列。与数组不同,链表的大小可以在运行时动态改变,内存分配也更加灵活。
链表的基本概念
链表是由节点组成的数据结构,每个节点包含:
数据域:存储实际数据
指针域:指向下一个节点的地址
链表的类型
单链表:每个节点只有一个指向下一个节点的指针
双链表:每个节点有指向前一个和后一个节点的指针
循环链表:尾节点指向头节点,形成环状结构
单链表实现
基本单链表操作
c
#include <stdio.h>
#include <stdlib.h>
#include <stdbool.h>
// 单链表节点定义
typedef struct ListNode {
int data;
struct ListNode *next;
} ListNode;
// 创建新节点
ListNode* createNode(int data) {
ListNode *newNode = (ListNode*)malloc(sizeof(ListNode));
if (newNode == NULL) {
printf("内存分配失败\n");
return NULL;
}
newNode->data = data;
newNode->next = NULL;
return newNode;
}
// 在链表头部插入节点
ListNode* insertAtHead(ListNode *head, int data) {
ListNode *newNode = createNode(data);
if (newNode == NULL) return head;
newNode->next = head;
return newNode;
}
// 在链表尾部插入节点
ListNode* insertAtTail(ListNode *head, int data) {
ListNode *newNode = createNode(data);
if (newNode == NULL) return head;
if (head == NULL) {
return newNode;
}
ListNode *current = head;
while (current->next != NULL) {
current = current->next;
}
current->next = newNode;
return head;
}
// 在指定位置插入节点
ListNode* insertAtPosition(ListNode *head, int data, int position) {
if (position < 0) {
printf("位置不能为负数\n");
return head;
}
if (position == 0) {
return insertAtHead(head, data);
}
ListNode *newNode = createNode(data);
if (newNode == NULL) return head;
ListNode *current = head;
for (int i = 0; i < position - 1 && current != NULL; i++) {
current = current->next;
}
if (current == NULL) {
printf("位置超出链表长度\n");
free(newNode);
return head;
}
newNode->next = current->next;
current->next = newNode;
return head;
}
// 删除头节点
ListNode* deleteAtHead(ListNode *head) {
if (head == NULL) {
printf("链表为空\n");
return NULL;
}
ListNode *temp = head;
head = head->next;
free(temp);
return head;
}
// 删除尾节点
ListNode* deleteAtTail(ListNode *head) {
if (head == NULL) {
printf("链表为空\n");
return NULL;
}
if (head->next == NULL) {
free(head);
return NULL;
}
ListNode *current = head;
while (current->next->next != NULL) {
current = current->next;
}
free(current->next);
current->next = NULL;
return head;
}
// 删除指定值的节点
ListNode* deleteNode(ListNode *head, int data) {
if (head == NULL) {
printf("链表为空\n");
return NULL;
}
// 如果要删除的是头节点
if (head->data == data) {
ListNode *temp = head;
head = head->next;
free(temp);
return head;
}
ListNode *current = head;
while (current->next != NULL && current->next->data != data) {
current = current->next;
}
if (current->next == NULL) {
printf("未找到值为 %d 的节点\n", data);
return head;
}
ListNode *temp = current->next;
current->next = current->next->next;
free(temp);
return head;
}
// 查找节点
bool searchNode(ListNode *head, int data) {
ListNode *current = head;
while (current != NULL) {
if (current->data == data) {
return true;
}
current = current->next;
}
return false;
}
// 获取链表长度
int getLength(ListNode *head) {
int length = 0;
ListNode *current = head;
while (current != NULL) {
length++;
current = current->next;
}
return length;
}
// 打印链表
void printList(ListNode *head) {
ListNode *current = head;
printf("链表: ");
while (current != NULL) {
printf("%d -> ", current->data);
current = current->next;
}
printf("NULL\n");
}
// 反转链表
ListNode* reverseList(ListNode *head) {
ListNode *prev = NULL;
ListNode *current = head;
ListNode *next = NULL;
while (current != NULL) {
next = current->next;
current->next = prev;
prev = current;
current = next;
}
return prev;
}
// 销毁链表
void destroyList(ListNode *head) {
ListNode *current = head;
while (current != NULL) {
ListNode *temp = current;
current = current->next;
free(temp);
}
}
// 单链表演示
void singlyLinkedListDemo() {
printf("=== 单链表操作演示 ===\n");
ListNode *head = NULL;
// 插入操作
head = insertAtHead(head, 10);
head = insertAtHead(head, 20);
head = insertAtTail(head, 30);
head = insertAtTail(head, 40);
head = insertAtPosition(head, 25, 2);
printList(head);
printf("链表长度: %d\n", getLength(head));
// 查找操作
printf("查找 25: %s\n", searchNode(head, 25) ? "找到" : "未找到");
printf("查找 50: %s\n", searchNode(head, 50) ? "找到" : "未找到");
// 删除操作
head = deleteNode(head, 25);
printf("删除 25 后: ");
printList(head);
head = deleteAtHead(head);
printf("删除头节点后: ");
printList(head);
head = deleteAtTail(head);
printf("删除尾节点后: ");
printList(head);
// 反转链表
head = reverseList(head);
printf("反转链表后: ");
printList(head);
destroyList(head);
}
int main() {
singlyLinkedListDemo();
return 0;
}
双链表实现
双链表基本操作
c
#include <stdio.h>
#include <stdlib.h>
#include <stdbool.h>
// 双链表节点定义
typedef struct DoublyListNode {
int data;
struct DoublyListNode *prev;
struct DoublyListNode *next;
} DoublyListNode;
// 创建新节点
DoublyListNode* createDoublyNode(int data) {
DoublyListNode *newNode = (DoublyListNode*)malloc(sizeof(DoublyListNode));
if (newNode == NULL) {
printf("内存分配失败\n");
return NULL;
}
newNode->data = data;
newNode->prev = NULL;
newNode->next = NULL;
return newNode;
}
// 在双链表头部插入节点
DoublyListNode* insertAtDoublyHead(DoublyListNode *head, int data) {
DoublyListNode *newNode = createDoublyNode(data);
if (newNode == NULL) return head;
if (head == NULL) {
return newNode;
}
newNode->next = head;
head->prev = newNode;
return newNode;
}
// 在双链表尾部插入节点
DoublyListNode* insertAtDoublyTail(DoublyListNode *head, int data) {
DoublyListNode *newNode = createDoublyNode(data);
if (newNode == NULL) return head;
if (head == NULL) {
return newNode;
}
DoublyListNode *current = head;
while (current->next != NULL) {
current = current->next;
}
current->next = newNode;
newNode->prev = current;
return head;
}
// 在双链表指定位置插入节点
DoublyListNode* insertAtDoublyPosition(DoublyListNode *head, int data, int position) {
if (position < 0) {
printf("位置不能为负数\n");
return head;
}
if (position == 0) {
return insertAtDoublyHead(head, data);
}
DoublyListNode *newNode = createDoublyNode(data);
if (newNode == NULL) return head;
DoublyListNode *current = head;
for (int i = 0; i < position - 1 && current != NULL; i++) {
current = current->next;
}
if (current == NULL) {
printf("位置超出链表长度\n");
free(newNode);
return head;
}
newNode->next = current->next;
newNode->prev = current;
if (current->next != NULL) {
current->next->prev = newNode;
}
current->next = newNode;
return head;
}
// 删除双链表头节点
DoublyListNode* deleteAtDoublyHead(DoublyListNode *head) {
if (head == NULL) {
printf("链表为空\n");
return NULL;
}
DoublyListNode *temp = head;
head = head->next;
if (head != NULL) {
head->prev = NULL;
}
free(temp);
return head;
}
// 删除双链表尾节点
DoublyListNode* deleteAtDoublyTail(DoublyListNode *head) {
if (head == NULL) {
printf("链表为空\n");
return NULL;
}
if (head->next == NULL) {
free(head);
return NULL;
}
DoublyListNode *current = head;
while (current->next != NULL) {
current = current->next;
}
current->prev->next = NULL;
free(current);
return head;
}
// 删除双链表指定值的节点
DoublyListNode* deleteDoublyNode(DoublyListNode *head, int data) {
if (head == NULL) {
printf("链表为空\n");
return NULL;
}
DoublyListNode *current = head;
// 遍历查找要删除的节点
while (current != NULL && current->data != data) {
current = current->next;
}
if (current == NULL) {
printf("未找到值为 %d 的节点\n", data);
return head;
}
// 如果要删除的是头节点
if (current == head) {
head = head->next;
if (head != NULL) {
head->prev = NULL;
}
} else {
current->prev->next = current->next;
if (current->next != NULL) {
current->next->prev = current->prev;
}
}
free(current);
return head;
}
// 打印双链表(向前)
void printDoublyListForward(DoublyListNode *head) {
DoublyListNode *current = head;
printf("双链表(向前): ");
while (current != NULL) {
printf("%d <-> ", current->data);
current = current->next;
}
printf("NULL\n");
}
// 打印双链表(向后)
void printDoublyListBackward(DoublyListNode *head) {
if (head == NULL) {
printf("链表为空\n");
return;
}
// 找到尾节点
DoublyListNode *current = head;
while (current->next != NULL) {
current = current->next;
}
printf("双链表(向后): ");
while (current != NULL) {
printf("%d <-> ", current->data);
current = current->prev;
}
printf("NULL\n");
}
// 获取双链表长度
int getDoublyLength(DoublyListNode *head) {
int length = 0;
DoublyListNode *current = head;
while (current != NULL) {
length++;
current = current->next;
}
return length;
}
// 销毁双链表
void destroyDoublyList(DoublyListNode *head) {
DoublyListNode *current = head;
while (current != NULL) {
DoublyListNode *temp = current;
current = current->next;
free(temp);
}
}
// 双链表演示
void doublyLinkedListDemo() {
printf("\n=== 双链表操作演示 ===\n");
DoublyListNode *head = NULL;
// 插入操作
head = insertAtDoublyHead(head, 10);
head = insertAtDoublyHead(head, 20);
head = insertAtDoublyTail(head, 30);
head = insertAtDoublyTail(head, 40);
head = insertAtDoublyPosition(head, 25, 2);
printDoublyListForward(head);
printDoublyListBackward(head);
printf("链表长度: %d\n", getDoublyLength(head));
// 删除操作
head = deleteDoublyNode(head, 25);
printf("删除 25 后: ");
printDoublyListForward(head);
head = deleteAtDoublyHead(head);
printf("删除头节点后: ");
printDoublyListForward(head);
head = deleteAtDoublyTail(head);
printf("删除尾节点后: ");
printDoublyListForward(head);
destroyDoublyList(head);
}
int main() {
singlyLinkedListDemo();
doublyLinkedListDemo();
return 0;
}
循环链表实现
循环单链表
c
#include <stdio.h>
#include <stdlib.h>
#include <stdbool.h>
// 循环单链表节点定义
typedef struct CircularListNode {
int data;
struct CircularListNode *next;
} CircularListNode;
// 创建新节点
CircularListNode* createCircularNode(int data) {
CircularListNode *newNode = (CircularListNode*)malloc(sizeof(CircularListNode));
if (newNode == NULL) {
printf("内存分配失败\n");
return NULL;
}
newNode->data = data;
newNode->next = newNode; // 指向自己,形成循环
return newNode;
}
// 在循环链表头部插入节点
CircularListNode* insertAtCircularHead(CircularListNode *last, int data) {
CircularListNode *newNode = createCircularNode(data);
if (newNode == NULL) return last;
if (last == NULL) {
return newNode;
}
newNode->next = last->next;
last->next = newNode;
return last;
}
// 在循环链表尾部插入节点
CircularListNode* insertAtCircularTail(CircularListNode *last, int data) {
CircularListNode *newNode = createCircularNode(data);
if (newNode == NULL) return last;
if (last == NULL) {
return newNode;
}
newNode->next = last->next;
last->next = newNode;
return newNode; // 新的尾节点
}
// 打印循环链表
void printCircularList(CircularListNode *last) {
if (last == NULL) {
printf("循环链表为空\n");
return;
}
CircularListNode *current = last->next;
printf("循环链表: ");
do {
printf("%d -> ", current->data);
current = current->next;
} while (current != last->next);
printf("(回到起点)\n");
}
// 约瑟夫环问题
void josephusProblem(int n, int k) {
printf("\n=== 约瑟夫环问题: n=%d, k=%d ===\n", n, k);
if (n <= 0 || k <= 0) {
printf("参数错误\n");
return;
}
// 创建循环链表
CircularListNode *last = NULL;
for (int i = 1; i <= n; i++) {
last = insertAtCircularTail(last, i);
}
printf("初始人员: ");
printCircularList(last);
CircularListNode *current = last->next;
CircularListNode *prev = last;
printf("淘汰顺序: ");
while (current->next != current) {
// 数到第k个人
for (int i = 1; i < k; i++) {
prev = current;
current = current->next;
}
// 淘汰当前人员
printf("%d ", current->data);
prev->next = current->next;
CircularListNode *temp = current;
current = current->next;
free(temp);
}
printf("\n幸存者: %d\n", current->data);
free(current);
}
// 循环链表演示
void circularLinkedListDemo() {
printf("\n=== 循环单链表操作演示 ===\n");
CircularListNode *last = NULL;
// 插入操作
last = insertAtCircularHead(last, 10);
last = insertAtCircularHead(last, 20);
last = insertAtCircularTail(last, 30);
last = insertAtCircularTail(last, 40);
printCircularList(last);
// 约瑟夫环问题演示
josephusProblem(5, 2);
josephusProblem(7, 3);
}
int main() {
singlyLinkedListDemo();
doublyLinkedListDemo();
circularLinkedListDemo();
return 0;
}
链表的应用实例
多项式相加
c
#include <stdio.h>
#include <stdlib.h>
// 多项式项节点
typedef struct PolyNode {
int coeff; // 系数
int exp; // 指数
struct PolyNode *next;
} PolyNode;
// 创建多项式项
PolyNode* createPolyTerm(int coeff, int exp) {
PolyNode *term = (PolyNode*)malloc(sizeof(PolyNode));
term->coeff = coeff;
term->exp = exp;
term->next = NULL;
return term;
}
// 插入多项式项(按指数降序)
PolyNode* insertPolyTerm(PolyNode *head, int coeff, int exp) {
PolyNode *newTerm = createPolyTerm(coeff, exp);
if (head == NULL || exp > head->exp) {
newTerm->next = head;
return newTerm;
}
PolyNode *current = head;
while (current->next != NULL && current->next->exp > exp) {
current = current->next;
}
// 如果指数相同,合并同类项
if (current->next != NULL && current->next->exp == exp) {
current->next->coeff += coeff;
free(newTerm);
// 如果系数为0,删除该项
if (current->next->coeff == 0) {
PolyNode *temp = current->next;
current->next = current->next->next;
free(temp);
}
return head;
}
newTerm->next = current->next;
current->next = newTerm;
return head;
}
// 多项式相加
PolyNode* addPolynomials(PolyNode *poly1, PolyNode *poly2) {
PolyNode *result = NULL;
PolyNode *p1 = poly1, *p2 = poly2;
while (p1 != NULL && p2 != NULL) {
if (p1->exp == p2->exp) {
int sumCoeff = p1->coeff + p2->coeff;
if (sumCoeff != 0) {
result = insertPolyTerm(result, sumCoeff, p1->exp);
}
p1 = p1->next;
p2 = p2->next;
} else if (p1->exp > p2->exp) {
result = insertPolyTerm(result, p1->coeff, p1->exp);
p1 = p1->next;
} else {
result = insertPolyTerm(result, p2->coeff, p2->exp);
p2 = p2->next;
}
}
// 添加剩余项
while (p1 != NULL) {
result = insertPolyTerm(result, p1->coeff, p1->exp);
p1 = p1->next;
}
while (p2 != NULL) {
result = insertPolyTerm(result, p2->coeff, p2->exp);
p2 = p2->next;
}
return result;
}
// 打印多项式
void printPolynomial(PolyNode *head) {
if (head == NULL) {
printf("0\n");
return;
}
PolyNode *current = head;
while (current != NULL) {
if (current->coeff > 0 && current != head) {
printf("+ ");
}
if (current->exp == 0) {
printf("%d", current->coeff);
} else if (current->exp == 1) {
printf("%dx", current->coeff);
} else {
printf("%dx^%d", current->coeff, current->exp);
}
if (current->next != NULL) {
printf(" ");
}
current = current->next;
}
printf("\n");
}
// 多项式演示
void polynomialDemo() {
printf("\n=== 多项式相加演示 ===\n");
// 创建多项式1: 3x^3 + 2x^2 + 5x
PolyNode *poly1 = NULL;
poly1 = insertPolyTerm(poly1, 3, 3);
poly1 = insertPolyTerm(poly1, 2, 2);
poly1 = insertPolyTerm(poly1, 5, 1);
// 创建多项式2: 4x^3 + 3x^2 + 2x + 1
PolyNode *poly2 = NULL;
poly2 = insertPolyTerm(poly2, 4, 3);
poly2 = insertPolyTerm(poly2, 3, 2);
poly2 = insertPolyTerm(poly2, 2, 1);
poly2 = insertPolyTerm(poly2, 1, 0);
printf("多项式1: ");
printPolynomial(poly1);
printf("多项式2: ");
printPolynomial(poly2);
PolyNode *result = addPolynomials(poly1, poly2);
printf("相加结果: ");
printPolynomial(result);
// 释放内存
// 实际使用时需要实现destroyPolynomial函数
}
LRU缓存实现
c
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define CACHE_SIZE 5
// LRU缓存节点
typedef struct LRUNode {
int key;
int value;
struct LRUNode *prev;
struct LRUNode *next;
} LRUNode;
// LRU缓存结构
typedef struct {
LRUNode *head;
LRUNode *tail;
int size;
int capacity;
} LRUCache;
// 创建LRU缓存节点
LRUNode* createLRUNode(int key, int value) {
LRUNode *node = (LRUNode*)malloc(sizeof(LRUNode));
node->key = key;
node->value = value;
node->prev = NULL;
node->next = NULL;
return node;
}
// 创建LRU缓存
LRUCache* createLRUCache(int capacity) {
LRUCache *cache = (LRUCache*)malloc(sizeof(LRUCache));
cache->head = NULL;
cache->tail = NULL;
cache->size = 0;
cache->capacity = capacity;
return cache;
}
// 将节点移动到头部(最近使用)
void moveToHead(LRUCache *cache, LRUNode *node) {
if (node == cache->head) return;
// 从原位置移除
if (node->prev) node->prev->next = node->next;
if (node->next) node->next->prev = node->prev;
// 更新尾指针
if (node == cache->tail) {
cache->tail = node->prev;
}
// 移动到头部
node->next = cache->head;
node->prev = NULL;
if (cache->head) {
cache->head->prev = node;
}
cache->head = node;
// 如果缓存为空,更新尾指针
if (cache->tail == NULL) {
cache->tail = node;
}
}
// 从缓存中获取值
int get(LRUCache *cache, int key) {
LRUNode *current = cache->head;
while (current != NULL) {
if (current->key == key) {
// 找到节点,移动到头部
moveToHead(cache, current);
return current->value;
}
current = current->next;
}
return -1; // 未找到
}
// 向缓存中插入值
void put(LRUCache *cache, int key, int value) {
// 检查是否已存在
LRUNode *current = cache->head;
while (current != NULL) {
if (current->key == key) {
current->value = value;
moveToHead(cache, current);
return;
}
current = current->next;
}
// 创建新节点
LRUNode *newNode = createLRUNode(key, value);
// 如果缓存已满,删除尾节点
if (cache->size == cache->capacity) {
LRUNode *tail = cache->tail;
cache->tail = tail->prev;
if (cache->tail) {
cache->tail->next = NULL;
} else {
cache->head = NULL;
}
free(tail);
cache->size--;
}
// 插入新节点到头部
newNode->next = cache->head;
if (cache->head) {
cache->head->prev = newNode;
}
cache->head = newNode;
// 更新尾指针
if (cache->tail == NULL) {
cache->tail = newNode;
}
cache->size++;
}
// 打印LRU缓存
void printLRUCache(LRUCache *cache) {
printf("LRU缓存: ");
LRUNode *current = cache->head;
while (current != NULL) {
printf("(%d:%d) ", current->key, current->value);
current = current->next;
}
printf("\n");
}
// LRU缓存演示
void lruCacheDemo() {
printf("\n=== LRU缓存演示 (容量: %d) ===\n", CACHE_SIZE);
LRUCache *cache = createLRUCache(CACHE_SIZE);
// 插入数据
for (int i = 1; i <= 6; i++) {
put(cache, i, i * 10);
printf("插入 (%d:%d): ", i, i * 10);
printLRUCache(cache);
}
// 访问数据
printf("访问 key=3: %d\n", get(cache, 3));
printLRUCache(cache);
printf("访问 key=2: %d\n", get(cache, 2));
printLRUCache(cache);
// 插入新数据
put(cache, 7, 70);
printf("插入 (7:70): ");
printLRUCache(cache);
// 释放内存
// 实际使用时需要实现destroyLRUCache函数
}
链表的性能优化
使用头节点简化操作
c
#include <stdio.h>
#include <stdlib.h>
// 带头节点的单链表
typedef struct HeadListNode {
int data;
struct HeadListNode *next;
} HeadListNode;
typedef struct {
HeadListNode *head; // 头节点(不存储实际数据)
int size;
} LinkedList;
// 初始化带头节点的链表
LinkedList* createLinkedList() {
LinkedList *list = (LinkedList*)malloc(sizeof(LinkedList));
list->head = (HeadListNode*)malloc(sizeof(HeadListNode));
list->head->next = NULL;
list->size = 0;
return list;
}
// 在指定位置插入(带头节点简化了边界处理)
void insertWithHead(LinkedList *list, int data, int position) {
if (position < 0 || position > list->size) {
printf("位置无效\n");
return;
}
HeadListNode *newNode = (HeadListNode*)malloc(sizeof(HeadListNode));
newNode->data = data;
HeadListNode *current = list->head;
for (int i = 0; i < position; i++) {
current = current->next;
}
newNode->next = current->next;
current->next = newNode;
list->size++;
}
// 打印带头节点的链表
void printLinkedList(LinkedList *list) {
printf("链表: ");
HeadListNode *current = list->head->next;
while (current != NULL) {
printf("%d -> ", current->data);
current = current->next;
}
printf("NULL\n");
}
void headNodeDemo() {
printf("\n=== 带头节点的链表演示 ===\n");
LinkedList *list = createLinkedList();
insertWithHead(list, 10, 0);
insertWithHead(list, 20, 0);
insertWithHead(list, 30, 1);
insertWithHead(list, 40, 3);
printLinkedList(list);
printf("链表大小: %d\n", list->size);
// 释放内存
// 实际使用时需要实现destroyLinkedList函数
}

