1.首先明确一下单链表的特点,单链表的数据不像顺序表那样在物理空间上连续,而是分布在内存的各个地方,相较于顺序表随机访问的便捷性,链表的增删改更为方便,现在来看看例题
2.双指针算法的典型应用:多项式相加
多项式相加 【问题描述】编写一个程序用单链表存储多项式,并实现两个一元多项式A与B相加的函数。A,B刚开始是无序的,A与B之和按降序排列。例如: 【输入样例】 【输出样例】 6.4 3 【样例说明】 【评分标准】必须用链表实现 这道题的方法非常典型,首先将数据存在两个链表上,根据双指针的算法,两个链表都需要进行排序以实现单调性,然后同时移动双指针,第一个链表的系数值大于第二个链表的系数值或者相反,则把该节点后插到新链表的后面,如果等于就相加并同时移动,循环结束条件为一个表遍历完,后续只需把没有遍历完的表接到新链表后面即可 |
3.正难则反:找倒数第k个节点
输出单链表倒数第K个结点值
【问题描述】输入一个单向链表,输出该链表中倒数第k个结点,链表的最后一个结点是倒数第1个节点。
【输入形式】输入第一位为K值,其后接一串以空格分隔的整型值,以0结束输入。
【输出形式】输出为倒数第K个结点的值,若无,则输出Not Found
【样例输入】3 13 45 54 32 1 4 98 2 0
【样例输出】4
【样例说明】K值为3,则输出链表倒数第3个结点的值,为4;数据输入间以空格隔开
【评分标准】本题要综合输出正确性及使用的数据结构。需由输入数据构建单链表。不使用链表的将不得分。
这道题就是传说中的正难则反,找倒数第k个节点,就是不处理倒数第k个节点,处理正数第n-k个节点
#include <stdio.h>
#include <stdlib.h>
// 定义链表节点结构体
typedef struct ListNode {
int val;
struct ListNode* next;
} ListNode;
// 创建链表节点
ListNode* createNode(int val) {
ListNode* newNode = (ListNode*)malloc(sizeof(ListNode));
if (!newNode) {
perror("Memory allocation failed");
exit(EXIT_FAILURE);
}
newNode->val = val;
newNode->next = NULL;
return newNode;
}
// 向链表尾部添加节点
void appendNode(ListNode** head, int val) {
ListNode* newNode = createNode(val);
if (*head == NULL) {
*head = newNode;
}
else {
ListNode* current = *head;
while (current->next != NULL) {
current = current->next;
}
current->next = newNode;
}
}
// 找到链表的倒数第k个节点
ListNode* findKthToTail(ListNode* head, int k) {
if (head == NULL || k <= 0) {
return NULL;
}
ListNode* fast = head, * slow = head;
// 首先让快指针前进k步
for (int i = 0; i < k - 1; ++i) {
if (fast->next != NULL) {
fast = fast->next;
}
else {
// 如果快指针在前进k步后到达链表尾部,说明k大于链表长度
return NULL;
}
}
// 然后快慢指针同时前进,直到快指针到达链表尾部
while (fast->next != NULL) {
fast = fast->next;
slow = slow->next;
}
// 此时慢指针指向倒数第k个节点
return slow;
}
int main() {
int k, val;
ListNode* head = NULL;
// 读取K值
scanf("%d", &k);
// 读取链表值,以0为结束标志
while (scanf("%d", &val) == 1 && val != 0) {
appendNode(&head, val);
}
// 查找倒数第k个节点
ListNode* kthNode = findKthToTail(head, k);
// 输出结果
if (kthNode) {
printf("%d\n", kthNode->val);
}
else {
printf("Not Found\n");
}
// 释放链表内存
ListNode* current = head;
while (current) {
ListNode* temp = current;
current = current->next;
free(temp);
}
return 0;
}
4.环形链表的经典问题:约瑟夫问题
. | 约瑟夫环问题 【问题描述】用不带头结点的单向循环链表解决约瑟夫环问题。 【输入形式】输入n和m的值,其中n为总人数,m为报数的密码 【输出形式】胜利者编号,也就是最后一个离开队伍的人 【样例输入】6 4 【样例输出】5 |
---|
最后来看一看重中之重,各种链表的基本操作