7-2 Reversing Linked List

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 (≤10 5 ) 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 33218

Sample Output:

00000 4 33218
33218 3 12309
12309 2 00100
00100 1 99999
99999 5 68237
68237 6 -1

 

       琢磨了好久才写出来的代码,没想到还是不完美【唉】,因为输入数据可以最多达到100000个,我的代码调用链表函数过多,导致时间复杂性过高,小部分样例就运行超时了【难受】,不过程序整体框架没问题,好歹25分满分也拿了22分【哈哈】。

#include<stdio.h>
#include<stdlib.h>

typedef struct Node List;
struct Node{
	int Addr;
	int Data;
	int NextAddr;
	List *Next; 
};

int num = 0;  //链表建好之后的链表节点数

List *ReadList(int N);
List *CreateList(List *L,int firstaddr,int N);
List *ListReverse(List *head,int K);
void PrintList(List *L);

int main()
{
	int N,K,FirstAddr;
	List *Read,*a;
	scanf("%d %d %d",&FirstAddr,&N,&K);
    Read = ReadList(N);
	a = CreateList(Read,FirstAddr,N);

	List *p = a;                                  //p指向链表头结点
    List *rp = NULL;                              //反转链表函数的返回值
	if(K == 1){
		PrintList(a);
	}else if(K <= num){
		for(int i=0; i<(num/K); i++){
			rp = ListReverse(p,K);
			p->Next = rp;            // 使p->Next 指向反转后链表的第一个节点
            p->NextAddr = rp->Addr;  // 更改NextAddr值,指向逆转后链表的下一个节点的Addr
            
			int j = 0;
			/*使p指向下一段需要反转的子链表的头结点(第一个节点的前一个节点)*/
            while (j < K){
                p = p->Next;
                j++;
            }
		}
    	PrintList(a);   //输出反转后链表
	}
	return 0;
 } 

List *ReadList(int N)  /*用单链表存储数据*/
{
	List *head,*rear;
	head = (List *)malloc(sizeof(struct Node));  //头结点 
	rear = head;              //rear始终指向终端结点,开始时指向头结点
	while( N-- ){
		List *p;
		p = (List *)malloc(sizeof(struct Node));
		scanf("%d %d %d",&(p->Addr),&(p->Data),&(p->NextAddr));
		rear->Next = p;
		rear = p;
	}
	rear->Next = NULL;
	
	return head;
}
 
List *CreateList(List *L,int firstaddr,int N)  //建立有顺序的单链表(尾插法) 
{
	int nextaddr = firstaddr;
	List *head,*rear,*p;
	head = (List *)malloc(sizeof(struct Node));  //头结点 
	rear = head;         //rear始终指向终端结点,开始时指向头结点
	
	while((N--) && (nextaddr != -1)){
		p = L->Next;     //每次都从链表头开始遍历 
		while( p ){
			if( p->Addr == nextaddr ){  /*若找到对应的下一结点*/
			    num++;
				List *q = (List *)malloc(sizeof(struct Node));  //申请结点空间 
				q->Addr = p->Addr;            //数据域赋值 
				q->Data = p->Data;
				q->NextAddr = p->NextAddr;
				rear->Next = q;               //尾插法 
				rear = q;
				break;
			}else{
				p = p->Next;         //没找到,链表指针后移 
			}
		}
		nextaddr = rear->NextAddr;     //每找到一个结点, nextaddr重新赋值 
	}
	rear->Next = NULL;
	
	return head;
}

List *ListReverse(List *head,int K)
{
	int cnt = 1;
	List *New,*Old,*Tmp;
	New = head->Next;
	Old = New->Next;
	while(cnt < K){
		Tmp = Old->Next;
		Old->Next = New;
		Old->NextAddr = New->Addr;  // 更改NextAddr值,指向逆转后其下一个节点的Addr
		New = Old;
		Old = Tmp;
		cnt++;
	}
	//使反转后的最后一个节点指向下一段子链表的第一个节点
    head->Next->Next = Old;  
    if (Old != NULL){
        //修改Next值,使它指向下一个节点的位置
        head->Next->NextAddr = Old->Addr; 
    }else{
        //如果old为NULL,即没有下一个子链表,那么反转后的最后一个节点即是真个链表的最后一个节点
        head->Next->NextAddr = -1;       
    }
    
	return New;
}

