<数据结构浙大>02-线性结构3 Reversing Linked List (25 分)

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 nonne

gative 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

题目分析:

由于这道题需要通过每一个输入的结点地址,将这些结点串联起来成为一个链表,所以这里可以创建一个结构数组arr[],将数组的索引设置为结点的地址,从而通过p->Next = &arr[pos]等操作将链表读入。

其次对于链表reverse操作,可以参照陈姥姥的教学(浙江大学数据结构 陈越_哔哩哔哩_bilibili),这里就不作赘述。

这道题更大的难点在于各种边界问题,已在代码中注释。

经过这几次练习,我对于指针的指针、引用、双向传递终于有了一个清晰的认识!其次,题目中每一个对范围大小的限定,都必须在代码中体现出来!

代码:

#include <iostream>
#define MaxSize 100000 //根据题意设置最大长度
using namespace std;

typedef int ElementType;

typedef struct Node* PtrNode;
struct Node {
    int Address;
    ElementType Data;
    int NextAdd;
    PtrNode   Next;
};
typedef PtrNode List;

struct Node arr[MaxSize];//结构数组 用Address作为数组的索引 这样方便将输入的结点连接起来!

PtrNode ReadList(int firstAddr, int* length)
{
    int addr;
    for (int i = 0; i < (*length); ++i) { //将输入的每组数都按索引存入数组
        cin >> addr;
        arr[addr].Address = addr;
        cin >> arr[addr].Data;
        cin >> arr[addr].NextAdd;
    }

    PtrNode head, p, temp;//创建链表
    head = new Node(); head->Next = NULL;//L为空的头结点
    p = head;
    int list_size = 0;//记录实际用到的链表长度                      
    int pos = firstAddr; //将pos初始化为链表的首地址,因为首地址一定是在这个链表内的
    while (arr[pos].Address != -1) {
        p->Next = &arr[pos];//这里重点!通过Next指针指向数组的地址(用&取地址),从而串联起来
        p = p->Next;
        ++list_size;
        if (arr[pos].NextAdd == -1) break;
        pos = arr[pos].NextAdd; //不要忘了 把pos更新为下一个结点的地址  
    }
    *length = list_size;//把length改为实际用到的list_size,这也就是为什么函数形参要写*length,main函数中要写&N,双向传递
    temp = head; head = head->Next; delete temp;//把空的头结点删掉
    return head;//返回头结点
}

List Reverse(List L, int reverse_length)
{
    List p1, p2, p3, rear;
    p1 = L->Next; p2 = p1->Next; p3 = p2->Next;

    while (--reverse_length) {
        p2->Next = p1;
        p1 = p2;
        p2 = p3;
        if (p3) p3 = p3->Next;
    }
    rear = L->Next;
    rear->Next = p2;
    L->Next = p1;
    return rear;
}



List ReverseList(List L, int length, int reverse_length)//主要为了边界处理
{
    if (reverse_length == 1)//K=1时,不用翻转,直接返回L
        return L;

    List head, p, temp;
    head = new Node(); head->Next = L;
    p = head;

    int t = length / reverse_length;//看需要几次翻转 比如6/3=2 就需要翻转两次 
    while (t--) {
        p = Reverse(p, reverse_length);
    }
    if (length % reverse_length == 0)//如果恰为整数倍,最后一个结点置空
        p->Next = NULL;

    temp = head;
    head = head->Next;
    delete temp;
    return head;
}

void PrintList(List L)
{
    List p;
    p = L;
    while (p) {
        if (!p->Next)
            printf("%05d %d %d\n", p->Address, p->Data, -1);
//这里也是细节,地址都是5位数,所以输出的时候用%05d,不够5位数往左边补0,例如00100
        else
            printf("%05d %d %05d\n", p->Address, p->Data, p->Next->Address);
        p = p->Next;
    }
}

int main()
{
    int firstAddr;
    int N, K;
    List L;
    cin>>firstAddr>>N>>K;

    L = ReadList(firstAddr, &N);
    L = ReverseList(L, N, K);
    PrintList(L);

    return 0;
}

运行结果:

 一些关于reverse的简单笔记:

 

 

  • 2
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

zbc-

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值