单链表应用:双指针【快慢指针】

2019\] (15 分)已知一个带有表头节点的单链表,节点结构为 | data | link | |------|------| 假设该链表只给出了头指针 `list`。在不改变链表的前提下,请设计一个尽可能高效的算法,查找链表中倒数第 `k` 个位置上的结点(`k` 为正整数)。若查找成功,算法输出该节点的 `data` 域的值,并返回 1;否则,只返回 0。要求: 1)描述算法的基本思想; 2)描述算法的详细实现步骤; 3)根据设计思想和实现步骤,采用程序设计语言描述算法(使用 C、C++、或 Java 语言实现),关键之处请给出简要注释。 #### 1)算法基本思想 采用**双指针(快慢指针)法**,在不改变链表结构、仅遍历一次链表的前提下,高效找到倒数第 k 个结点: * 定义两个指针 `fast` 和 `slow`,初始均指向表头节点。 * 先让 `fast` 指针向前移动 `k` 步,使两指针之间保持 `k` 个结点的距离。 * 之后 `fast` 和 `slow` 同时向后移动,当 `fast` 到达链表末尾时,`slow` 恰好指向倒数第 k 个结点。 * 若 `fast` 在移动 k 步的过程中提前到达末尾,说明 k 值超过链表长度,查找失败。 *** ** * ** *** #### 2)详细实现步骤 1. **初始化** :定义指针 `fast`、`slow`,均指向链表头节点 `list`。 2. **前向移动 k 步** :循环移动 `fast` 指针,共 k 次;若循环中 `fast` 变为 `NULL`,说明 k 大于链表长度,返回 0。 3. **同步移动** :当 `fast` 不为空时,`fast` 和 `slow` 同时向后移动,直到 `fast` 指向链表尾节点的下一个位置(`NULL`)。 4. **结果处理** :此时 `slow` 指向倒数第 k 个结点,输出其 `data` 域值,返回 1;若步骤 2 中提前结束,返回 0。 *** ** * ** *** #### 3)C 语言实现代码 核心代码 ```cpp // 链表结点结构定义(需在函数外声明) typedef struct Node { int data; struct Node *link; } Node; // 核心函数:查找单链表倒数第k个结点 // 参数:list-链表头指针,k-倒数第k个位置 // 返回:查找成功返回1,失败返回0;成功时输出目标结点data值 int findKthFromEnd(Node *list, int k) { // 1. 边界条件校验:空链表、k非正均直接失败 if (list == NULL || k <= 0) return 0; // 2. 初始化快慢指针 Node *fast = list, *slow = list; // 3. 快指针先移动k步,判断k是否超出链表长度 for (int i = 0; i < k; i++) { if (fast == NULL) return 0; // k超过链表长度,返回失败 fast = fast->link; } // 4. 快慢指针同步移动,直到快指针到链表末尾 while (fast != NULL) { fast = fast->link; slow = slow->link; } // 5. 找到目标结点,输出data并返回成功 printf("%d\n", slow->data); return 1; } ``` 完整代码 ```cpp #include #include // 定义链表结点结构 typedef struct Node { int data; struct Node *link; } Node; // 查找倒数第k个结点的算法 int findKthFromEnd(Node *list, int k) { if (list == NULL || k <= 0) { // 空链表或k不合法 return 0; } Node *fast = list; Node *slow = list; // fast指针先移动k步 for (int i = 0; i < k; i++) { if (fast == NULL) { // k超过链表长度 return 0; } fast = fast->link; } // 同步移动fast和slow,直到fast到达末尾 while (fast != NULL) { fast = fast->link; slow = slow->link; } // slow指向倒数第k个结点,输出data并返回1 printf("%d\n", slow->data); return 1; } // 辅助函数:创建新结点 Node* createNode(int data) { Node *newNode = (Node*)malloc(sizeof(Node)); newNode->data = data; newNode->link = NULL; return newNode; } // 辅助函数:尾插法构建链表 void append(Node *head, int data) { Node *cur = head; while (cur->link != NULL) { cur = cur->link; } cur->link = createNode(data); } // 测试主函数 int main() { // 创建带头节点的链表 Node *list = createNode(0); // 表头节点data无实际意义 append(list, 1); append(list, 2); append(list, 3); append(list, 4); append(list, 5); int k = 2; int res = findKthFromEnd(list, k); printf("返回值: %d\n", res); // 预期输出4,返回1 return 0; } ``` **算法分析**: * 时间复杂度:O(n),仅遍历链表一次。 * 空间复杂度:O(1),仅使用两个额外指针,无额外存储空间。 * 满足题目 "不改变链表、尽可能高效" 的要求。 #### 总结 1. 核心逻辑:通过**快慢指针**构建 k 步距离,同步移动后慢指针定位倒数第 k 个结点; 2. 关键校验:覆盖空链表、k≤0、k 超链表长度三类失败场景; 3. 效率特性:时间复杂度 O (n)、空间复杂度 O (1),满足题目 "高效且不修改链表" 的要求。

相关推荐
今儿敲了吗2 小时前
41| 快速乘
数据结构·c++·笔记·学习·算法
ysa0510302 小时前
树的定向(dfs并查集贪心)
数据结构·c++·笔记·算法·深度优先·图论
仰泳的熊猫3 小时前
题目2281:蓝桥杯2018年第九届真题-次数差
数据结构·c++·算法·蓝桥杯
blackicexs3 小时前
第九周第一天
数据结构·算法
hoiii1873 小时前
MATLAB模拟ADS-B数据解码与信号处理整体流程
数据结构·matlab·信号处理
AMoon丶4 小时前
Golang--锁
linux·开发语言·数据结构·后端·算法·golang·mutex
李日灐4 小时前
改造红黑树实现封装 map/set:感受C++ 标准容器的精妙设计与底层实现
开发语言·数据结构·c++·后端·算法·红黑树
李日灐4 小时前
【优选算法1】双指针经典算法题
数据结构·c++·后端·算法·刷题·双指针
故事和你914 小时前
sdut-程序设计基础Ⅰ-期末测试(重现)
大数据·开发语言·数据结构·c++·算法·蓝桥杯·图论