题目描述:
输入两个递增排序的链表,合并这两个链表并使新链表中的节点仍然是递增排序的。
示例1:
输入:1->2->4, 1->3->4
输出:1->1->2->3->4->4
限制:0 <= 链表长度 <= 1000
来源:力扣(LeetCode)
链接:https://leetcode-cn.com/problems/he-bing-liang-ge-pai-xu-de-lian-biao-lcof
著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。
题外话:很烦, 好久没写了,指针的东西又快忘的差不多了,又出现了几个问题:
1.指针初始化的时候究竟用不用new或者malloc?
2.两个指针指向同一个地址,其中一个指针改变了,另一个会变吗?
3.链表的头指针如何保留?
分析:这道题其实很简单,只是牵扯到了链表与指针。思路就是用l1和l2同时指向两个链表,比较链表元素的大小,若l1元素>l2,那么l2插入新链表l第一个节点,然后l2指针后移, 若l1元素<=l2,那么l1插入新链表l第一个节点,然后l1指针后移。依次这样判断,直到l1或者l2为空。然后把l1或者l2剩余部分接到l链表最后。
但是在刚开始写的时候,遇到了一些问题,其中最典型的就是如下:
ListNode *p1,*head1,*p2,*head2;
head1=p1=new ListNode(1);
p1=p1->next;
p1=new ListNode(2);
p1=p1->next;
p1=new ListNode(3);
cout<<"head is "<<head1<<endl;
cout<<"head val is "<<head1->val<<endl;
cout<<"head next is "<<head1->next<<endl;
这段代码想干什么呢?是想建立一个链表,依次为1,2,3。p1和head同时指向第一个开辟的内存空间,并且赋值为1,然后,我们想开辟第二个节点,把它接在p1后面。但是如图所示的做法对吗?看似是对的,先来到p1->next,然后在为该指针分配内存,创立节点。但是,输出告诉我们并不对,head的next为空,出了什么问题?其实是这句话有问题,
p1=p1->next;
这句话在链表的创立和遍历中很常见,但是为什么出现了问题?我们首先要明白,p1->next此时指向了内存中的某个位置吗?并没有,p1->next此时是野指针,那么,理所当然,p1也变成了野指针,这时候p1已经不是建立第一个节点时指向的那个位置了,在没有为head->next指定内存之前,p1已经变成了野指针,链已经断开了,还怎么构建链表呢?
因此,建立链表的时候,必须先指定出next指针所指向的内存,然后才去对next进行操作。
最终代码如下:
/**
* Definition for singly-linked list.
* struct ListNode {
* int val;
* ListNode *next;
* ListNode(int x) : val(x), next(NULL) {}
* };
*/
class Solution {
public:
ListNode* mergeTwoLists(ListNode* l1, ListNode* l2) {
if(l1==NULL&&l2==NULL)
return NULL;
ListNode *l=new ListNode(0);
ListNode *head;
bool flag=true;
while(l1!=NULL&&l2!=NULL)
{
if(l1->val>=l2->val)
{
l->next=new ListNode(l2->val);
l=l->next;
if(flag)
{
head=l;
flag=false;
}
l2=l2->next;
}
else
{
l->next=new ListNode(l1->val);
l=l->next;
if(flag)
{
head=l;
flag=false;
}
l1=l1->next;
// cout<<"hello"<<endl;
}
}
if(l1!=NULL)
{
// cout<<"hello"<<endl;
l->next=l1;
if(flag)
{
head=l->next;
flag=false;
}
// cout<<"l->next->val "<<l->next->val<<endl;
}
if(l2!=NULL)
{
// cout<<"hi"<<endl;
l->next=l2;
if(flag)
{
head=l->next;
flag=false;
}
}
// while(head!=NULL)
// {
// cout<<head->val<<" "<<head->next<<endl;
// head=head->next;
// }
return head;
}
};
注意几个特殊的测试用例:
1.p1=[],p2=[]
2.p1=[1],p2=[]
3.p1=[],p2=[1]
弄明白这些后,可以回答上面提出的问题了。
1.指针初始化的时候究竟用不用new或者malloc?
不是必须,但是尽量保证该指针最后指向了某个内存,避免野指针的出现。可以在之后对指针指向的地址进行设置,但必须的有。
2.两个指针指向同一个地址,其中一个指针改变了,另一个会变吗?
分情况,1.p1和p2指向同一内存,p1改变了内存中的值,那么p2指向的内存的值也发生变化,因为二者对应的是同一个内存。2.p1和p2指向同一内存,p1指向了其他地方,那么p1和p2就没有关系了。
3.链表的头指针如何保留?
在创立链表时,头指针head要指向链表第一个节点,然后不再改变。用p指针来指向next,完成链表的创建。即无法仅仅使用一个指针就完成链表的创建和头指针的返回,必须要head和p指针配合使用。
隔了几天,再写一次吧,精简版代码:
/**
* Definition for singly-linked list.
* struct ListNode {
* int val;
* ListNode *next;
* ListNode(int x) : val(x), next(NULL) {}
* };
*/
class Solution {
public:
ListNode* mergeTwoLists(ListNode* l1, ListNode* l2) {
ListNode *p;
ListNode *head;
head=p=new ListNode(0);
while(l1!=NULL&&l2!=NULL)
{
if(l1->val>l2->val)
{
ListNode *temp=new ListNode(l2->val);
p->next=temp;
p=p->next;
l2=l2->next;
}
else
{
ListNode *temp=new ListNode(l1->val);
p->next=temp;
p=p->next;
l1=l1->next;
}
}
if(l1!=NULL) p->next=l1;
if(l2!=NULL) p->next=l2;
return head->next;
}
};