C++面试宝典第4题:合并链表

题目

        有一个链表,其节点声明如下:

struct TNode
{int nData;struct TNode *pNext;TNode(int x) : nData(x), pNext(NULL) {}
};

        现给定两个按升序排列的单链表pA和pB,请编写一个函数,实现这两个单链表的合并。合并后,仍然按升序进行排列。比如:单链表pA为1->3->5->6->8,单链表pB为2->3->7,则合并后返回的链表为1->2->3->3->5->6->7->8。函数的声明如下:

          TNode *MergeList(TNode *pA, TNode *pB);

解析

        这道题主要考察应聘者对链表等数据结构的理解能力,在面试中比较常见。一般有两种解法:一种是使用递归函数来实现,另一种是使用链表遍历来实现。

        先来看第一种解法,使用递归函数来实现。当链表pA为NULL时,直接返回链表pB即可。当链表pB为NULL时,直接返回链表pA即可。当链表pA和pB均不为NULL时,则比较链表首部的元素,若pA->nData小于pB->nData,则返回pA,并让pA->pNext指向递归函数MergeList(pA->pNext, pB)的返回值。下面,我们给出了这道题的示例代码。

#include<iostream>
using namespace std;struct TNode
{int nData;struct TNode *pNext;TNode(int x) : nData(x), pNext(NULL) {}
};// 插入新节点到链表尾部
TNode *AppendNode(TNode *pTail, int nData)
{  TNode *pNodeNew = new TNode(nData);pTail->pNext = pNodeNew;return pNodeNew;
}// 打印链表
void PrintList(TNode *pNode)
{while (pNode != NULL){cout << pNode->nData;pNode = pNode->pNext;if (pNode != NULL){cout << "->";}else{cout << endl;}}
}// 合并两个链表
TNode *MergeList(TNode *pA, TNode *pB)
{  if (pA == NULL){return pB;}if (pB == NULL){return pA;}if (pA->nData < pB->nData){pA->pNext = MergeList(pA->pNext, pB);return pA;}else{pB->pNext = MergeList(pA, pB->pNext);return pB;}
}  int main()
{TNode *pA = new TNode(1);TNode *pTail = AppendNode(pA, 3);pTail = AppendNode(pTail, 5);pTail = AppendNode(pTail, 6);pTail = AppendNode(pTail, 8);// 输出:1->3->5->6->8PrintList(pA);TNode *pB = new TNode(2);pTail = AppendNode(pB, 3);pTail = AppendNode(pTail, 7);// 输出:2->3->7PrintList(pB);TNode *pResult = MergeList(pA, pB);// 输出:1->2->3->3->5->6->7->8PrintList(pResult);return 0;
}

        当然,递归函数也有其缺点:当链表中的元素较多,递归的层级较多时,可能会导致堆栈溢出。

        接下来,我们来看第二种解法,使用链表遍历来实现。首先,当链表pA和pB其中一个为NULL时,直接返回另一个链表即可。接下来,我们创建了一个新的临时节点,作为新链表的头和尾,并遍历链表pA和pB。在遍历过程中,如果pA->nData小于pB->nData,则将pA作为新链表尾部的下一个节点,并遍历新链表尾部和pA的下一个节点;如果pA->nData不小于pB->nData,则将pB作为新链表尾部的下一个节点,并遍历新链表尾部和pB的下一个节点。循环遍历完成后,由于链表pA和pB不一样长,因此,需要检查链表pA和pB是否为NULL。若不为NULL,则将对应链表放到新链表尾部。最后,我们返回了新建节点的下一个节点作为合并后的链表首节点,并删除了新建的临时节点。具体实现,可参考如下的示例代码。

#include<iostream>
using namespace std;struct TNode
{int nData;struct TNode *pNext;TNode(int x) : nData(x), pNext(NULL) {}
};// 插入新节点到链表尾部
TNode *AppendNode(TNode *pTail, int nData)
{  TNode *pNodeNew = new TNode(nData);pTail->pNext = pNodeNew;return pNodeNew;
}// 打印链表
void PrintList(TNode *pNode)
{while (pNode != NULL){cout << pNode->nData;pNode = pNode->pNext;if (pNode != NULL){cout << "->";}else{cout << endl;}}
}// 合并两个链表
TNode *MergeList(TNode *pA, TNode *pB)
{if (pA == NULL){return pB;}if (pB == NULL){return pA;}TNode *pResult = new TNode(-1);TNode *pTail = pResult;while (pA && pB){if (pA->nData < pB->nData){pTail->pNext = pA;pTail = pTail->pNext;pA = pA->pNext;} else{pTail->pNext = pB;pTail = pTail->pNext;pB = pB->pNext;}}if (pA){pTail->pNext = pA;}if (pB){pTail->pNext = pB;}TNode *pTemp = pResult;pResult = pResult->pNext;delete pTemp;return pResult;
}int main()
{TNode *pA = new TNode(1);TNode *pTail = AppendNode(pA, 3);pTail = AppendNode(pTail, 5);pTail = AppendNode(pTail, 6);pTail = AppendNode(pTail, 8);// 输出:1->3->5->6->8PrintList(pA);TNode *pB = new TNode(2);pTail = AppendNode(pB, 3);pTail = AppendNode(pTail, 7);// 输出:2->3->7PrintList(pB);TNode *pResult = MergeList(pA, pB);// 输出:1->2->3->3->5->6->7->8PrintList(pResult);return 0;
}

