数据结构与算法(C语言版)——计算约瑟夫环问题

1、需求分析

1.1、问题阐述

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

1.2、基本需求

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

2、概要设计

利用循环链表来代表约瑟夫环,每次出列的人从链表中删去,一直循环到最终剩下一人。

3、测试数据

m的初值为20;n=7,7个人的密码依次为:3,1.7,2,4,8,4,首先m的值是6 (正确的出列顺序为6,1,4,7,2,3,5)

4、详细设计

首先创建一个空的循环链表,然后根据输入的总人数n和循环数m来为循环链表动态分配空间,并利用该循环链表来代表我们的约瑟夫环,对于每次计数循环出列的人,只需将其代表的结点从循环链表中删去然后将出列的人的密码作为新的m值,随后一直循环到最终剩下一个结点即剩下最后一个人。

5、用户手册

只需要在开头输入总人数n和每次出列所需人数m即可计算出最终优胜者。

6、测试结果

测试结果完全正确:

7、源代码:

//
// Created by stu_kk on 2022/4/25.
//
#include<stdio.h>
#include<iostream>
#include<stdlib.h>
using namespace std;
typedef struct List{//链表
    int key;
    int password;
    struct List *next;
}list;
int n,m;
list *ans = NULL;
int pass[1001];
void add(){
    list *head,*body,*tail;
    head = (list*)malloc(sizeof(list));
    head->key = 1;
    head->password = pass[0];//赋值密码
    tail = head;
    for(int i = 2;i<=n;i++){
        body = (list*)malloc(sizeof(list));
        body->key = i;
        body->password = pass[i-1];
        tail->next = body;
        body->next = NULL;
        tail = body;
    }
    tail->next = head;//头尾链接,循环链表
    ans = head;
}
void solve(){
    int size = n;
    list *p = ans;
    list *parent = ans;//设置它为p的上一个指针.
    while(parent->next!=ans){
        parent = parent->next;
    }
    printf("依次离开的人:\n") ;
    while(p->next!=p){
        for(int i = 1;i<m;i++){//数到m的人离开
            parent = p;
            p = p->next;
        }
        printf("%d ",p->key);
        m = p->password;
        parent->next = p->next;
        free(p);
        p = parent->next;
    }
    printf("%d",p->key);
}
int main(){
    printf("请输入人数n和数值m :");
    scanf("%d%d",&n,&m);//n个人、每数到m出列 。
    printf("请输入%d个人的密码 :",n);
    for(int i = 0;i<n;i++){
    	scanf("%d",&pass[i]);
	}
    add();//先将n个人都加入链表
    solve();
    return 0;
}


  • 5
    点赞
  • 72
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 3
    评论
好的,我可以为您提供一种实现方法。 约瑟夫环问题是一个经典的问题,可以用链表来实现。具体实现可以参考以下代码: ```c #include <stdio.h> #include <stdlib.h> // 定义链表结点 typedef struct node { int data; struct node *next; } Node; // 创建链表 Node* CreateList(int n) { Node *head, *p, *tail; head = (Node*)malloc(sizeof(Node)); // 头结点 tail = head; for (int i = 1; i <= n; i++) { p = (Node*)malloc(sizeof(Node)); p->data = i; tail->next = p; tail = p; } tail->next = head->next; // 将链表首尾相连形成环 free(head); // 头结点释放 return tail->next; // 返回环的起始结点 } // 约瑟夫环问题处理函数 void Josephus(int n, int m) { Node *head, *p, *q; head = CreateList(n); // 创建有 n 个结点的环 p = head; // p 指向当前结点的前一个结点 while (n > 1) { for (int i = 1; i < m; i++) { p = p->next; } q = p->next; // q 指向当前结点 p->next = q->next; // 将当前结点删除 printf("%d ", q->data); // 输出删除的结点的编号 free(q); // 释放删除的结点 n--; } printf("%d\n", head->data); // 输出最后剩余的结点的编号 free(head); // 释放链表 } int main() { int n, m; printf("请输入链表结点数 n 和报数 m:"); scanf("%d%d", &n, &m); Josephus(n, m); return 0; } ``` 这个程序的输入为链表结点数 n 和报数 m,输出为依次删除结点之后最后剩余的结点的编号。您可以根据自己的需求修改输入输出方式,或者将该函数封装为一个库函数供其他程序调用。

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

stu_kk

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

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

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

打赏作者

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

抵扣说明:

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

余额充值