【C语言督学训练营 第十二天】三篇文章吃透数据结构中的线性表(三)----- 线性表考研真题

前言

本篇博客从头到尾都在解析一道2019年考研真题中的一道关于链表的大题,虽然题目没有竞赛算法题那么复杂,那么难想,但是我们依旧可以从中收获到好多知识,本题的突破点就是快慢指针与链表反转。一份学习总会有一份收获吧!

题目描述

在这里插入图片描述

题目分析

先分析一下题目的流程,题目的大意是将一个序列,经过一定的算法变成a1,an…交替的样子,通过观察可以发现,新产生的序列奇数项是a1,a2,a3,…,偶数项为an,an-1,an-2…,所以我们不妨大胆猜想,中间的算法作用就是先将原序列分割成两半,然后将后半段反转,最后将分割后的两半依次拼接。

显然想法是行得通的,所以重新捋顺一下思路应该这么做:

  • 链表从中间分割 使用快慢指针
  • 链表逆置 采用辅助指针
  • 链表拼接 采用辅助指针

拓展(后面复习到还会再加进来):

  • 在判断链表是否是循环链表时也可以使用快慢指针的方法

于是我们不妨设置三个函数,每一个函数负责一个功能,在主函数中合理进行调度。暂且将splitList、reversal、concatList作为上述三个算法的函数名。
分析到这里,这个题目的脉络也就相对清晰了,接下来要做的就是细化分析步骤(也就是回答题目的第一小问)!
在这里插入图片描述
在这里插入图片描述

在这里插入图片描述

代码实战

这点代码着着实实撸了一下午,写的时候思路很清晰但是有奇数偶数项在干扰我们,其实这题里面奇数偶数项有影响也没影响,看我们咋想,操作比较简单注释就比较少了,如果有疑问就评论区留言吧!

//
// Created by Zhu Shichong on 2023/1/9.
//
#include <stdio.h>
#include<stdlib.h>
#define bool int
#define true 1
#define false 0
typedef int ElemType;
//数组类型
struct myList{
    ElemType data;
    struct myList* next;
};
typedef struct myList myList;

//遍历链表
void print_list(myList *head){
    if(head->next==NULL){
        printf("null!!!");
    }
    for (myList *p=head;p->next!=NULL;p=p->next){
        printf("%3d",p->next->data);
    }
    printf("\n");
}
//找出中间节点
myList *spliteList(myList *head){
    //p走路是二倍速,q是一倍速
    myList *p,*q;
    for(p=head->next,q=head->next;p->next!=NULL&&p->next->next!=NULL;p=p->next->next,q=q->next);
    p=q->next;
    q->next=NULL;
    return p;
}
//将后半段链表反转
myList *reversalList(myList* head){
    myList *p,*q,*r;
    if(head->next==NULL){
        return NULL;
    }
    p=head;
    q=p->next;
    r=q->next;
    p->next=NULL;
    for(;r!=NULL;){
        q->next=p;
        p=q;
        q=r;
        r=r->next;
    }
    q->next=p;

    return q;
}
//拼接数组
myList *concatList(myList* head,myList* l){
    myList *p,*tail;
    tail=head;
    p=head->next;
    while (l!=NULL&&p!=NULL){
        tail->next=p;
        p=p->next;
        tail->next->next=l;
        l=l->next;
        tail=tail->next->next;
    }
    if(p!=NULL){
        tail->next=p;
    }
    if(l!=NULL){
        tail->next=l;
    }
    return head;

}
int main() {
    // 创建一个头结点(头结点一般不用于存储信息)
    myList *head=(myList*)malloc(sizeof (myList));
    head->next=NULL;
    myList *tail=head;
    for(int i=1;i<7;i++){
        myList *p=NULL;
        p=(myList*) malloc(sizeof (myList));
        p->data=i;
        p->next=NULL;
        tail->next=p;
        tail=tail->next;
    }
    print_list(head);
    /*
     * 每调用一次spliteList(head)函数,链表长度就会减半
     * */
    print_list(concatList(head,reversalList(spliteList(head))));
    return 0;
}

最后是第三问,分析咱们算法的时间复杂度,这里每一个函数的时间复杂度是0.5n,三个函数加起来有1.5n,
忽略首项系数,该算法时间复杂度应为O(n)。


在这里插入图片描述

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

酷尔。

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值