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 nonne
gative 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
题目分析:
由于这道题需要通过每一个输入的结点地址,将这些结点串联起来成为一个链表,所以这里可以创建一个结构数组arr[],将数组的索引设置为结点的地址,从而通过p->Next = &arr[pos]等操作将链表读入。
其次对于链表reverse操作,可以参照陈姥姥的教学(浙江大学数据结构 陈越_哔哩哔哩_bilibili),这里就不作赘述。
这道题更大的难点在于各种边界问题,已在代码中注释。
经过这几次练习,我对于指针的指针、引用、双向传递终于有了一个清晰的认识!其次,题目中每一个对范围大小的限定,都必须在代码中体现出来!
代码:
#include <iostream>
#define MaxSize 100000 //根据题意设置最大长度
using namespace std;
typedef int ElementType;
typedef struct Node* PtrNode;
struct Node {
int Address;
ElementType Data;
int NextAdd;
PtrNode Next;
};
typedef PtrNode List;
struct Node arr[MaxSize];//结构数组 用Address作为数组的索引 这样方便将输入的结点连接起来!
PtrNode ReadList(int firstAddr, int* length)
{
int addr;
for (int i = 0; i < (*length); ++i) { //将输入的每组数都按索引存入数组
cin >> addr;
arr[addr].Address = addr;
cin >> arr[addr].Data;
cin >> arr[addr].NextAdd;
}
PtrNode head, p, temp;//创建链表
head = new Node(); head->Next = NULL;//L为空的头结点
p = head;
int list_size = 0;//记录实际用到的链表长度
int pos = firstAddr; //将pos初始化为链表的首地址,因为首地址一定是在这个链表内的
while (arr[pos].Address != -1) {
p->Next = &arr[pos];//这里重点!通过Next指针指向数组的地址(用&取地址),从而串联起来
p = p->Next;
++list_size;
if (arr[pos].NextAdd == -1) break;
pos = arr[pos].NextAdd; //不要忘了 把pos更新为下一个结点的地址
}
*length = list_size;//把length改为实际用到的list_size,这也就是为什么函数形参要写*length,main函数中要写&N,双向传递
temp = head; head = head->Next; delete temp;//把空的头结点删掉
return head;//返回头结点
}
List Reverse(List L, int reverse_length)
{
List p1, p2, p3, rear;
p1 = L->Next; p2 = p1->Next; p3 = p2->Next;
while (--reverse_length) {
p2->Next = p1;
p1 = p2;
p2 = p3;
if (p3) p3 = p3->Next;
}
rear = L->Next;
rear->Next = p2;
L->Next = p1;
return rear;
}
List ReverseList(List L, int length, int reverse_length)//主要为了边界处理
{
if (reverse_length == 1)//K=1时,不用翻转,直接返回L
return L;
List head, p, temp;
head = new Node(); head->Next = L;
p = head;
int t = length / reverse_length;//看需要几次翻转 比如6/3=2 就需要翻转两次
while (t--) {
p = Reverse(p, reverse_length);
}
if (length % reverse_length == 0)//如果恰为整数倍,最后一个结点置空
p->Next = NULL;
temp = head;
head = head->Next;
delete temp;
return head;
}
void PrintList(List L)
{
List p;
p = L;
while (p) {
if (!p->Next)
printf("%05d %d %d\n", p->Address, p->Data, -1);
//这里也是细节,地址都是5位数,所以输出的时候用%05d,不够5位数往左边补0,例如00100
else
printf("%05d %d %05d\n", p->Address, p->Data, p->Next->Address);
p = p->Next;
}
}
int main()
{
int firstAddr;
int N, K;
List L;
cin>>firstAddr>>N>>K;
L = ReadList(firstAddr, &N);
L = ReverseList(L, N, K);
PrintList(L);
return 0;
}
运行结果:
一些关于reverse的简单笔记: