剑指 Offer 25. 合并两个排序的链表

题目描述:

输入两个递增排序的链表,合并这两个链表并使新链表中的节点仍然是递增排序的。

示例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;
    }
};

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值