PAT A 1074 B 1025(甲级 乙级)—— 静态链表的使用

1074 Reversing Linked List(25 分)

作者: CHEN, Yue

单位: 浙江大学

时间限制: 400 ms

内存限制: 64 MB

代码长度限制: 16 KB

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

 


 

这道题涉及到了数据结构中的链表的知识,当我把PAT甲级前107道题做完的时候发现关于链表的题目基本上都可以使用静态链表来解决,并且解决起来会比 动态链表好处理一些,因为链表我们通常是创建单向链表,但是好多题目中都会涉及到反向输出等单向动态链表比较难完成的操作,这时候使用静态链表就可以发挥很大的优势,所以如果是考PAT的同学,一定要多巩固静态链表的使用。

这道题的思路其实并不难,只要根据题目要求找到完整的链表,然后通过将链表以 k 个节点为一个单位分块,倒序输出,最后不足k个的单独分块(当然如果恰好 num % k == 0 是最好不过的),按顺序输出就可以了。

但是这一过程中有一个关键问题没有解决,那就是现在的链表还是单向的,怎么去发挥静态链表的优势呢,下边就是具体的方法:

我们可以在链表节点的结构体中加一个名为order的int型成员,这个成员用来记录这个节点在整个链表中出现的顺序,首先我们要把整个静态链表中所有的order都设置为一个负值或者是较大的值,然后我们遍历整个链表,这时链表中每个节点的order值就是他们出现的顺序,最后我们用sort函数对整个静态链表去排序,Node a, b在比较的过程中,如果两者有不在链表的成员,就排序靠后,如果两者都在链表中,那么谁的order较小谁在前边。这样排序完成之后就会发现我们把链表转换为了顺序表,顺序表随机存取是非常方便的,接下来我们就可以对他进行分块输出等操作了。

 

在最后输出处理的时候我们可以按照正常的逻辑顺序输出 当前node的address 当前node的data 下一个node的address,但是也可以换一种思路:

PAT A 1074 B 1025(甲级 乙级)—— 静态链表的使用_第1张图片

我们可以看到除了第一个node之外,后边的每一个node的address可以看做是输出了两次,只不过中间加了一个换行,这样思考还有一个好处就是,当前的输出与前后的输出不相关了,比如我输出当前块的最后一个元素的时候,还要输出下一个块的第一个元素,下一个块的第一个元素还需要分情况去处理,因为可能是下一个块的第一个元素(当下一个块是最后一个不足k个的块时),也可能是下一个块的最后一个元素。所以就会多了许多判断步骤,但是如果这样输出就和上下无关了,只需要判断这是不是第一个输出的节点,然后再最后循环输出完毕之后,再输出一个 -1\n 即可。

 

如果读着后边的技巧很晦涩,也可以结合代码去看,如果还有问题的话,可以留言问我。

当然《算法笔记》中使用了正常思维去解这道题,也可以参考。

 


 

AC代码:

#include 
#include 

using namespace std;

const int maxn = 100010;

struct Node {
    int address, key, next, order;
}node[maxn];

bool cmp(Node, Node);

int main() {
    int head, n, k;

    scanf("%d%d%d", &head, &n, &k);

    for(int i = 0; i < maxn; ++i) {
        node[i].order = -1;
    }

    for(int i = 0; i < n; ++i) {
        int add;
        scanf("%d", &add);
        scanf("%d%d", &(node[add].key), &(node[add].next));
        node[add].address = add;
    }

    int p = head, ordernum = 0;
    while(p != -1) {
        node[p].order = ordernum++;
        p = node[p].next;
    }

    sort(node, node + maxn, cmp);

    int i = k - 1, x = 0;
    while(i < ordernum) {
        for(int j = i; j > i - k; --j, ++x) {
            if(x != 0) {
                printf("%05d\n", node[j].address);
            }
            printf("%05d %d ", node[j].address, node[j].key);
        }
        i += k;
    }

    while(x < ordernum) {
        if(x != 0) {
            printf("%05d\n", node[x].address);
        }
        printf("%05d %d ", node[x].address, node[x].key);
        ++x;
    }
    printf("-1\n");

    return 0;
}

bool cmp(Node a, Node b) {
    if(a.order == -1 || b.order == -1) {
        return a.order != -1;
    } else {
        return a.order < b.order;
    }
}

 


 

如有错误,欢迎指摘。

你可能感兴趣的:(PAT练习题)