【数据结构】关于链表的面试题

一、单链表逆置

1、法一

思路:

通过两个辅助指针 p和 q,在遍历链表时逐个反转指针方向。

  • p初始化为 第一个有效节点,用于遍历原链表;q初始化为 NULL,用于临时保存 p 的下一个节点。
  • plist->next 被置为 NULL,表示逆置后的链表初始为空(头节点指向空)。
  • 每次迭代中:q 保存 p 的下一个节点(防止断链)。

  • 将 p 的 next 指向当前逆置链表的头部(plist->next)。
  • 更新头节点的 next 指向 p,使 p 成为新链表的第一个节点。
  • p 移动到 q(原链表的下一个节点),继续循环。
  • 终止条件
    当 p 为 NULL 时,说明原链表已全部遍历完毕,逆置完成。

关键点说明:

头插法:通过每次将当前节点插入头节点之后,实现链表的逆置。

断链处理q 临时保存 p->next,避免修改 p->next 后丢失后续节点。

时间复杂度:O(n),仅需一次遍历。

空间复杂度:O(1),仅使用固定数量的指针变量。

示例流程:

假设原链表为 1 -> 2 -> 3 -> NULL,头节点为 H

  1. 初始:H -> 1 -> 2 -> 3p 指向 1
  2. 第一次循环后:H -> 1 -> NULLp 指向 2
  3. 第二次循环后:H -> 2 -> 1 -> NULLp 指向 3
  4. 第三次循环后:H -> 3 -> 2 -> 1 -> NULLp 为 NULL,退出循环。

代码实现:

//逆置单链表
void Reverse_list(Node* plist) {assert(plist != NULL);assert(plist->next != NULL);assert(plist->next->next != NULL);Node* p = plist->next;Node* q = NULL;plist->next = NULL;while (p != NULL) {q = p->next;p->next = plist->next;plist->next = p;p = q;}
}

2、法二

思路:

  1. 指针初始化
    p初始化为第一个有效节点(plist->next),q初始化为第二个节点(p->next)。p->next被置为NULL,表示反转后的新链表的尾节点。

  2. 迭代反转

    • r保存q的下一个节点(q->next),防止断链。
    • q->next指向p,完成局部反转。
    • 指针pq分别向后移动一位,继续处理后续节点。
    • 循环终止时,p指向原链表的最后一个节点,即反转后的新链表头。
  3. 更新头节点
    plist->next = p;将头节点的next指向反转后的新链表头。

示例流程

假设链表为 头节点 -> 1 -> 2 -> 3 -> NULL

  1. 初始状态:
    p = 1, q = 2, 1->next = NULL
  2. 第一次循环:
    r = 3, 2->next = 1, p = 2, q = 3
  3. 第二次循环:
    r = NULL, 3->next = 2, p = 3, q = NULL
  4. 结束循环,头节点->next = 3,得到 头节点 -> 3 -> 2 -> 1 -> NULL

关键点

  • 三指针协同pqr分别用于记录当前节点、下一个节点及临时保存节点,确保反转过程中不断链。
  • 头节点处理:传入的plist通常为不存储数据的头节点,反转后仍需保持头节点指向新链表头。
  • 时间复杂度:O(n),仅需遍历一次链表;空间复杂度O(1),仅使用固定数量的指针。

边界情况

若链表为空或仅有一个节点,断言会触发错误。实际应用中需根据需求调整断言条件或添加特殊处理。

​代码实现:

void Reverse_list2(Node* plist) {assert(plist != NULL);assert(plist->next != NULL);assert(plist->next->next != NULL);Node* p = plist->next;Node* q = p->next;Node* r = NULL;p->next = NULL;while (q != NULL) {r = q->next;q->next = p;p = q;q = r;}plist->next = p;
}

二、如何判断两个单链表存在交点

思路:两个链表的指针,分别跑到自身的尾节点,判断是否为同一个尾节点

 代码实现:

bool Intersect(Node* plist1, Node* plist2) {assert(plist1 != NULL);assert(plist2 != NULL);Node* p = plist1;Node* q = plist2;for (; p->next != NULL; p = p->next);for (; q->next != NULL; q = q->next);return p == q;
}

 三、获取两个单链表的相交点

思路:

该算法的目标是找到两个单链表的相交节点(如果有)。核心思路是通过对齐两个链表的起始位置,然后同步遍历,直到找到相同节点。

步骤分解

  1. 检查链表是否相交
    调用Intersect(plist1, plist2)函数判断两链表是否相交。若不相交,直接返回NULL

  2. 计算链表长度
    通过Get_Length函数获取两个链表的长度len1len2,用于后续对齐操作。

  3. 对齐起始位置
    将较长链表的指针p向后移动|len1 - len2|步,使得剩余未遍历部分与较短链表的长度一致。此时pq(较短链表的头指针)处于同一起跑线。

  4. 同步遍历寻找交点
    同时移动pq指针,逐个节点比较。当p == q时,当前节点即为相交节点,返回该节点。

