题目
有一个链表,其节点声明如下:
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、给定一个单向链表的头节点,写一个函数将其反转。