约瑟夫环实现实验报告(完成代码+实验截图)

一.实验目的:

理解线性表的基本逻辑结构,完成链表及循环链表的实现

通过实验进一步理解线性表的逻辑结构和存储结构,提高使用理论知识指导解决实际问题的能力,熟练掌握链表的实际应用。

二.实验内容:

题目:Josephus环问题

问题描述:

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

基本要求:

利用单向循环链表存储结构模拟此过程,按照出列的顺序印出各人的编号。

三. 实验方案

(一)算法设计思路:

由题知使用带头结点单循环链表,

建立链表:

第一步:建立头节点、然后建立单循环链表。(建立一个输出函数检验是否建立成功)。

       第二步:建立主函数,通过键盘输入人数、报道数,调用单循环链表和建立存放出队顺序的数组。

第三步:建立子函数,通过主函数传来链表的头指针,总人数,报数值和数组(用来存每个人出列顺数),调用子函数的功能

  子函数功能实现:使用两个指针 p(头指针) q(p前一个结点的指针)二者相互交替完成链表结点的删除和空间的释放。在while的语句内循环至只剩一个人,再将其存入最后一位数组中。

第四步:输出数组a的值即是出队顺序。

(二)使用模块及变量的说明(例如结构体的定义、含义)

typedef struct Lnode:(组成链表的结点)

data来标记每个人,

next是指向下一个结点的指针(来存结点的地址)

LNode 是结点的别名,*LinkList是指向结点指针。

LinkList Creat_list(int n)函数:(创建单循环链表)

    L是头指针指向头节点,r是尾指针指向最后一个结点

    s存放申请的结点空间的地址。

    n是传来的总人数,k是来控制循环结束

   

int output(LinkList L):(检查链表是否创建成功)

int main():(调用各个函数)

    n是总人数,m是报道人数

L是头指针(指向头结点)

A[100]是存放出队顺序的数组

void Func(LinkList tail, int n, int m, int* a):(获得出队顺序的函数)

    count是每个人的报数值,flag是死亡人数值

p是头指针(指向头节点的下一个结点),q是指向头节点的指针

i是数组a的下标。

四. 实验步骤或程序(经调试后正确的源程序)

  1. #include<iostream>
    
    #include<string>
    
    using namespace std;
    
    
    
    typedef struct Lnode
    
    {
    
        int data;
    
        struct Lnode* next;
    
    
    
    }LNode,*LinkList;
    
    
    
    LinkList Creat_List(int n)
    
    {
    
        LinkList L = NULL;
    
        LNode* s, * r = NULL;
    
        int x;
    
        cin >> x;
    
        s = (LNode*)malloc(sizeof(LNode));
    
        if (s == NULL) {
    
             cout << "调用失败";
    
        }
    
        else
    
             L = s;
    
        r = s;
    
        int k = 1;
    
        while (1)
    
        {
    
             k++;
    
             s = (LNode*)malloc(sizeof(LNode));
    
             if (s == NULL) {
    
                 cout << "调用失败";
    
             }
    
             else
    
                 s->data = x;
    
    
    
             r->next = s;
    
    
    
             r = s;
    
             if (k > n)
    
                 break;
    
             cin >> x;
    
    
    
        }
    
        r->next = L->next;
    
        return L;
    
    
    
    }
    
    int output(LinkList L)//有头节点输出
    
    {
    
        while (L->next)
    
        {
    
             L = L->next;
    
             cout << L->data << " ";
    
    
    
        }
    
        return 0;
    
    
    
    }
    
    
    
    
    
    int main()
    
    {
    
        void Func(LinkList tail, int n, int m, int* a);
    
       
    
        int n,m;
    
        cout << "总人数:";
    
        cin >> n;
    
        LinkList L,H;
    
        cout << "编号依次为:"<<endl;
    
        L=Creat_List(n);
    
    
    
        cout << "输入报道的数";
    
        cin >> m;
    
        int a[100];
    
       
    
        Func(L, n, m, a);
    
        cout << "出列顺序依次是:";
    
        for (int i = 0; i < n; i++)
    
        {
    
             cout << a[i]<<" ";
    
        }
    
     system("pause");
    
        return 0;
    
    }
    
    
    
    void Func(LinkList tail, int n, int m, int* a)
    
    {
    
        int i = 0;
    
        int count = 0, flag = 0;//设置报数值和死亡人数值
    
        LinkList  p= tail->next, q = tail;//定义p为头指针,q为p前一个结点的指针
    
        while (flag < n - 1) {//死亡人数没有达到n-1
    
             count++;//报数
    
             if (count == m) {//满足出圈条件
    
                
    
                 a[i] = p->data;//记录当前出圈者的编号
    
                 i++;//让数组移向下一个值
    
                 q->next = p->next;//让p的上一个结点的指针指向p的下一个结点
    
                 free(p);//释放当前结点
    
                 p = q->next;//p移动到下一个人
    
                 count = 0;//重新开始报数
    
                 flag++;//死亡人数加一
    
             }
    
             else {//不满足就移向下一个人
    
                 q = p;
    
                 p = p->next;
    
             }
    
        }
    
        a[i]= p->data;//记录最后一个人的编号
    
        free(p);
    
    }

五.程序运行结果(程序运行结果的一些截图)

六.实验总结(调试过程中遇到哪些问题,怎么解决的)

第一个问题:链表建立不成

    刚开始建立链表循环书中是while用标志来停止循环的,但是题中要求了总人数,所以可以用count来计数。用break停止循环

第二个问题:链表每次都多输入一个数,但输出链表时又没了。

我检查了一下发现是break停的位置不对,应放在cin的上面终止,否则会多输入一次却没存储,没任何意义。

第三个问题:链表的类型选取

    我刚开始选取的是无头节点的表尾插入,但是之后发现如果是这样只能选取一个指针,对于删除结点的困难很大,之后选取了带头节点的双指针来删除结点,很方便。

第四个问题:每次出队删除结点,如何记录下他的的顺序

       刚开始我想要再建立一个链表来实现发现有点难度,容易搞混,后来想到可以存在数组里面,这样很简单就能保存出队顺序。

                                              

  • 5
    点赞
  • 55
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 3
    评论
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

五敷有你

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值