《剑指Offer》面试题17:合并两个排序的链表
知识点
链表和递归
题目描述
输入两个递增排序的链表,合并这两个链表并使新链表中的结点仍然是按照递增排序的。例如输入图中的链表1和链表2,则合并之后的升序链表3所示。
解题思路
首先分析合并两个链表的过程。我们的分析从合并两个链表的头结点开始。链表1的头结点的值小于链表2的头结点的值,因此链表1的头结点将是合并后链表的头结点,如图所示:
我们继续合并两个链表中剩余的结点。在两个链表中剩下的结点依然是排序的,因此合并这两个链表的步骤和前面的步骤是一样的。我们还是比较两个头结点的值。此时链表2的头结点的值小于链表1的头结点的值,因此链表2的头结点的值将是合并剩余结点得到的链表的头结点。我们把这个结点和前面合并链表时得到的链表的尾节点链接起来,如图所示。
当我们得到两个链表中值较小的头结点并把它链接到已经合并的链表之后,两个链表剩余的结点依然是排序的,因此合并的步骤和之前的步骤是一样的。这就是典型的递归的过程,我们可以定义递归函数完成这一合并过程。
接下来我们来解决鲁棒性的问题。每当代码试图访问空指针指向的内存时程序就会崩溃,从而导致鲁棒性问题。在本题中一旦输入空的链表就会引入空的指针,因此我们要对空链表单独处理。当第一个链表是空链表,也就是它的头结点是一个空指针时,那么把它和第二个链表合并,闲人合并的过程就是第二个链表。同样,当输入的第二个链表的头结点是空指针的时候,我们把它和第一个链表合并得到的结果就是第一个链表。如果两个链表都是空链表,合并的结果是得到一个空链表。
测试用例
代码
/*《剑指Offer——名企面试官精讲典型编程题》代码
著作权所有者:何海涛*/
#include "stdio.h"
#include "cstdlib"
struct ListNode
{
int m_nValue;
ListNode *m_pNext;
};
ListNode* CreateListNode(int value)
{
ListNode* pNode = new ListNode();
pNode->m_nValue = value;
pNode->m_pNext = NULL;
return pNode;
}
void ConnectListNodes(ListNode* pCurrent, ListNode* pNext)
{
if (pCurrent == NULL)
{
printf("Error to connect two nodes.\n");
exit(1);
}
pCurrent->m_pNext = pNext;
}
void PrintListNode(ListNode* pNode)
{
if (pNode == NULL)
{
printf("The node is NULL\n");
}
else
{
printf("The key in node is %d.\n", pNode->m_nValue);
}
}
void PrintList(ListNode* pHead)
{
printf("PrintList starts.\n");
ListNode* pNode = pHead;
while (pNode != NULL)
{
printf("%d\t", pNode->m_nValue);
pNode = pNode->m_pNext;
}
printf("\nPrintList ends.\n");
}
void DestroyList(ListNode* pHead)
{
ListNode* pNode = pHead;
while (pNode != NULL)
{
pHead = pHead->m_pNext;
delete pNode;
pNode = pHead;
}
}
ListNode* Merge(ListNode* pHead1, ListNode* pHead2)
{
if (pHead1 == NULL)
return pHead2;
else if (pHead2 == NULL)
return pHead1;
ListNode* pMergedHead = NULL;
if (pHead1->m_nValue < pHead2->m_nValue)
{
pMergedHead = pHead1;
pMergedHead->m_pNext = Merge(pHead1->m_pNext, pHead2);
}
else
{
pMergedHead = pHead2;
pMergedHead->m_pNext = Merge(pHead1, pHead2->m_pNext);
}
return pMergedHead;
}
// ====================测试代码====================
ListNode* Test(char* testName, ListNode* pHead1, ListNode* pHead2)
{
if (testName != NULL)
printf("%s begins:\n", testName);
printf("The first list is:\n");
PrintList(pHead1);
printf("The second list is:\n");
PrintList(pHead2);
printf("The merged list is:\n");
ListNode* pMergedHead = Merge(pHead1, pHead2);
PrintList(pMergedHead);
printf("\n\n");
return pMergedHead;
}
// list1: 1->3->5
// list2: 2->4->6
void Test1()
{
ListNode* pNode1 = CreateListNode(1);
ListNode* pNode3 = CreateListNode(3);
ListNode* pNode5 = CreateListNode(5);
ConnectListNodes(pNode1, pNode3);
ConnectListNodes(pNode3, pNode5);
ListNode* pNode2 = CreateListNode(2);
ListNode* pNode4 = CreateListNode(4);
ListNode* pNode6 = CreateListNode(6);
ConnectListNodes(pNode2, pNode4);
ConnectListNodes(pNode4, pNode6);
ListNode* pMergedHead = Test("Test1", pNode1, pNode2);
DestroyList(pMergedHead);
}
// 两个链表中有重复的数字
// list1: 1->3->5
// list2: 1->3->5
void Test2()
{
ListNode* pNode1 = CreateListNode(1);
ListNode* pNode3 = CreateListNode(3);
ListNode* pNode5 = CreateListNode(5);
ConnectListNodes(pNode1, pNode3);
ConnectListNodes(pNode3, pNode5);
ListNode* pNode2 = CreateListNode(1);
ListNode* pNode4 = CreateListNode(3);
ListNode* pNode6 = CreateListNode(5);
ConnectListNodes(pNode2, pNode4);
ConnectListNodes(pNode4, pNode6);
ListNode* pMergedHead = Test("Test2", pNode1, pNode2);
DestroyList(pMergedHead);
}
// 两个链表都只有一个数字
// list1: 1
// list2: 2
void Test3()
{
ListNode* pNode1 = CreateListNode(1);
ListNode* pNode2 = CreateListNode(2);
ListNode* pMergedHead = Test("Test3", pNode1, pNode2);
DestroyList(pMergedHead);
}
// 一个链表为空链表
// list1: 1->3->5
// list2: 空链表
void Test4()
{
ListNode* pNode1 = CreateListNode(1);
ListNode* pNode3 = CreateListNode(3);
ListNode* pNode5 = CreateListNode(5);
ConnectListNodes(pNode1, pNode3);
ConnectListNodes(pNode3, pNode5);
ListNode* pMergedHead = Test("Test4", pNode1, NULL);
DestroyList(pMergedHead);
}
// 两个链表都为空链表
// list1: 空链表
// list2: 空链表
void Test5()
{
ListNode* pMergedHead = Test("Test5", NULL, NULL);
}
int main()
{
Test1();
Test2();
Test3();
Test4();
Test5();
system("pause");
return 0;
}