总结

        链表是一种常见的数据结构,它通过指针链接一系列的节点。通过这道题,我们学习了链表的数据结构,以及链表合并的操作。

        另外,我们还为你留了一些课后的拓展作业,快来试一试吧!

        1、给定一个单向链表,判断链表中是否有环。

        2、给定一个单向链表的头节点,写一个函数将其反转。

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

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

相关文章

井盖发生位移怎么办?智能井盖传感器效果

井盖位移是一种严重的安全隐患&#xff0c;因为它可能导致道路受阻并干扰正常的交通&#xff0c;还可能对行人和车辆的安全造成威胁。为了有效应对这一问题&#xff0c;智能井盖传感器的应用提供了一种解决方案。智能井盖传感器可以实时监测井盖的位移情况&#xff0c;并在发现…

15、lambda表达式、右值引用、移动语义

前言 返回值后置 auto 函数名 (形参表) ->decltype(表达式) lambda表达式 lambda表达式的名称是一个表达式 (外观类似函数)&#xff0c;但本质绝非如此 语法规则 [捕获表] (参数表) 选项 -> 返回类型 { 函数体; }lambda表达式的本质 lambda表达式本质其实是一个类…

(1)(1.5) FrSky telemetry

文章目录 前言 1 设置 2 Turnigy 9XR Pro 前言 FrSky 遥测技术允许你显示 ArduPilot 的信息&#xff0c;如飞行模式、电池电量和错误信息&#xff0c;以及来自 OpenTx 兼容遥控发射机上其他 FrSky 传感器的信息&#xff0c;甚至包括较旧的 X9R 发射机&#xff08;尽管功能较…

周报:静态页面(酷狗首页)的制作-上

在前端领域学习了HTML和CSS有关知识后&#xff0c;我开始进行对常见网页制作的练习了&#xff0c;本次我尝试制作的是酷狗首页。以下为酷狗首页的样例&#xff1a; 不难发现&#xff0c;酷狗首页和豆瓣首页有很多相似之处&#xff0c;练习酷狗首页就相当于我对常规页面制作的巩…

电影《三大队》观后感

上周点播看了电影《三大队》&#xff0c;这部电影讲述的是三大队警员&#xff0c;在办案过程中&#xff0c;因为把犯罪嫌疑人打死后&#xff0c;锒铛入狱后&#xff0c;后来出来后&#xff0c;再次抓捕犯罪嫌疑人的故事。 &#xff08;1&#xff09;故事情节 有一次&#xff0c…

聚类算法的性能度量

聚类算法的性能度量 聚类算法就是根据数据中样本与样本之间的距离或相似度&#xff0c;将样本划分为若干组&#xff0f;类&#xff0f;簇&#xff0c;其划分的原则&#xff1a;簇内样本相似、簇间样本不相似&#xff0c;聚类的结果是产生一个簇的集合。 其划分方式主要分为两…

Mybatis源码解析5:Mapper执行流程1

Mybatis源码解析5&#xff1a;Mapper执行流程1 1.项目结构2. 源码分析2.1 Mapper代理 MapperProxy#invoke2.2 创建MapperMethod2.2.1 方法名称解析器ParamNameResolve2.2.2 MapperMethod#execute 2.3 DefaultSqlSession2.4 CachingExecutor2.5 SimpleExecutor#doQuery获取连接对…

AD域控环境搭建操作手册

AD域搭建 1、准备环境1.0、介绍什么是域控服务器为什么需要域域控制器的作用部署域服务器需要考虑几个方面什么是活动目录活动目录与DNS的关系 1.1、安装Windows Serve 20191.2、安装Windows101.3、安装域服务1.4、W10加入域环境1.5、OU和域用户的创建1.6、域用户安全策略1.7、…

Wireshark使用技巧

Wireshark作为网络数据软件&#xff0c;功能强大&#xff0c;本专栏介绍仅为冰山一角&#xff0c;仅仅是一个入门级别的介绍&#xff0c;大部分功能还需要在日常工作中进行挖掘。 总结Wireshark软件的使用技巧如下&#xff1a; 1.合理部署Wireshark的位置&#xff0c;从源头保障…

ArkUI Button组件

Button 1.声明button组件 Button(label?:ResourceStr) label是按钮上面显示的文字 如果不传入label 则需要在内部嵌套其他组件 内部嵌套其他组件 可以放入icon图标来构建自己想要的样式 按钮类型 按钮使用type(ButtonType.xxx)属性来设置&#xff0c;xxx的类型分为三种 1.…

导入pgsql中的保存的html数据到hive时,换行符无法被repalce

数据如图所示&#xff1a; 当我使用replace函数 \r\n 、\r 、 \n替换时。无论如何都无法替换 最终发现可以使用chr(ASCII码) 可以匹配到&#xff0c;坑我好久。 replace(replace(replace(replace(replace(bid_html_con, chr(9),),chr(10),),chr(13),),chr(160),),chr(32),)

【GIS】JDK版本升级到17后,GeoServer的图层无法通过openLayer预览

JDK版本升级到17后&#xff0c;图层无法通过openLayer预览 1. 错误图示 终端输出的错误 网页端无法显示图层&#xff0c;并且输出错误提示 2.原因猜测 估计可能是由于java17的模块化&#xff0c;Java被分成了多个独立部署和运行的模块&#xff0c;这使得Java应用能够更快…