1 题目简述
Merge two sorted linked lists and return it as a newlist. The new list should be made by splicing together the nodes of the first two lists.
合并两个已排序的链表并将其作为一个新列表返回。新列表应该通过拼接前两个列表的节点来完成。
Example:
Input: 1->2->4, 1->3->4
Output: 1->1->2->3->4->4
2 答案详解
(1) 解决思想
本次解答采用C++编写,C++相对于C语言的一个重要的特点是:面向对象编程(OOP),故我们采用类的方法来实现所述要求。
为了让读者能简易地理解作者的思路,故后面会以举例子的形式来阐述。两个有序链表的状态有5种情况,称这两个链表为first和second:
1.first链表为空,second链表不为空。
2.first链表不为空,second链表为空。
3.两个链表均为空。
4.两个链表均不为空,且first链表的首节点元素值<second链表的首节点元素值
5.两个链表均不为空,且first链表的首节点元素值>=second链表的首节点元素值
针对以上5种情况进行相应的处理:
1.针对情况1,返回first链表。
2.针对情况2,返回second链表。
3.针对情况3,返回first链表(为空)。
4.针对情况4,不做操作。
5.针对情况5,将first链表和second链表互换,使之变为情况4。
现在,针对情况4和情况5来进行举例来详细说明。设有两个有序链表分别为:2->4->7,1->3->5->6,将其分别赋给first和second。首先做判断,由于两个链表均不为空,且first链表的首节点元素值>=second链表的首节点元素值,故交换两个链表,此时first链表变为1->3->5->6,而second链表变为2->4->7。
然后,应知道目的是合并两个有序链表,而不是新建一个合并后的链表,即改变两个链表的节点的后继指向,而不开辟新的空间来容纳合并后的链表。接下来,由于要访问两个链表,故建立两个节点指针:temp指针指向first链表首节点,comp指针指向second链表首节点。
之后,为了使得temp指向的节点值始终<comp指向的节点值,故进行分步操作进行说明:
1.将temp->next(值为3)与comp(值为2)进行比较,发现3>2,故将temp->next与comp进行交换后,first链表变为:1->2->4->7,而comp此时指向的链表变为:3->5->6。而后将temp赋值为temp->next,值为2。
2.将temp->next(值为4)与comp(值为3)进行比较,发现4>3,故将temp->next与comp进行交换后,first链表变为:1->2->3->5->6,而comp此时指向的链表变为:4->7。而后将temp赋值为temp->next,值为3。
3.将temp->next(值为5)与comp(值为4)进行比较,发现5>4,故将temp->next与comp进行交换后,first链表变为:1->2->3->4->7,而comp此时指向的链表变为:5->6。而后将temp赋值为temp->next,值为4。
4.将temp->next(值为7)与comp(值为5)进行比较,发现7>5,故将temp->next与comp进行交换后,first链表变为:1->2->3->4->5->6,而comp此时指向的链表为:7。而后将temp赋值为temp->next,值为5。
5.将temp->next(值为6)与comp(值为7)进行比较,发现6<7,故不进行操作,此时first链表仍为:1->2->3->4->5->6,comp指向的链表仍为:7。而后将temp赋值为temp->next,值为6。
6.由于temp指向了first链表的最后一个节点,所以此时comp指向的链表上的所有节点值均>=first最后一个节点值,故可直接将temp->next赋值为comp。此时first链表变为:1->2->3->4->5->6->7。
最后,返回first链表。
(2) 设计程序
所设计的程序采用类模板实现,程序如下:
#include <iostream>
using std::cout;
using std::endl;
struct ListNode {
int val;
ListNode* next;
ListNode(int x):val(x),next(NULL) {}
};
template<class T>
class Solution
{
private:
T first_;
T second_;
public:
Solution(const T& first,const T& second):first_(first),second_(second) {}
T& MerTwoSorLists();
};
template<class T>
T& Solution<T>::MerTwoSorLists()
{
T temp(NULL);
T comp(NULL);
T swap(NULL);
if(first_ == NULL and second_ != NULL) {
return second_;//如果第一个链表为空,而第二个链表不为空,则返回第二个链表
} else if(first_ != NULL and second_ == NULL) {
return first_;//如果第一个链表不为空,而第二个链表为空,则返回第一个链表
} else if(first_ == NULL and second_ == NULL) {
return first_;//如果两个链表都为空,则返回第一个链表
} else if(first_ -> val > second_ -> val) {
swap = first_;
first_ = second_;
second_ = swap;//如果第一个链表的首个元素大于第二个链表的首个元素,则交换两个链表
}
temp = first_;
comp = second_;//temp和comp用于遍历两个链表
/*若两个链表不为空,则合并两个链表,此过程没有创建新的链表,而是改变两个链表中的节点的指向*/
while(temp != NULL or comp != NULL) {//遍历条件:均未遍历到两个链表的末端
if(temp->next == NULL) {
temp->next = comp;
return first_;//如果遍历到temp最后一个节点,则将temp的下一个节点赋值为comp,因为comp指向的节点元素值始终>=temp指向的节点元素值
} else if(temp->next->val < comp->val) {
temp = temp->next;//如果此时temp下一个节点的元素< comp节点的元素,则temp指向temp下一个节点
} else {
swap = temp->next;
temp->next = comp;
comp = swap;
temp = temp->next;//如果此时temp下一个节点的元素>= comp节点的元素,则交换temp->next和comp,并让temp指向temp下一个节点。目的:为了使temp节点的元素始终小于comp节点的元素
}
}
}
template<class T>
void Show(T pnode)
{
while(pnode != NULL) {
cout << pnode->val ;
if(pnode->next != NULL) {
cout << "->";
}
pnode = pnode->next;
}
cout << endl;
}
int main()
{
ListNode n11(1);
ListNode n12(3);
ListNode n13(5);
ListNode n14(6);
n11.next = &n12;
n12.next = &n13;
n13.next = &n14;
ListNode n21(2);
ListNode n22(4);
ListNode n23(7);
n21.next = &n22;
n22.next = &n23;
cout << "The first list:";
Show(&n21);
cout << "The second list:";
Show(&n11);
Solution<ListNode*> sol(&n21,&n11);
ListNode* res = sol.MerTwoSorLists();
cout << "After the merger:";
Show(res);
}
程序运行结果为:
The first list:2->4->7
The second list:1->3->5->6
After the merger:1->2->3->4->5->6->7