Given a constant K and a singly linked list L, you are supposed to reverse the links of every K elements on L. For example, given L being 1→2→3→4→5→6, if K = 3, then you must output 3→2→1→6→5→4; if K = 4, you must output 4→3→2→1→5→6.
Input Specification:
Each input file contains one test case. For each case, the first line contains the address of the first node, a positive N (<= 105) which is the total number of nodes, and a positive K (<=N) which is the length of the sublist to be reversed. The address of a node is a 5-digit nonnegative integer, and NULL is represented by -1.
Then N lines follow, each describes a node in the format:
Address Data Next
where Address is the position of the node, Data is an integer, and Next is the position of the next node.
Output Specification:
For each case, output the resulting ordered linked list. Each node occupies a line, and is printed in the same format as in the input.
Sample Input:00100 6 4 00000 4 99999 00100 1 12309 68237 6 -1 33218 3 00000 99999 5 68237 12309 2 33218Sample Output:
00000 4 33218 33218 3 12309 12309 2 00100 00100 1 99999 99999 5 68237 68237 6 -1
这一题涉及到了插入、删除等操作,所以我选择了链表法。
之后有两种选择,
1.如果选择压缩空间复杂度,则应该用动态链表;
2.如果选择压缩时间复杂度,则应该用静态链表;
我第一次写的时候选择了方案1:
#include<stdio.h>
#include<stdlib.h>
typedef struct Node{
struct Node *priorone;
int address;
int data;
int next;
struct Node *nextone;
}Node;
typedef struct List{
struct Node *head;
int address;
int N;
int K;
}List;
List* creatList();
Node* creatNode();
Node* serchadd(Node* node[],int address,int N);
int connectNode(Node *node[],Node *head,int N);
void transpose(Node *p1,Node *q1,int K);
void changenextadd(List *list);
int printlist(List *list);
int main()
{
List *list=creatList(); //创建表头
int K=list->K;
int N=list->N;
if (K==0&&N==0) return 0;
Node *tempN=NULL; //创建节点,写入数组
Node* node[N];
int i;
for(i=0;i<N;++i){
tempN=creatNode();
node[i]=tempN;
}
list->head=serchadd(node,list->address,N); //连接头结点
int N0;
N0=connectNode(node,list->head,N); //构造静态双向链表
int count=N0/K; //计算可以转置的次数
Node *p=list->head; //设置指针,指向要转置的链表段的首尾
if(p!=NULL) p->priorone=NULL;
Node *q=list->head;
int ret=0;
for(ret=0;ret<K-1;ret++){
if(p!=NULL) q=q->nextone;
}
int changehead=1; //第一次转置要更新表头
while(count){ //对链表进行分段转置
--count;
transpose(p,q,K);
if(changehead==1){
list->address=q->address;
list->head=q;
changehead=0;
}
p=p->nextone; //设置下一段的起始位置
q=p; //设置下一段的末端
if(count){
for(ret=0;ret<K-1;ret++){
q=q->nextone;
}
}
}
changenextadd(list); //更新节点的next地址数据
printlist(list);
return 0;
}
Node* serchadd(Node* node[],int address,int N)
{
int i;
for(i=0;i<N;++i){
if(node[i]->address==address){
return node[i];
}
}
return NULL;
}
List* creatList()
{
List *p;
p=(List*)malloc(sizeof(List));
scanf("%d",&(p->address));
scanf("%d",&(p->N));
scanf("%d",&(p->K));
return p;
}
Node* creatNode()
{
Node *p;
p=(Node*)malloc(sizeof(Node));
scanf("%d",&(p->address));
scanf("%d",&(p->data));
scanf("%d",&(p->next));
Node *priorone=NULL;
Node *nextone=NULL;
return p;
}
int connectNode(Node *node[],Node *head,int N)
{
int count=0;
Node *rear=head,*temp=head;
while(temp!=NULL){
temp=serchadd(node,rear->next,N);
rear->nextone=temp;
if(temp!=NULL ){
temp->priorone=rear;
}
rear=temp;
count++;
}
return count;
}
void transpose(Node *p1,Node *q1,int K)
{
int cnt=0;
Node *temp=q1;
for(cnt=0;cnt<K-1;++cnt){
q1=q1->priorone;
temp->priorone->nextone=temp->nextone;
temp->nextone=p1;
temp->priorone=p1->priorone;
p1->priorone=temp;
if(temp->priorone!=NULL) temp->priorone->nextone=temp;
temp=q1;
}
}
void changenextadd(List *list)
{
Node *p=list->head;
while(p->nextone!=NULL){
p->next=p->nextone->address;
p=p->nextone;
}
p->next=-1;
}
int printlist(List *list)
{
Node *p=list->head;
if(p!=NULL){
while(p->next!=-1){
printf("%05d %d %05d\n",p->address,p->data,p->next);
p=p->nextone;
}
printf("%05d %d %d\n",p->address,p->data,p->next);
}
else return 0;
}
其实我的这个写法夹杂了一些静态链表的影子,本来是想方便操作,结果后面DEBUG的时候更麻烦。这种方法虽然压缩了一些空间,但是时间复杂度远远超过了静态链表法,实在是捡了芝麻丢了西瓜。最后的PAT数据有一组没过,但是暂时找不到原因;还有一组数据超时,就是时间复杂度太高。
若用静态链表,将每个节点的地址作为数组下标,俗称打表,再构造链表,则时间复杂度大大减少,可以变成O(N)