1074. Reversing Linked List

来源:互联网 发布:告白气球 知乎 编辑:程序博客网 时间:2024/05/29 19:53

题目

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 33218
Sample Output:
00000 4 33218
33218 3 12309
12309 2 00100
00100 1 99999
99999 5 68237
68237 6 -1

基本思路

考察链表的基本操作。由于题目中直接给出结点的地址,故使用静态链表。
1.使用静态链表做题时,定义结点的结构一般为

struct node{    int data;//数据域     int address,next;//结点的位置,下个结点的位置    xxx;//表示结点的某种性质}Node[maxn];

本题中,xxx 的部分可以定义为int order; 其中order表示结点在链表中的序号(从0开始),注意序号结点位置的区别(下面会再次提及)。初始化order为maxn,表示初始所有节点均为无效结点。
2.由题目给出的链表首地址开始遍历整个链表,并标记有效结点的order为0,1,2…n-1。(有效结点表示由题目给定的链表首地址所能遍历到的结点,无效结点即不在同一链表上的结点。在本题样例中全为有效结点。)
3.构造比较函数cmp,使结点按order的值从小到大排序。因此排序后,有效结点在Node[]的左侧,无效结点在右侧。
4.输出链表。每k个结点要反转一次,n个结点可分为n/k组,当n % k == 0 时表示恰好分为n/k组,反之则表示最后还有一部分剩余。

注意点

1.第一层for循环要执行n/k次,即共有n/k组需要反转;第二层for循环要执行k-1次,即每组内共有k个元素(其中每组的最后一个元素单独处理)。这里对于下标的处理要找一下规律。
2.对于每组的最后一个元素。若当前不是最后一组,则跳到下一组的最后一个;若当前是最后一组,那么再考虑n%k是否为0,这里又分两种情况——为0则直接输出-1 ,否则还要再处理最后剩余的一小部分。
2.直接用%05d 无法输出-1,因此最后一个结点要分开考虑。

代码
#include<cstdio>#include<algorithm>using namespace std;const int maxn = 100000;struct node{    int data;//数据域     int address,next;//Address是该结点的位置,next是下个结点的位置    int order;//表示结点在链表中的序号(从 0开始) }Node[maxn];//链表的静态实现 bool cmp(node a,node b){    return a.order < b.order;} int main(){    int addressBegin,n,k;//起始结点的位置,结点个数,要反转的子序列长度    scanf("%d%d%d",&addressBegin,&n,&k);    int address,next,data;    for(int i=0;i<n;i++){//输入n个结点的信息        scanf("%d%d%d",&address,&data,&next);        Node[address].address = address;        Node[address].data = data;        Node[address].next = next;     }     for(int i=0;i<maxn;i++){//初始化结点的性质         Node[i].order = maxn;    }    int p = addressBegin,count = 0;//count记录有效结点的个数     while(p != -1){//由起始结点开始遍历链表,对有效结点进行标记         Node[p].order = count++;        p = Node[p].next;    }     n = count;//将结点有效个数赋予n,方便习惯性的操作     sort(Node,Node+maxn,cmp);//排序,将有效结点移至左端 ,此时结点Node[i]的order 与 i 相同     for(int i = 0; i < n/k; i++){//n个元素,每k个元素内部进行反转,共有n/k个子序列需要反转         for( int j = (i+1)*k - 1; j > i*k; j--){//在每个子序列内,反向输出,但每组的最后一个结点单独处理             printf("%05d %d %05d\n",Node[j].address,Node[j].data,Node[j-1].address);         }        printf("%05d %d ",Node[i*k].address,Node[i*k].data);         //处理每组的最后一个结点         if(i < n/k - 1){//若不是最后一组,则指向下一组的最后一个结点             printf("%05d\n",Node[i*k + 2*k -1].address);            }else{//最后一组             if(n % k == 0){//恰可以分成n/k 个组                 printf("-1\n");            }else{//将剩下不完整的部分输出                 printf("%05d\n",Node[i*k + k].address);                 for(int j = n/k * k;j < n;j++){                    printf("%05d %d ",Node[j].address,Node[j].data);                    if(j < n-1) printf("%05d\n",Node[j].next);                    else printf("-1");                }             }         }    }    return 0;} 
反思总结

*本题要搞清楚为什么定义order?刚建立链表时,Node[]存储为Node[00100],…,Node[12309],……,Node[68237]。而通过定义order,由cmp对Node[]进行排序,Node[]则存储为 Node[0],Node[1],…,Node[n-1]。这样就方便了处理for循环。

0 0