关键点

  • 时间复杂度:O(m+n),其中m和n为两链表长度。需遍历两次链表(计算长度+同步查找)。
  • 空间复杂度:O(1),仅使用常数级额外空间。
  • 边界条件:处理两链表长度差为0时,直接进入同步遍历阶段。

示例说明

假设链表1为A->B->C->D,链表2为E->F->C->D(相交于节点C):

  1. len1=4len2=4(长度差为0,无需对齐)。
  2. 同步遍历p(链表1)和q(链表2),第三次移动时pq均指向C,返回C

代码实现:

Node* Get_Intersect_Node(Node* plist1, Node* plist2) {bool tag = Intersect(plist1, plist2);if (!tag) return NULL;int len1 = Get_Length(plist1);int len2 = Get_Length(plist2);Node* p = len1 >= len2 ? plist1 : plist2;Node* q = len1 >= len2 ? plist2 : plist1;//此时p指向较长的单链表的辅助结点,q指向较长的单链表的辅助结点for (int i = 0; i < abs(len1 - len2); i++) {p = p->next;}//pq同步向后走,直到相遇while (p != q) {p = p->next;q = q->next;}return p;
}

 

 

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。
如若转载,请注明出处:http://www.pswp.cn/web/89733.shtml
繁体地址,请注明出处:http://hk.pswp.cn/web/89733.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

LVS(Linux virual server)

LVS&#xff08;Linux virual server&#xff09; 系统性能扩展方式 Scale UP&#xff1a;增强单台服务器性能&#xff0c;适合单体应用&#xff0c;但有硬件限制。 Scale Out&#xff1a;增加服务器数量&#xff0c;适合分布式和集群系统&#xff0c;可灵活扩展。 集群&#x…

在 ASP.NET Core 和 JavaScript 中配置 WebSocket

在本文中&#xff0c;我们将了解 WebSocket&#xff0c;并逐步讲解如何在客户端配置 WebSocket 并与服务器通信。首先&#xff0c;让我们先来了解一下“ WebSocket ”。什么是 WebSocketWebSocket 是一种协议&#xff0c;它提供了一种通过持久连接在客户端和服务器之间交换数据…

车载刷写框架 --- 关于私有节点刷写失败未报引起的反思

我是穿拖鞋的汉子,魔都中坚持长期主义的汽车电子工程师。 老规矩,分享一段喜欢的文字,避免自己成为高知识低文化的工程师: 做到欲望极简,了解自己的真实欲望,不受外在潮流的影响,不盲从,不跟风。把自己的精力全部用在自己。一是去掉多余,凡事找规律,基础是诚信;二是…

ABP VNext + GitHub Actions:CI/CD 全流程自动化

&#x1f31f; ABP VNext GitHub Actions&#xff1a;CI/CD 全流程自动化 &#x1f4da; 目录&#x1f31f; ABP VNext GitHub Actions&#xff1a;CI/CD 全流程自动化&#x1f929; TL;DR&#x1f504; 全局流程概览1️⃣ 准备工作与项目结构1.1 &#x1f6e0;️ 工具链与 S…

Elasticsearch 重命名索引

作者&#xff1a;来自 Elastic Alex Salgado 学习如何使用四种实用方法在 Elasticsearch 中重命名索引。 想获得 Elastic 认证&#xff1f;看看下一期 Elasticsearch Engineer 培训什么时候开始&#xff01; Elasticsearch 拥有丰富的新功能&#xff0c;帮助你根据使用场景构建…

高通8255 Android Virtio Virtio-SPI 配置方法

目录 一&#xff1a;VirtIO和Passthrough的区别 二&#xff1a;配置逻辑 三&#xff1a;配置方法 步骤一&#xff1a;QNX SPI资源配置 & 测试 配置 测试 步骤二&#xff1a;BE配置 &测试 配置 测试 步骤三&#xff1a;Hypervisor配置 配置 测试 步骤四&…

从零手写红黑树(C++实现详解)

目录 一、红黑树概述 二、红黑树节点设计 (1)枚举红黑 &#xff08;2&#xff09;红黑树的节点设计 三、红黑树核心实现:Insert 1.首先将节点遍历到对应位置创建对应节点并插入到二叉搜索树对应的位置 2.本文重点的重点 &#xff08;1&#xff09;parent为黑时直接插入即…

【黄山派-SF32LB52】—硬件原理图学习笔记

目录 一、硬件介绍 二、芯片主控 1.模组介绍 2.原理图介绍 3.模组供电电路 三、电源转换部分 1.OVP过压保护电路 2.CHG充电电路 3.系统电源桥接电路 4.LDO电路 四、Debug电路 1.一键下载电路 五、QSPI屏幕 六、SD卡 七、AUDIO音频 八、GPIO电路 1.按键部分…

从五次方程到计算机:数学抽象如何塑造现代计算

