面试题17:合并两个排序的链表
一.题目描述
输入两个递增排序的链表,合并这两个链表并使新链表中的结点仍然是按照递增排序的。例如输入图3.7中的链表1和链表2,则合并之后的升序链表如链表3所示。
链表结点定义如下:
struct ListNode
{
int m_nValue;
ListNode* m_pNext;
};
二.分析问题
1.举例分析
注:
链表1和链表2是两个递增排序的链表,合并这两个链表得到升序链表为链表3。
首先分析合并两个链表的过程。我们的分析从合并两个链表的头结点开始。链表1的头结点的值小于链表2的头结点的值,因此链表1的头结点将是合并后链表的头结点(如图所示)。
注:
(a)链表1的头结点的值小于链表2的头结点的值,因此链表1的头结点是合并后链表的头结点。
(b)在剩余的结点中,链表2的头结点的值小于链表1的头结点的值,因此链表2的头结点是剩余结点的头结点,把这个结点和之前已经合并好的链表的尾结点链接起来。
我们继续合并两个链表中剩余的结点(图中虚线框中的链表)。在两个链表中剩下的结点依然是排序的,因此合并这两个链表的步骤和前面的步骤是一样的。我们还是比较两个头结点的值。此时链表2的头结点的值小于链表1的头结点的值,因此链表2的头结点的值将是合并剩余结点得到的链表的头结点。我们把这个结点和前面合并链表时得到的链表的尾结点(值为1的结点)链接起来,如图(b)所示。
当我们得到两个链表中值较小的头结点并把它链接到已经合并的链表之后,两个链表剩余的结点依然是排序的,因此合并的步骤和之前的步骤是一样的。这就是典型的递归的过程,我们可以定义递归函数完成这一合并过程。
在本题中一旦输入空的链表就会引入空的指针,因此我们要对空链表单独处理。当第一个链表是空链表,也就是它的头结点是一个空指针时,那么把它和第二个链表合并,显然合并的结果就是第二个链表。同样,当输入的第二个链表的头结点是空指针的时候,我们把它和第一个链表合并得到的结果就是第一个链表。如果两个链表都是空链表,合并的结果是得到一个空链表。
三.代码
ListNode* Merge(ListNode* pHead1, ListNode* pHead2)
{
if (pHead1 == NULL)
{
retunr pHead2;
}
else if (pHead2 == NULL)
{
return pHead1;
}
ListNode* pMergeHead = NULL;
if (pHead1->m_nValue < pHead2->m_nValue)
{
pMergeHead = pHead1;
pMergeHead->m_pNext = Merge(pHead1->m_pNext, pHead2);
}
else
{
pMergeHead = pHead2;
pMergeHead->m_pNext = Merge(pHead1, pHead2->m_pNext);
}
return pMergeHead;
}