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->8
    PrintList(pA);

    TNode *pB = new TNode(2);
    pTail = AppendNode(pB, 3);
    pTail = AppendNode(pTail, 7);
    // 输出:2->3->7
    PrintList(pB);

    TNode *pResult = MergeList(pA, pB);
    // 输出:1->2->3->3->5->6->7->8
    PrintList(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->8
    PrintList(pA);

    TNode *pB = new TNode(2);
    pTail = AppendNode(pB, 3);
    pTail = AppendNode(pTail, 7);
    // 输出:2->3->7
    PrintList(pB);

    TNode *pResult = MergeList(pA, pB);
    // 输出:1->2->3->3->5->6->7->8
    PrintList(pResult);
    return 0;
}

总结

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

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

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

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

相关推荐

  1. C++面试29:sizeof使用大全

    2023-12-11 11:12:05       26 阅读

最近更新

  1. TCP协议是安全的吗?

    2023-12-11 11:12:05       16 阅读
  2. 阿里云服务器执行yum,一直下载docker-ce-stable失败

    2023-12-11 11:12:05       16 阅读
  3. 【Python教程】压缩PDF文件大小

    2023-12-11 11:12:05       15 阅读
  4. 通过文章id递归查询所有评论(xml)

    2023-12-11 11:12:05       18 阅读

热门阅读

  1. React学习笔记

    2023-12-11 11:12:05       35 阅读
  2. 线程组、线程切换、线程异常

    2023-12-11 11:12:05       44 阅读
  3. scheduleatfixedrate详解

    2023-12-11 11:12:05       39 阅读
  4. Presto集群安装部署

    2023-12-11 11:12:05       44 阅读
  5. springboot自定义cron定时任务执行

    2023-12-11 11:12:05       37 阅读
  6. 第三十一章 控制到 XML 模式的映射 - %ListOfDataTypes

    2023-12-11 11:12:05       23 阅读
  7. SAP ABAP 对象ALV的一些功能(ALV资料五)

    2023-12-11 11:12:05       29 阅读
  8. # C语言——预处理(#define,#if..)

    2023-12-11 11:12:05       28 阅读