这个题目一开始我用的是排序输出的办法,想要投机取巧,但无奈除了各种BUG,看了陈越姥姥的讲解[ 在第四讲:树(中)]里,决定用正常的反转链表方法。里边各种指针什么的搞得人头晕,再加上我自己变量命名的办法搞得我更晕了。
特别注意的是测试点“有多余结点不在链表上”,因为我在反转的时候计算反转次数用到了总的节点数目,所以当有多余节点时,反转次数就受到了影响,最后输出了错误答案。
因此,写一个函数用于统计链表中有效节点的个数,再反转就不会出问题了
可通过代码如下:
#include<stdio.h>
#pragma warning( disable : 4996)
#define MaxSize 100000
struct Node
{
int Data;
int Next;
};
// 全局变量
struct Node virtual_memeory[MaxSize];// 申请一个MaxSize大小的数组用于模拟内存
// 将输入存入数组的对应位置
void ReadandSave(int NodeNum);
// 将链表反转,返回头结点位置(数组下标)
int Reverse(int head,int NodeNum, int ReverseLen);
// 按照题目要求输出数组
void PrintList(int ListHead);
// 计算链表中有效节点的个数
int CalEffectiveNodeNum(int ListHead);
int main()
{
int head, NodeNum, ReverseLen;// ReverseLen为每次翻转的长度
scanf("%d %d %d", &head, &NodeNum, &ReverseLen);// 读入第一行数据(头结点地址,节点数,翻转长度)
ReadandSave(NodeNum);
int EffectiveNodeNum = CalEffectiveNodeNum(head);
int newhead = Reverse(head, EffectiveNodeNum, ReverseLen);
PrintList(newhead);
return 0;
}
void ReadandSave(int NodeNum)
{
int address, data, next;// 数组下标即为地址
for (int i = 0; i < NodeNum; i++)
{
scanf("%d %d %d", &address, &data, &next);
virtual_memeory[address].Data = data;
virtual_memeory[address].Next = next;
}
}
int Reverse(int head, int NodeNum, int ReverseLen)
{
if (NodeNum == 1 || ReverseLen==1)// 若输入链表只有1个节点或反转长度为1,直接返回
return head;
// 开始翻转
int ReverseNum = NodeNum / ReverseLen;// TODO:会受到节点数目影响,写一个函数统计有效节点数
int CurrentHead;// 当前轮次的头指针
int ListHead = head;// 链表总的头指针
CurrentHead = head;// 第一轮的头指针为本来的头指针
int front;// front指向当前需逆转节点的前一个节点
int rear;// rear指向当前需逆转的节点
int tmp;// 记录当前头结点本来的下个结点,否则后面的链表就丢了
int LastTail;// 上一次运行的队尾,用于下次运行时上次的队尾指针
for (int i = 1; i <= ReverseNum; i++)
{
// 新的一轮,重置指针
front = CurrentHead;
rear = virtual_memeory[front].Next;
tmp = virtual_memeory[rear].Next;
for (int j = 1; j <= ReverseLen-1; j++)
{
virtual_memeory[rear].Next = front;
// 三个指针整体向后移动
front = rear;
rear = tmp;
tmp = virtual_memeory[rear].Next;
}
if (i == 1)
ListHead = front;// 第一轮时的front为整个新链表的头指针
else
virtual_memeory[LastTail].Next = front;// 将本轮产生的新链表和上一轮的接起来
virtual_memeory[CurrentHead].Next = rear;// 将本轮的第一个节点的指针指向后面链表的第一个节点
LastTail = CurrentHead;
CurrentHead = rear;
}
return ListHead;
}
void PrintList(int ListHead)
{
int p = ListHead;
int n;
while (p != -1)
{
n = virtual_memeory[p].Next;
if(n == -1)// 保证-1原样输出而不是输出-00001
printf("%05d %d %d\n", p, virtual_memeory[p].Data, n);
else
printf("%05d %d %05d\n", p, virtual_memeory[p].Data, n);
p = n;
}
}
int CalEffectiveNodeNum(int ListHead)
{
int p = ListHead;
int num = 0;
while (p != -1)
{
num += 1;
p = virtual_memeory[p].Next;
}
return num;
}
通过截图: