浙江大学-陈越-数据结构-02-线性结构3 Reversing Linked List 可通过C语言代码

这个题目一开始我用的是排序输出的办法,想要投机取巧,但无奈除了各种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;
}

通过截图:
在这里插入图片描述

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值