约瑟夫环实现(实验报告)

约瑟夫环

1.实验目的
本次实验意在通过对循环链表的构建删除等操作加强同学对单链表.循环链表的认识和使用,提高同学对结构体的自定义以及指针应用等方面的理解。
2.实验内容与要求
① 问题描述:编号为1到n的n个人,按顺时针方向围成一个环(循环单链表),每人都持有一个密码(正整数)。任选一个正整数作为报数的上限(设为m),从第一个人开始按顺时针方向从1开始顺序报数,当报到m时,暂停报数并输出其标识(位序),同时将报数为m的人删除,并将他的密码作为新的m值,继续从1开始重新报数,直到m并输出。如此重复,直到全部人员都从队列中输出。编写程序,求出该出列顺序。
② 利用循环单链表实现这个过程,单链表的结点约定如下:
Typedef struct LNode {
int IDCode; // 人员标识
int PWD; // 人员密码
struct Lnode *next; // 指针域
} LNode, *LinkList;

在这里插入图片描述

其中,L为不带头结点的单链表的头指针,mi是第i个人的密码(1≤i≤n)。请按这个约定编程。
③ 测试数据:20≤n≤30
要求:参数n和m从键盘上输入,同时输入每个人的密码,存放在数组PWD中,利用这些参数构建单链表并完成出列顺序的输出。输入的次序为人员标识(位序)。
④ 主程序约定如下:
main () { //以下仅仅是描述,请大家按照要求完善代码
int PWD[30]; //定义密码数组
printf(“输入人员数n”);
scanf(%d,n);
printf(“输入初始密码m”);
scanf(%d,m);
createJoseph( int n , int PWD); //建立Joseph环,返回指向最后一个结点的指针p
printIDCode(LinkList P , int m); //输出每个人员的编号,当m大于n时,应该取n的模
printf(“以上是张三的运行结果。”);
}
⑤ 提升练习

  1. 构造顺序文件存放人员密码,根据n读取前n个数据作为密码,实现以上功能;
  2. 最后建立的p结点的指针,指向了前面的某一个元素结点(未必是第一个),请按上述要求,输出环中的所有人员标识符。
  1. 实验过程与结果
    实验环境:codeblock
    完整代码:
#include <stdio.h>
#include <stdlib.h>
#include<time.h>
typedef struct  LNode {
               int  IDCode;   // 人员标识
               int  PWD;     // 人员密码
               struct Lnode  *next;      // 指针域
}LNode, *LinkList;
//构造一个空的单链表
LNode *InitJoseph(LinkList L)
{
    if(L==NULL)
    {
        printf("初始化单链表错误!\n");
        exit(1);
    }
    else
    L->next=L;
     return L;
}
//插入人员密码构造循环单链表
LNode *createJoseph(int n,int PWD,LinkList L)
{
    LinkList p=L,q;
    int i=1;
       if (n==1)
      {
          p->IDCode=n;
          p->PWD=PWD;
          p->next=p;
          return p;
      }
else
      {
          q=(LinkList)malloc(sizeof(LNode));
          q->IDCode=n;
          q->PWD=PWD;
          q->next=p->next;
          p->next=q;
          return q;
      }
}
//定义遍历函数输出构造好的循环链表的数据
void TraverseList(LinkList L, int n)
  {
      int i=0;
      LinkList p=L;
      printf("参与的人的编号为:\n");
      while (i<n)
     {
          printf("%d\t",p->IDCode);
          p=p->next;
          i++;
     }
      p=L;
      printf("\n参与人的对应密码为:\n");
       while (i>0)
     {
          printf("%d\t", p->PWD);
          p=p->next;
          i--;
     }
      printf("\n");
  }
//定义删除函数
void printIDCode(LinkList L, int n, int PWD)
  {    int i,m;
    LinkList p=L,q;
    m=PWD;
    while(n>0)
        {
               if(m>n)
                m=m%n;//求余m,减少运算次数
                if(m==1)
                for(i=1;i<n;i++)
                p=p->next;
              for(i=1;i<m-1;i++)//寻找要删除的成员的前一个成员,找到后令p指向
              {
                   p=p->next;
              }
                   q=p->next;//q为要删除的成员
                   p->next=q->next;
                   printf("删除 %d 号成员\t该成员持有的密码为 %d 号\n",q->IDCode,q->PWD);
                   m=q->PWD;
                   free(q);
                   p=p->next;
                   n--;
      }
  }
  //定义随机指针函数