void PrintList(List *L)
{
	List *p = L->Next;  //链表带头结点,因此链表第一个非零项为下一个 
	while( p ){
		if( p->NextAddr != -1){
            //格式输出,%05d意味着如果一个整数不足5位,输出时前面补0 如:22,输出:00022
			printf("%05d %d %05d\n",p->Addr,p->Data,p->NextAddr); 
		}else{
		    //-1不需要以%05d格式输出
			printf("%05d %d %d\n",p->Addr,p->Data,p->NextAddr); 
		}
		p = p->Next;
	}
}

 

 不愿放弃的我只好去找度娘了。【。。。】

借鉴了一位仁兄的代码,终于把代码撸出来了。。。

#include<stdio.h>
#include<stdlib.h>

#define MaxSize 100005

typedef struct Node List;
typedef struct Node{
	int Addr;
	int Data;
	int NextAddr;
	List *Next; 
}LNode;

List *ListReverse(List *head,int K);
void PrintList(List *L);

int main()
{
	int N,K,FirstAddr;
	int num = 0;          //链表建好之后的链表节点数
    int data[MaxSize];   //存data值 节点位置作为索引值
    int next[MaxSize];   //存next值 节点位置为索引
    int tmp;              //临时变量,输入的时候用
    
    scanf("%d %d %d", &FirstAddr, &N, &K);    
    LNode a[N+1];                //能存N+1个结点的数组
    a[0].NextAddr = FirstAddr;   //a[0] 作为头结点
    //读输入的节点   
    for (int i = 1; i < N+1; i++){
        scanf("%d", &tmp);
        scanf("%d %d", &data[tmp], &next[tmp]);        
    }
    
    //构建单链表
    int i = 1;
    while (1){
        if (a[i-1].NextAddr == -1){
            a[i-1].Next = NULL;
            num = i-1;
            break;            
        }
        //a[0].NextAddr = FirstAddr;  //a[0] 作为头结点
        a[i].Addr = a[i-1].NextAddr;
        a[i].Data = data[a[i].Addr]; 
        a[i].NextAddr = next[a[i].Addr];
        a[i-1].Next = a+i;
                
        i++;
    }

	List *p = a;                                  //p指向链表头结点
    List *rp = NULL;                              //反转链表函数的返回值
	if(K == 1){
		PrintList(a);
	}else if(K <= num){
		for(int i=0; i<(num/K); i++){
			rp = ListReverse(p,K);
			p->Next = rp;            // 使p->Next 指向反转后链表的第一个节点
            p->NextAddr = rp->Addr;  // 更改NextAddr值,指向逆转后链表的下一个节点的Addr
            
			int j = 0;
			/*使p指向下一段需要反转的子链表的头结点(第一个节点的前一个节点)*/
            while (j < K){
                p = p->Next;
                j++;
            }
		}
    	PrintList(a);   //输出反转后链表
	}
	return 0;
 } 

List *ListReverse(List *head,int K)
{
	int cnt = 1;
	List *New,*Old,*Tmp;
	New = head->Next;
	Old = New->Next;
	while(cnt < K){
		Tmp = Old->Next;
		Old->Next = New;
		Old->NextAddr = New->Addr;  // 更改NextAddr值,指向逆转后其下一个节点的Addr
		New = Old;
		Old = Tmp;
		cnt++;
	}
	//使反转后的最后一个节点指向下一段子链表的第一个节点
    head->Next->Next = Old;  
    if (Old != NULL){
        //修改Next值,使它指向下一个节点的位置
        head->Next->NextAddr = Old->Addr; 
    }else{
        //如果old为NULL,即没有下一个子链表,那么反转后的最后一个节点即是真个链表的最后一个节点
        head->Next->NextAddr = -1;       
    }
    
	return New;
}

void PrintList(List *L)
{
	List *p = L->Next;  //链表带头结点,因此链表第一个非零项为下一个 
	while( p ){
		if( p->NextAddr != -1){
            //格式输出,%05d意味着如果一个整数不足5位,输出时前面补0 如:22,输出:00022
			printf("%05d %d %05d\n",p->Addr,p->Data,p->NextAddr); 
		}else{
		    //-1不需要以%05d格式输出
			printf("%05d %d %d\n",p->Addr,p->Data,p->NextAddr); 
		}
		p = p->Next;
	}
}

非常感谢这位兄弟-https://blog.csdn.net/weixin_42182906/article/details/80343251,想法真心不错。

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值