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;
}
双链表实现
双链表基本操作
#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;
}
循环链表实现
循环单链表
#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;
}
链表的应用实例
多项式相加
#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 + 5xPolyNode *poly1 = NULL;poly1 = insertPolyTerm(poly1, 3, 3);poly1 = insertPolyTerm(poly1, 2, 2);poly1 = insertPolyTerm(poly1, 5, 1);// 创建多项式2: 4x^3 + 3x^2 + 2x + 1PolyNode *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缓存实现
#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函数
}
链表的性能优化
使用头节点简化操作
#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函数
}


