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

约瑟夫环

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©
    {
    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) 实验过程中遇到的问题

    原文作者:约瑟夫环问题
    原文地址: https://blog.csdn.net/L120305q/article/details/82759710
    本文转自网络文章,转载此文章仅为分享知识,如有侵权,请联系博主进行删除。
点赞