文章目录
- 前言
- 题目描述
- 题目分析
- 代码实战
前言
本篇博客从头到尾都在解析一道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)。