二、基本要求 |
在控制台下实现约瑟夫环。
编号为1,2,3,……,n 的 n 个人按顺时针方向围坐一圈,每人持有一个密码(正整数)。一开始任选一个正整数作为报数上限值 m,从第一个人开始按顺时针方向自1开始报数,报到 m时停止报数。报m的人出列,将他的密码作为新的 m 值,从他在顺时针方向上的下一个人开始重新报数,如此下去,直至所有人全部出列为止。试设计一个程序求出出列顺序。
(1)m 的初值由用户输入,n值可以由用户输入可从读入的文件中统计。
(2)每个人应至少包含的信息:姓名、编号、密码。
(3)参照线性表的实现完成此程序。
(4)打印”约瑟夫环“的初始顺序信息,含有编号、姓名、密码。
(4)用户可选择按姓名或按编号打印出列顺序。
(6)本题提交整个程序的实现代码。
==========================头文件========================
#ifndef JOSEPHUS_H
#define JOSEPHUS_H
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <malloc.h>
#define HEAD_OF_FROM "编号 姓名 密码" //从文件读入时,忽略文件头
typedef struct Penson //每一个人的基本信息
{
int ID;
char name[10];
int code;
}Penson;
typedef struct Josephus //单循环链表
{
Penson p;
struct Josephus *next;
}SeqList;
SeqList *Creat(int n,Penson *P);//构造单循环链表
void OutQueue(SeqList *tail,int num ,int code);//删除节点,约瑟夫环的规则
int Open_File(int n,int m);//打开文件,从中读入需要的信息
#endif
======================函数实现========================
#include "Josephus.h"
SeqList *Creat(int n,Penson *P,int m)
{
SeqList *head = (SeqList *)malloc(sizeof(SeqList));//头节点
SeqList *rear,*q;//采用尾插法
if (!head)//验证分配成功
{
exit(0);
}
rear = head;
for (int i = 0;i< n;++i)
{
q = (SeqList *)malloc(sizeof(SeqList));
if (!q)
{
exit(0);
}
q->p.code = P[i].code;//数据域分配
q->p.ID = P[i].ID;
strcpy(q->p.name,P[i].name);
//指针域分配
rear->next = q;//尾指针的指针域指向q
rear = q;// 尾指针一直指向最后一个
}
rear->next = head->next;//构成单循环链表,尾指针指向头节点
OutQueue(head,n,m);//由约瑟夫环规则,删除节点
return head;
}
void OutQueue(SeqList *head,int n ,int m)
{
int choice = 1;
printf("请选择按何种方式显示出列顺序:/n[0]按姓名/n[1]按编号/n/n请输入你的选择(0-1):");
scanf("%d",&choice);
printf("/n出列顺序为:/n");
{
SeqList *p;
while (n!=1)//直到最后一个节点的时候,停止循环
{
m = (m-1)%n +1;//简化计算机的操作,节省空间复杂度,密码比人数大的时候,让链表少转几圈
//第一个节点的m值特殊处理
for (int i = 1;i<m;++i)
{
head = head->next; //依次循环
}
p = head->next;
if (choice == 0)
{
printf("%s/n",p->p.name);
}else{
printf("%d/n",p->p.ID);
}
head ->next = p->next;
m = p->p.code;//传递密码··把密码覆盖为新的m值
free(p);//删除节点
p = NULL;//将p赋新值,也可不用
--n;//计数器
}
}
if (choice == 0)
{
printf("%s/n",head->p.name);
}else{
printf("%d/n",head->p.ID);
}
//printf("%d/n",head->p.ID);
free(head);//释放链表,避免悬垂指针
head = NULL;
}
int Open_File(int n,int m)//文件操作
{
int i=0,j=0;
char *filename = "c://a.txt";//文件地址
Penson P[10];
FILE *fp = fopen(filename,"r");//只读方式打开
errno = 0;
if (!fp)
{
fprintf(stderr,"打开文件失败,Error code : %s/n",strerror(errno));
return -1;
}
fseek(fp,sizeof(HEAD_OF_FROM),SEEK_SET);
i = 0;
while (!feof(fp)&&i<n)
{
fscanf(fp,"%d %s %d/n",&P[i].ID,P[i].name,&P[i].code);
i++;
}
printf("/n约瑟夫环的初始顺序信息为:/n编号/t姓名/t 密码/n");
for (j = 0;j<n;j++)
{
printf(" %d/t%s/t%d/n",P[j].ID,P[j].name,P[j].code);
}
printf("/n");
Creat(n,P,m);//调用构造链表的函数
fclose(fp);
}
=============================主函数=========================
#include "Josephus.h"
int main(void)
{
int m,n;
printf("请输入m和n的初值:");
scanf("%d %d",&m,&n);
Open_File(n,m);
system("pause");
return 0;
}