好玩的约瑟夫环-单链表版本(题解源码C语言)

【题目描述】

有M个人,编号分别为1到M,玩约瑟夫环游戏,最初时按编号顺序排成队列;每遍游戏开始时,有一个正整数报数密码N,队列中人依次围坐成一圈,从队首的人开始报数,报到N的人出列,然后再从出列的下一人开始重新报数,报到N的人出列;重复这一过程,直至所有人出列,完成一遍游戏,所有出列的人形成新队列;游戏可能玩很多遍,每遍有新报数密码。求若干遍游戏完成后队列次序。本题要求使用单链表实现,程序要求采用模块化设计,格式规范,有合适注解。

【输入描述】

每个测试用例包含若干个正整数(至少1个),第一个正整数为玩游戏人数M,后续每个正整数为每遍游戏报数密码;报数密码可能为1

【输出描述】

每个测试用例结果占一行,每个编号占4位。

【样例输入】

10   3   5    2

【样例输出】

4   6   5   2   9   1   3   7   8  10

题解:

#include <stdio.h>
#include <stdlib.h>
#include <string.h>

struct Node
{
	int date;
	struct Node* next;
};

//创建链表 
struct Node* createList()
{
	struct Node* headNode = (struct Node*)malloc(sizeof(struct Node));
	//headNode变成一个变量
	//变量使用前初始化
	//headNode->date = 0;
	headNode->next = NULL;
	
	return headNode;
};

//创建结点 
struct Node* createNode(int date)
{
	struct Node* newNode = (struct Node*)malloc(sizeof(struct Node));
	newNode->date = date;
	newNode->next = NULL;
	return newNode;
}

//插入结点(尾插法) 
void insertNodebyTail(struct Node* headNode, int date)
{
	struct Node* pmove = headNode;
	while (pmove->next != NULL)
	{
		pmove = pmove->next;
	}
	struct Node* newNode = createNode(date);
	pmove->next = newNode;
}



//删除结点
void deleteNode(struct Node* headNode, int posDate)
{
	struct Node* posNode = headNode->next;
	struct Node* posNodefront = headNode;

	if (posNode == NULL)
	{
		printf("无法删除链表\n");
	}

	else
	{
		while (posNode->date != posDate)
		{
			posNodefront = posNode;
			posNode = posNodefront->next;

			if (posNode == NULL)
			{
				printf("未找到指定结点,无法删除\n");
				return;
			}
		}
		posNodefront->next = posNode->next;

		//return posNode->next;
		//free(posNode);
	}
}


//打印链表
void printList(struct Node* headNode)
{
	struct Node* pMove = headNode->next;

	while (pMove != NULL)
	{
		printf("%-4d", pMove->date);
		pMove = pMove->next;
	}
	printf("\n");
}

int main(void)
{

	struct Node* list = createList();//建两个表,一个用来存储信息,另一个用来存储导出的信息
	struct Node* list1 = createList();
	
	int M;//完游戏人数
	scanf_s("%d",&M);
	for (int i = 1; i <=M; i++)
	{
		insertNodebyTail(list,i);
	}
	
	

	int temp;//报数密码
	int flag = 0;//标记那个链表是空的
	 int count = 0;//记数
	 struct Node* p, * q;
	while(1)
	{
	
		
		if (scanf_s("%d", &temp) ==EOF)//由于不知道有多少个输入数据。所以用该条件跳出接受数据的循环(含义自己百度查)
		{
	    	break;
	    }
		if (temp == 10086) { break; }//测试时用于跳出循环
		if (flag == 0) {
			 p = list->next;
			while (p)
			{
				
				while (p) {
					count++;
					if (count == temp)
					{
						
						insertNodebyTail(list1, p->date);//将第一个符合条件的导入另一个链表

						deleteNode(list, p->date);//删除这个符合条件的数据

						count = 0;//重新开始计数
						
					}


					p = p->next;//回到第一个元素所在位置,循环,直到找到所有符合条件的数据(循环完后只剩下一个表头不在有数据)

				}
				p = list->next;
			}
			
			flag = 1;
			//printList(list1);
			//printList(list1);
		}
		   
		else {
			
			 q = list1->next;
			while (q)//原理同上
			{
				
				while (q) {
					
					count++;
					if (count == temp)
					{
						
						insertNodebyTail(list,q->date);
						deleteNode(list1,q->date);
						count = 0;
					}

					q = q->next;
				}
				q = list1->next;
			}
			
			flag = 0;
			//printList(list);
		}
		// printf("\n%d", k);
	}



	
	
		printList(list);//只有一个表是有数据的,直接打印即可,也可也用flag判断后在打印
		printList(list1);
	

	

	
	return 0;
}

  • 3
    点赞
  • 11
    收藏
    觉得还不错? 一键收藏
  • 2
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值