引言 数学的发展往往始于一个具体的问题&#xff0c;而后在寻求解答的过程中&#xff0c;催生出深刻的抽象理论。从五次方程的求解到抽象代数&#xff0c;再到范畴论和λ演算&#xff0c;最终影响图灵机和现代计算机的设计&#xff0c;这一历程展现了数学如何从实际问题演变为通…

剧本杀小程序开发:科技赋能,重塑推理娱乐新形态

在科技飞速发展的今天&#xff0c;各个行业都在积极探索与科技的融合&#xff0c;以实现创新发展。剧本杀行业也不例外&#xff0c;剧本杀小程序的开发&#xff0c;正是科技赋能传统娱乐的生动体现&#xff0c;它重塑了推理娱乐的新形态&#xff0c;为玩家带来了前所未有的游戏…

机器学习sklearn入门:归一化和标准化

bg&#xff1a;归一化&#xff08;Normalization&#xff09;通常指将数据按比例缩放至某个特定范围&#xff0c;但具体范围并不一定是固定的 0到1。标准化是将数据转换成均值为0&#xff0c;标准差为1的分布。使用场景&#xff1a;用归一化&#xff1a;需要严格限定范围&#…

【Project】kafka+flume+davinci广告点击实时分析系统

一、项目需求分析 某电商平台需实现广告实时点击分析系统&#xff0c;核心需求为实时统计以下内容的Top10&#xff1a; 各个广告的点击量各个省份的广告点击量各个城市的广告点击量 通过实时掌握广告投放效果&#xff0c;为广告投放策略调整和大规模投入提供依据&#xff0c;以…

JAVA后端开发——success(data) vs toAjax(rows): 何时用

toAjax(int rows)用途&#xff1a;用于不返回任何数据的 “写” 操作&#xff08;增、删、改&#xff09;。工作原理&#xff1a;它只接收一个 int 类型的参数&#xff08;通常是数据库操作影响的行数&#xff09;。它只关心这个数字是不是大于0&#xff0c;然后返回一个通用的…

pdf格式怎么提取其中一部分张页?

想从PDF里提取几个页面&#xff0c;办法还挺多的&#xff0c;下面给你唠唠常见的几种&#xff0c;保准你一看就懂。一、用专业PDF编辑软件提取 像Adobe Acrobat&#xff0c;这可是PDF编辑界的“老手”了。你先把要处理的PDF文件在Adobe Acrobat里打开&#xff0c;接着找到菜单栏…

Spring监听器

1、监听器的原理 ApplicationListener<T>是Spring框架中基于观察者模式实现的事件监听接口&#xff0c;用于监听应用程序中特定类型的事件。该接口是一个函数式接口&#xff0c;从Spring 4.2开始支持Lambda表达式实现。 接口定义如下&#xff1a; FunctionalInterface …

基于Rust游戏引擎实践(Game)

Rust游戏引擎推荐 以下是一些流行的Rust游戏引擎,适用于不同开发需求: Bevy 特点:数据驱动、模块化设计,支持ECS架构,适合初学者和复杂项目。 适用场景:2D/3D游戏、原型开发。 Amethyst 特点:成熟的ECS框架,支持多线程,社区活跃。 适用场景:大型游戏或高性能应用。…

PyTorch 数据加载实战:从 CSV 到图像的全流程解析

目录 一、PyTorch 数据加载的核心组件 1.1 Dataset 类的核心方法 1.2 DataLoader 的作用 二、加载 CSV 数据实战 2.1 自定义 CSV 数据集 2.2 使用 TensorDataset 快速加载 三、加载图像数据实战 3.1 自定义图像数据集 3.2 使用 ImageFolder 快速加载 四、加载官方数据…

程序人生,开启2025下半年

时光匆匆&#xff0c;2025年已然过去一半。转眼来到了7月份。 回望过去上半年&#xff0c;可能你也经历了职场的浮沉、生活的跌宕、家庭的变故。 而下半年&#xff0c;生活依旧充满了各种变数。 大环境的起起伏伏、生活节奏的加快&#xff0c;都让未来的不确定性愈发凸显。 在这…

在 .NET Core 中创建 Web Socket API

要在 ASP.NET Core 中创建 WebSocket API&#xff0c;您可以按照以下步骤操作&#xff1a;设置新的 ASP.NET Core 项目打开 Visual Studio 或您喜欢的 IDE。 创建一个新的 ASP.NET Core Web 应用程序项目。 选择API模板&#xff0c;因为这将成为您的 WebSocket API 的基础。在启…

Python 之地址编码识别

根据输入地址&#xff0c;利用已有的地址编码文件&#xff0c;构造处理规则策略识别地址的编码。 lib/address.json 地址编码文件&#xff08;这个文件太大&#xff0c;博客里放不下&#xff0c;需要的话可以到 gitcode 仓库获取&#xff1a;https://gitcode.com/TomorrowAndT…