PAT乙级练习题B1025.反转链表

题目描述

给定一个常数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(<= 105)、以及正整数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

题目解析

将链表按顺序每K个节点反转一次,需要注意反转后第K个节点的next的指向,因为第K个节点后的K个节点也反转了,所以第K个节点的next要指向后面K个节点反转后的第一个节点。我原来没注意,代码提交后只有两个报错,我在这里卡了半天,现在想想可能只有那两个测试点是把K的反转循环跑了两遍以上的,所以循环还是要自己手推走两遍。
还有一个需要注意的地方是,给出的节点中可能存在无用节点,所以不要用N作为反转的循环判定条件。
这里我使用map来存储节点,能够比较好的模拟真实的链表,可以按需求申请内存,内存占用要小些。
我看其他人的代码,发现大家基本上是把链表按顺序存到vector或数组里面,反转后可以直接把节点的next指向数组中顺序的下一个节点地址,所以没有遇到我上面讲的第一个问题。不过我感觉这样就失去了对链表操作的本意,真实情况下若是链表大小超过了内存,这样做就不行了。

代码

#include
#include
#include
#include
using namespace std;

struct node
{
    int value;
    int next;
};

int main()
{
    int first, N, K, address;
    cin >> first >> N >> K;    //读入首行数据
    if (first == -1)
    {
        cout << -1 << endl;
        system("pause");
        return 0;
    }
    map<int, node> L;
    node nod;
    for (int i = 0; i < N; ++i)        //读入节点数据
    {
        cin >> address >> nod.value >> nod.next;
        L[address] = nod;
    }
    if (K != 1)       //K不等于1则开始反转链表
    {
        vector<int> list(K);
        address = first;
        int last;
        for (int i = 0; address != -1; i = 1)   //到最后节点则停止,注意这里不要使用N作为条件,因为所给的节点中可能包含无用节点
        {
            bool break_flag = 0;
            for (int j = 0; j < K; ++j)       //读取K个节点进行反转
            {
                list[j] = address;            //按链表顺序将节点地址读入数组
                address = L[address].next;
                if (address == -1 && j != K - 1)       //若读不满K个节点则停止
                {
                    break_flag = 1;
                    break;
                }
            }
            if (break_flag)
            {
                break;
            }
            reverse(list.begin(), list.end());       //将节点地址数组反转
            for (int j = 0; j < K - 1; ++j)
            {
                L[list[j]].next = list[j + 1];
            }
            L[list[K - 1]].next = address;
            if (i == 0)
            {
                first = list[0];
            }
            else
            {
                L[last].next = list[0];            //注意,后面一组K个节点的反转会导致前面一组K个节点的最后一个节点的next指向错误,需要修正
            }
            last = list[K-1];
        }
    }
    address = first;
    while (address != -1)    //输出链表
    {
        nod = L[address];
        if (nod.next != -1)
        {
            printf("%05d %d %05d\n", address, nod.value, nod.next);
        }
        else
        {
            printf("%05d %d %d", address, nod.value, nod.next);
            cout << endl;
        }
        address = nod.next;
    }

    system("pause");
    return 0;
}

你可能感兴趣的:(PAT乙级)