PAT乙级真题 1025 反转链表 C++实现

题目

给定一个常数 K 以及一个单链表 L,请编写程序将 L 中每 K 个结点反转。例如:给定 L 为 1→2→3→4→5→6,K 为 3,则输出应该为 3→2→1→6→5→4;如果 K 为 4,则输出应该为 4→3→2→1→5→6,即最后不到 K 个元素不反转。
输入格式:
每个输入包含 1 个测试用例。每个测试用例第 1 行给出第 1 个结点的地址、结点总个数正整数 N (≤10 ^ 5)、以及正整数 K (≤N),即要求反转的子链结点的个数。结点的地址是 5 位非负整数,NULL 地址用 −1 表示。
接下来有 N 行,每行格式为:
Address Data Next
其中 Address 是结点地址,Data 是该结点保存的整数数据,Next 是下一结点的地址。
输出格式:
对每个测试用例,顺序输出反转后的链表,其上每个结点占一行,格式与输入相同。
输入样例:
00100 6 4
00000 4 99999
00100 1 12309
68237 6 -1
33218 3 00000
99999 5 68237
12309 2 33218
输出样例:
00000 4 33218
33218 3 12309
12309 2 00100
00100 1 99999
99999 5 68237
68237 6 -1

思路

终于碰到有些难度的题目了。

用map存储该模拟链表,以做到由地址直达节点。

确实建立一个模拟单链表,逐段手工反转指针(尝试过建立成双向链表,节点中加入pre字段,感觉有些取巧了)。

反转每段单向链表时,入栈存储节点地址,出栈替换next指针。记录上一段链表的头,当遍历到下一段链表的尾时,将二者连起来。

需要注意的坑:

  1. 测试点5考察大规模数据量,输入输出用cin cout就会超时。原本考虑用string存储地址,但scanf和printf都不支持直接读入或输出string(都需要额外转换操作),故转而都改成int,输出如00100的数字时用控制格式输出。

  2. 测试点6考察“存在无效节点”的情况,真是挖的一手好坑。需要重新遍历一遍,计算有效节点的数量。

算法

#include <iostream>
#include <stack>
#include <map>
using namespace std;

struct Node{
    int addr;
    int data;
    int next;
};

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

    map<int, Node> nodeMap;
    for (int i=0; i<n; i++){
        Node *node = new Node();
        scanf("%d %d %d", &node->addr, &node->data, &node->next);
        nodeMap[node->addr] = *node;
    }
    //注意坑!并非所有节点都有效,需重新数有效节点数
    n = 0;
    for (int h=head; h!=-1; h=nodeMap[h].next){
        n++;
    }

    int len = n;
    int curHead = head;
    int preHead = -1;

    while (len >= k){
        int p = curHead;
        stack<int> s;
        //p从头遍历到尾
        for (int i=0; i<k-1; i++){
            s.push(p);
            p = nodeMap[p].next;
        }
        //若是第一组,将其尾作为新的总的头
        if (len==n){
            head = p;
        }
        //关联上一组的头和当前组的尾
        if (preHead!=-1){
            nodeMap[preHead].next = p;
        }
        //curHead指向下一组
        preHead = curHead;
        curHead = nodeMap[p].next;
        //反转链表
        for (int i=0; i<k-1; i++){
            nodeMap[p].next = s.top();
            p = s.top();
            s.pop();
        }
        len -= k;
    }
    nodeMap[preHead].next = curHead;
    int p = head;
    for (int i=0; i< n-1; i++){
        printf("%05d %d %05d\n", nodeMap[p].addr, nodeMap[p].data, nodeMap[p].next);
        p = nodeMap[p].next;
    }
    printf("%05d %d -1\n", nodeMap[p].addr, nodeMap[p].data);
    return 0;
}
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值