DAY 5 实战 2019考研真题

题目分析:我们可以将算法实现分为三个部分:找到中间位置的结点,将后半部分的新链表逆置,将逆置的链表插入前半部分链表中。但这之间也会产生许多问题,比如如果链表结点是奇数个呢? 如何在空间复杂度是O(1)用代码实现呢?

解题设计:第一部分找到中间位置结点,正常思维都是遍历两遍链表一次找尾节点长度一次找中间节点,但秉持着能优则优的原则,我们选择双指针法一次遍历链表即可,命名两个指针ppre与pcur,我们让pcur一次走两步,而ppre一次走一步,这样当pcur遍历完链表之后ppre此时在中间结点。有人会担心奇数个结点怎么办,在经过画图论证后我发现其实并不会影响结果。

void middle_find(LinkList L,LinkList &L2)
{
    LinkList ppre,pscr;
    L2=(LinkList) malloc(sizeof (LNode));
    ppre=L->next;
    pscr=L->next;
    while(pscr)
    {
        pscr=pscr->next;
        if(pscr==NULL)
        {
            break;
        }
        pscr=pscr->next;
        if(pscr==NULL)
        {
            break;
        }
        ppre=ppre->next;
    }
    L2->next=ppre->next;
    ppre->next=NULL;

}

在实现代码的时候,我发现了一些小问题并改正了过来,比如pcur一定要移动一步就判断一次是否为null,L的尾部要切断。

第二部分将L2逆置。首先我们要判断什么情况下才需要逆置,链表为空和一个结点肯定不需要(考研不可能这样但最好考虑全面)。接下来使用三指针法,命名三个指针r,s,t,使其分别对应链表里待处理的三个指针。接下来让第二个指针指向第一个指针,再将三个指针均向后移一位,重复上述操作,这样就会得到一个“反向的”链表,此时L2还指向第一个结点(现在是最后一个结点),t为空时结束循环,但要记得此时最后一个结点还未逆置,所以要在循环外加上s->next=r。

void reverse_list(LinkList L)
{
    LinkList r,s,t;
    r=L->next;
    if(r==NULL)
    {
        return;
    }
    s=r->next;
    if(s==NULL)
    {
        return;
    }
    t=s->next;

    while(t)
    {
        s->next=r;
        r=s;
        s=t;
        t=t->next;
    }
    s->next=r;
    L->next->next=NULL;
    L->next=s;
}

第三部分L与L2合并。考虑到空间复杂度是O(1),我们不能申请新的空间,所以要直接处理现存的链表。我们需要 3 个指针(pcur,p,q),合并后的新链表我们让 pcur 指针始终指向新链表尾部,初始化为 pcur=L->next,使用 p 指针始终指向链表 L 待放 入的结点,初始化值为 p=L->next,q 指针始终指向链表 L2 待放入的结点,初始化值为 q=L2->next。因为链表 L 的第一个结点不动,所以 p=p->next。 开启循环 while(p!=NULL&&q!=NULL),首先将 pcur->next=q,然后 q=q->next 和 pcur=pcur->next,接着 pcur->next=p,然后 p=p->next 和 pcur=pcur->next,直到循环结 束。循环结束后,有可能 L 还剩余一个结点,也可能 L2 剩余一个结点,但是只会有一个剩 余的有结点,因此我们判断 p 不为 NULL,把 p 放入,如果 q 不为 NULL,把 q 放入即可。

void merge(LinkList L,LinkList L2)
{
    LinkList ppre,p,q;
    ppre=L->next;
    p=ppre->next;
    q=L2->next;
    while(p!=NULL&&q!=NULL)
    {
        ppre->next=q;
        ppre=ppre->next;
        q=q->next;
        ppre->next=p;
        p=p->next;
        ppre=ppre->next;
    }
    if(p!=NULL)
    {
        ppre->next=p;
    }
    if(q!=NULL)
    {
        ppre->next=q;
    }
}

接下来是测试结果(尾插法新建链表):

 运行成功!

总结:一下就打出完整代码是不可能的,一定要先出思路,写代码的过程中要考虑各种各样的情况防止bug。

 

评论 4
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值