2019年408真题41算法题

 

1、找中间结点方法:定义两个指针pcur、ppre,开始时同时指向L->next,之后向后遍历,让pcur每走两步,ppre走一步,当pcur为空时,结束循环,此时ppre指向中间结点

 

 2、L2原地逆置方法:定义三个指针r、s、t,使它们分别指向链表开始的三个结点,先让s->next=r,则a2指向a1,之后r、s、t依次后移,依次完成a3指向a2,a4指向a3,再后移发现t为空,此时结束循环,但最后的a5还没指向,所以在循环外要再执行依次s->next=r。

最后需要让L2->next->next=NULL(此时L2->next->next拿到的是a1),因为原有链表的头结点变成最后一个结点,需要让最后一个结点的next为NULL,再让L2->next=s,使s成为逆置后的链表的第一个结点。

 3、轮流合并方法:定义三个指针pcur、p、q,让pcur始终指向合并后的新链表的尾部,初始化为p=L->next,让p始终指向L待插入的结点,初始化为p=L->next,q始终指向L2待插入的结点,初始化为q=L2->next

 循环到最后,L或L2总会有一个链表剩一个结点没放进去,此时判断p不为NULL或者q不为NULL,再将p或q放进去即可

#include <stdio.h>
#include <stdlib.h>
typedef int ElemType;
typedef struct LNode
{
    ElemType data;
    struct LNode *next;
}LNode,*LinkList;
void list_tail_insert(LinkList &L)
{
    L=(LinkList)malloc(sizeof(LNode));
    ElemType x;
    L->next=NULL;
    scanf("%d",&x);
    LNode *s,*r;
    r=L;
    while (x!=9999)
    {
        s=(LinkList)malloc(sizeof(LNode));
        s->data=x;
        r->next=s;
        r=s;
        scanf("%d",&x);
    }
    r->next=NULL;
}


//找到中间结点
void find_middle(LinkList L,LinkList &L2)
{
    L2=(LinkList)malloc(sizeof(LNode));
    LinkList pcur,ppre;//双指针法遍历链表
    ppre=pcur=L->next;
    while(pcur)
    {
        pcur=pcur->next;
        if(NULL==pcur)//让pcur先走一步,看看是否为空,不然如果为空再继续走,程序会崩溃
        {
            break;
        }
        pcur=pcur->next;
        if(NULL==pcur)//为了使得偶数个,ppre依然指向a1,a2,到a6中的a3结点
        {
            break;
        }
        ppre=ppre->next;
    }
    L2->next=ppre->next;//由L2头结点指向后面一半链表
    ppre->next=NULL;//前面一半链表的最后一个结点,next要为NULL
}


//逆置
void reverse(LinkList L2)//逆转时不会改变L2,不用带引用
{
    LinkList r,s,t;
    r=L2->next;
    if(NULL==r)
    {
        return;//链表中没有结点,只有头结点
    }
    s=r->next;
    if(NULL==s)
    {
        return;//链表只有一个结点
    }
    t=s->next;
    while (t)
    {
        s->next=r;//链表开始逆置
        r=s;
        s=t;
        t=t->next;
    }
    s->next=r;
    L2->next->next=NULL;//逆置后,链表第一个结点的next要为NULL
    L2->next=s;//s为链表的第一个结点,L2指向它
}


//合并链表
void merge(LinkList L,LinkList L2)
{
    LinkList pcur,p,q;
    pcur=L->next;//pcur始终指向组合后链表的链表尾,pcur一开始指向a1
    p=pcur->next;//这里p获取到的是L->next->next,p一开始指向a2
    q=L2->next;//q指向L2第一个结点
    while(p!=NULL&&q!=NULL)
    {
        pcur->next=q;
        q=q->next;
        pcur=pcur->next;
        pcur->next=p;
        p=p->next;
        pcur=pcur->next;
    }
    //任何一个链表都可能剩余一个结点,要判断后放进来
    if(p!=NULL)
    {
        pcur->next=p;
    }
    if(q!=NULL)
    {
        pcur->next=q;
    }
}
void print_list(LinkList L)
{
    L=L->next;
    while(L!=NULL)
    {
        printf("%d",L->data);
        L=L->next;
        if(L)
        {
            printf(" ");
        }
    }
    printf("\n");
}
int main()
{
    LinkList L;
    list_tail_insert(L);
    print_list(L);
    LinkList L2=NULL;
    find_middle(L,L2);//寻找中间结点,并返回第二条链表,只有一个结点时,L2中是没有结点的
    printf("-----------------------\n");
    print_list(L);
    print_list(L2);
    printf("-----------------------\n");
    reverse(L2);
    print_list((L2));
    printf("-----------------------\n");
    merge(L,L2);
    free(L2);
    print_list(L);
    return 0;
}

运行结果:头插法创建链表

                   找中间结点后分成两个链表

                   逆序后的L2

                   最终插入结果

 

  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值