题目来源: 计算机考研408真题2019年41题
题目描述:
- 描述: 41.(13分)设线性表采用带头结点的单链表保存,链表中的结点定义如下:
typedef struct node
{
int data;
struct node*next;
} NODE;
请设计一个空间复杂度为O(1)且时间上尽可能高效的算法,重新排列L中的各结点,得到线性表。
要求:
1)给出算法的基本设计思想。
2)根据设计思想,采用C、C++或Java语言描述算法,关键之处给出注释.
3)说明你所设计算法的时间复杂度和空间复杂度。
思路:双指针
- 1.先进行审题,找规律: 和,发现L'是由L摘取第一个元素,再摘取倒数第一个元素……依次合并而成的
- 2.对于"摘取倒数第一个元素"这个操作,会发现仅仅是与链表后半部分的元素有关,又因为要求空间复杂度O(1),所以,可以采用将后半段链表原地逆置
- 先找出链表L的中间结点,为此设置两个指针p和q,指针p每次走一步,指针q每次走两步,当指针q到达链尾时,指针p正好在链表的中间结点
- 将L的后半段结点原地逆置
- 从单链表前后两段中依次各取一个结点,按要求重排
具体实现:
#include <iostream>
using namespace std;
typedef struct Node {
int data; //数据域
struct Node *next; //指针域
} Node,*Linklist;
void show(Linklist L){ //Node* 和 Linklist一样
while(L->next != NULL){
cout<<L->next->data;
L = L->next;
}
}
Linklist List_HeadInsert(Linklist &L){ //创建链表
Node *s;
int x;
L = (Linklist)malloc(sizeof (Node));
L->next = NULL;
cin>>x;
while(x!=9999){ //如果x的值是9999,那么就结束链表的创建
s=(Node*) malloc(sizeof (Node));
s->data = x;
s->next = L->next;
L->next = s;
cin>>x;
}
return L;
}
void change_list(Linklist& h) { //Node* 和 Linklist一样
Node *p, *q, *r, *s;
p = q = h;
while (q->next != NULL) { //寻找中间结点
p = p->next; //p走一步
q = q->next; //q走一步
if(q->next != NULL)
q = q->next; //q再走一步,前后每次共走两步
}
q = p->next; //p所指结点为中间结点,q为后半段链表的首结点
p->next = NULL;
while(q!=NULL){ //将链表后半段逆置
r = q->next;
q->next = p->next;
p->next = q;
q = r;
}
s = h->next; //s指向前半段的第一个数据结点,即插入点
q= p->next; //q指向后半段的第一个数据结点
p->next = NULL;
while(q!=NULL){ //将链表后半段的结点插入到指定位置
r = q->next; //r指向后半段的下一个结点
q->next = s->next; //将q所指结点插入到s所指结点之后
s->next = q;
s = q->next; //s指向前半段的下一个插入点
q = r;
}
}
int main() { //测试
Linklist head;
Linklist linklist = List_HeadInsert(head);
show(head);
change_list(linklist);
cout<<"成果展示:"<<endl;
show(head);
}
开启掘金成长之旅!这是我参与「掘金日新计划 · 2 月更文挑战」的第 27 天,点击查看活动详情”