单循环链表解决约瑟夫环的问题

mac2024-06-27  52

题目:约瑟夫(Josephus)的一种描述是:编号为1,2,…,n的n个人按顺时针方向围坐一圈,每人持有一个密码(正整数)。一开始任选一个正整数作为报数上限值m,从第一个人按顺时针方向自1开始顺序报数,报到m时停止报数。报道m的人将出列,将他的密码作为新的m值,从他在顺时针方向上的下一个人开始重新从一报数,如此下去,直至所有的人全部出列为止。试设计一个程序求出出列顺序。

语言:C语言 要求:使用单循环链表模拟约瑟夫环

1.输入分析

本程序需要从计算机的命令行窗口输入,输入形式为 <*.exe> <人数n> <初始上限m> <密码1> <密码2> … <密码n> 用“空格”将各个数字隔开,以“回车键”作为输入结束的标志,人数n应与密码个数相同,人数n,初始上限m,密码均应为正整数,否则程序会有报错提示。

2.输出形式

假设命令行参数是齐全且正确的,输出约瑟夫环的出列顺序,并将输出结果导入文件中; 若输入参数有误,程序将有错误提示。

3.程序执行的命令包括

1)构造约瑟夫环;2)模拟约瑟夫环的执行过程;3)输出出列顺序;4)结束。

代码如下:

#include<stdio.h> #include<string.h> #include<stdlib.h> typedef struct LNode{ int data_1;//存储编号 int data_2;//存储密码 struct LNode *next; }LNode, * LinkList; LinkList InitList(){ //初始化单循环链表的头节点 LNode *node = (LNode*)malloc(sizeof(LinkList)); node->next = node; node->data_1 = NULL; node->data_2 = NULL; return node; } void ListInsert(LinkList head,LinkList p){ //将 p 结点插入带头结点的单循环链表的末尾 LinkList temp = head->next; while(temp->next != head){ temp = temp->next; } temp->next = p; p->next = head; return ; } int str_to_num(char *str){ //将字符串转换为数字 int num = 0; int i,length; length = strlen(str); for(i = 0 ; i < length ; i++ ){ if(str[i] < 48 || str[i] > 57){ printf("\n数据应为正整数,请重新输入数据\n\n"); exit(0); } num = num * 10 + (str[i] - '0'); } if(num <= 0){ printf("\n密码应为正整数,请重新输入数据\n\n"); exit(0); } return num; } int main(int argc,char **argv){ LinkList link_1 = InitList();//未出列的人的单循环链表的头节点,不存储实际数据 LinkList link_2 = InitList();//已出列的人的单循环链表的头节点,不存储实际数据 int n = str_to_num(argv[1]);//人数 int m = str_to_num(argv[2]);//初始最高上限 if(n != argc-3){ printf("\n人数与密码个数不匹配,请重新输入数据\n\n"); exit(0); } if(m <= 0){ printf("\n初始上限应为正整数,请重新输入数据\n\n"); exit(0); } //将输入的数据插入单循环链表link_1中 LNode *p; int i; for(i = 3 ; i < argc ; i++){ p = (LNode*)malloc(sizeof(LinkList)); p->data_2 = str_to_num(argv[i]); p->data_1 = i - 2; ListInsert(link_1,p); } int length_1 = argc - 3;//length_1为link_1中结点的个数 LinkList pre = link_1; LinkList curr = link_1->next; while(length_1){ for(i = 1 ; i < m ; i++){ pre = curr; if(curr->next != link_1){ curr = curr->next; } else{ curr = curr->next->next; } } //循环结束时,curr指向的结点的报数为 m ,更新m的值,在link_1中删去该节点,并插入该结点至link_2中 m = curr->data_2; pre->next = curr->next; ListInsert(link_2,curr); length_1--; if(pre->next == link_1) curr = pre->next->next; else curr = pre->next; } //将结果读入文件并输出 FILE* fp; char ch; if((fp = fopen("E:\\程序设计\\数据结构\\result.txt","w")) == NULL){ printf("\n无法打开此文件result.txt\n\n"); exit(0); } LinkList shuchu = link_2->next; while(shuchu != link_2){ ch = '0' + shuchu->data_1; fputc(ch,fp); fputc(' ',fp); printf("%d ",shuchu->data_1); shuchu = shuchu->next; } fclose(fp); return 0; }
最新回复(0)