PAT 1110 区块反转(C语言25分,包含第六个测试点解决思路)

定一个单链表 L,我们将每 K 个结点看成一个区块(链表最后若不足 K 个结点,也看成一个区块),请编写程序将 L 中所有区块的链接反转。例如:给定 L 为 1→2→3→4→5→6→7→8,K 为 3,则输出应该为 7→8→4→5→6→1→2→3。

输入格式:

每个输入包含 1 个测试用例。每个测试用例第 1 行给出第 1 个结点的地址、结点总个数正整数 N (≤105)、以及正整数 K (≤N),即区块的大小。结点的地址是 5 位非负整数,NULL 地址用 −1 表示。

接下来有 N 行,每行格式为:

Address Data Next

其中 Address 是结点地址,Data 是该结点保存的整数数据,Next 是下一结点的地址。

输出格式:

对每个测试用例,顺序输出反转后的链表,其上每个结点占一行,格式与输入相同。

输入样例:

00100 8 3
71120 7 88666
00000 4 99999
00100 1 12309
68237 6 71120
33218 3 00000
99999 5 68237
88666 8 -1
12309 2 33218

输出样例:

71120 7 88666
88666 8 00000
00000 4 99999
99999 5 68237
68237 6 00100
00100 1 12309
12309 2 33218
33218 3 -1

代码长度限制16 KB

时间限制400 ms

内存限制64 MB

第六个测试点大坑

输入可能出现多余结点,例如以下测试数据中真正有意义的链表节点少于输入的N

输入
33333 3 1
11111 10 -1
33333 30 22222
22222 20 -1
正确输出
22222 20 33333
33333 30 -1

这里如果忽视了多余节点的情况就可能出现这种错误结果

00000 0 22222
22222 20 33333
33333 30 -1
解决思路;
  1. 通过循环筛查找出真正有意义的链表结点长度

  1. 在后续用新的nodes存放筛查后的链表,避免整个代码都使用N进行计算

程序代码

#include<stdio.h>
#include<string.h>
typedef struct
{
    int addr;
    int data;
    int next;
}Node;
int main()
{
    int firstAddr, N, K, firstAddr1, k, len;
    scanf("%d %d %d", &firstAddr, &N, &K);
    Node nodes[100002];//下标为节点地址,用于输入地址
    int addr;
    int i, j;
    for (i = 0; i < N; i++)
    {
        scanf("%d", &addr);
        scanf("%d %d", &nodes[addr].data, &nodes[addr].next);
    }
    Node Nodes[100002];//下标从0到len,用于重新整理输出时的顺序
    Nodes[0].addr = firstAddr;
    Nodes[0].data = nodes[firstAddr].data;
    Nodes[0].next = nodes[firstAddr].next;
    for (i = 1; i < N; i++)
    {
        if (Nodes[i - 1].next != -1)
        {
            Nodes[i].addr = Nodes[i - 1].next;
            Nodes[i].data = nodes[Nodes[i].addr].data;
            Nodes[i].next = nodes[Nodes[i].addr].next;
        }
        else
        {
            break;
        }
    }
    len = i;//防止出现多余结点,筛查有意义链表节点的长度
    int c, d;//c存放区块数量,d存放最后一个不足K个结点的区块
    c = len / K; d = len % K;
    if (d != 0)
    {
        if (c != 0)
        {
            Nodes[len - 1].next = Nodes[len - K - d].addr;
            Nodes[K - 1].next = -1;
        }
        else
            Nodes[len - 1].next = -1;
    }
    else
    {
        Nodes[K - 1].next = -1;
    }
    for (i = c * K - 1, j = c * K - 2 * K; j >= 0; i = i - K, j = i - 2 * K + 1)
    {
        Nodes[i].next = Nodes[j].addr;//确定新的链表顺序
    }
    Node newnodes[100002];//下标为节点地址,使输出时用while函数更方便
    for (k = 0; k < len; k++)
    {
        newnodes[Nodes[k].addr].addr = Nodes[k].addr;
        newnodes[Nodes[k].addr].data = Nodes[k].data;
        newnodes[Nodes[k].addr].next = Nodes[k].next;
    }
    if (c != 0)
        i = (d == 0 ? len - K : len - d);
    else
        i = 0;
    firstAddr1 = Nodes[i].addr;//输出时的第一个地址
    while (firstAddr1 != -1)
    {
        if (newnodes[firstAddr1].next != -1)
            printf("%05d %d %05d\n", newnodes[firstAddr1].addr, newnodes[firstAddr1].data, newnodes[firstAddr1].next);
        else
            printf("%05d %d -1\n", newnodes[firstAddr1].addr, newnodes[firstAddr1].data);
        firstAddr1 = newnodes[firstAddr1].next;
    }
    return 0;
}

  • 4
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值