void random(LinkList L,int n,int m)
{
    int i,t;
    printf("\n生成一个指针T随机指到第t个人:\n");
    srand((unsigned)time(NULL));
    for(i=20;i<=30;i++)
        t=(rand()%(30-20))+20;
        printf("生成的随机数为\t%d",t);
            for(i=1;i<t;i++)
            L=L->next;
    printf("此时游戏从第 %d 号成员开始\n该成员持有的密码为 %d 号\n",L->IDCode,L->PWD);
    printIDCode(L,n,m);
    printf("\n******************以上是随机指针测试结果*****************\n");
}
void savecode(int n,int M[])
{
	FILE *fp;
	char filename[20];
	int i;
	printf("请输入要保存的文件名称:\n");
	scanf("%s",filename);
	if((fp=fopen(filename,"wb"))==NULL)//打开输出文件
	{
		printf("cannot open file:\n");
		return;
	}
	for(i=0;i<n;i++)
	{
		if(fwrite(&M[i],sizeof(int),1,fp)!=1)//数组向磁盘文件写入
			printf("file write error!\n");
	}
	    printf("保存文件成功!!!");
	fclose(fp);
}
void readcode(int n,int M[])
{
    FILE *fp;
    char filename[20];
    int i;
    printf("请输入读入的文件名:");
    scanf("%s",filename);
	if((fp=fopen(filename,"rb"))==NULL)//以只读方式打开二进制文件
	{   printf("can not open file\n");
		fclose(fp);
	}
	for(i=0;i<n;i++)
    fread(&M[i],sizeof(int),1,fp);//磁盘文件向数组读入
    printf("读入数据成功!!!!");
    fclose(fp);
}
void main()
{int i,n,m;
int c;    
char filename[20];
LinkList p,L;
int PWD[30];//定义密码数组
printf("请输入参与人员人数n:\n");
scanf("%d",&n);
printf("请输入初始密码m:\n");
scanf("%d",&m);
printf("\n1-请依次输入各成员密码");
printf("\n2-创建约瑟夫环");
printf("\n3-文件存储约瑟夫环密码");
printf("\n4-从文件中读取各成员密码");
printf("\n5-进行普通删除操作");
printf("\n6-进行随机生成删除操作");
printf("\n7-输出所有成员编号及该成员对应的密码信息");
while(1)
    {  printf("\n请输入你想进行操作的序号:\n");
scanf("%d",&c);
switch(c)
{
  case 1:
       {
           printf("请依次输入各成员密码:\n");
           for(i=0;i<n;i++)//构造密码数组时候n可以换成其他数比如30;
           scanf("%d",&PWD[i]);
       }
       break;
  case 2:
       {
            L=((LinkList)malloc(sizeof(LNode)));
            L=InitJoseph(L);
            p=L;
            for(i=0;i<n;i++)
              {
     p=createJoseph(i+1,PWD[i],p);//建立Joseph环,返回指向最后一个结点的指针p
              }
            printf("约瑟夫环构建成功!!!");
            L=p->next;//此时L指向第一个节点
       }
        break;
  case 3:
    {
          savecode(n,PWD);//构造文件存放密码,密码数据可以不是n个
    }
    break;
  case 4:
    {
        readcode(n,PWD);//读取前n个数作为密码;
    }
     break;
  case 5:
    {
        printIDCode(L,n,m);
        printf("\n******************以上是程序测试结果*****************\n");
    }
     break;
  case 6:
      {
          random(L,n,m);
      }
       break;
    case 7:
        {
            TraverseList(L,n);
        }
        break;
    default: break;
   } if((c<1)||(c>7))
             break;

}
}

代码运行结果:
实验测试使用数据:m的初值为20;n=7,7个人的密码依次为:3,1,7,2,4,8,4,正确的出列顺序为6,1,4,7,2,3,5。
一次运行程序,进行输入成员密码,保存文件,按密码删除等操作。

在这里插入图片描述
在这里插入图片描述
可见删除的成员序号为正确结果 6,1,4,7,2,3,5
关闭程序,进行下次运行,演示提升练习。此时文件中已经存放待读取的成员密码信息。
在这里插入图片描述

之后进行随机删除操作,注意进行随机删除操作时初始密码为20

在这里插入图片描述

(4) 实验结果分析

(5) 实验过程中遇到的问题

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值