用循环队列解决约瑟夫环问题

问题描述

编号为1、2、…按顺时针坐在一张圆桌周围,每人持有一个密码,一个人选任意正整数为报数上限m,从第一个人开始报数报到m时停止报数,这个人出列,直到所有的人都出列,游戏结束。用线性表的内容来实现这个程序。

解决问题的步骤:

第一步:建立n个节点的无头循环链表。
第二步:从链表的第一个节点开始计数,直到寻找到第m个节点第三步:输出该节点的id值,并将其password值,作为新的m值。
第三步:输出该节点的id值,并将其passward值作为新的m的值。
第四步:根据新的m值,不断从链表中删除节点,直到循环链表为空,程序结束。

程序代码

#include<stdio.h>
#include<stdlib.h>
#define MAX 100

typedef struct NodeType        //自定义结构体类型
{
    int id;
    int password;
    struct NodeType *next;        //用于指向下一个结点的指针
}NodeType;

void CreatList(NodeType **, int);    //创建单向循环链表
NodeType *GetNode(int, int);        //得到一个结点
void PrintList(NodeType *);            //打印循环链表
int IsEmptyList(NodeType *);        //判空
void JosephusOperate(NodeType **, int);        //运行环求解

int main(void)
{
    int n = 0;
    int m = 0;
    NodeType *pHead = NULL;
    do
    {
        if (n>MAX)
        {
            printf("人数太多,请重新输入!\n");
        }
        printf("请输入人数n(最多%d个):", MAX);
        scanf("%d", &n);
    } while (n>MAX);
    printf("请输入初始密码m:");
    scanf("%d", &m);
    CreatList(&pHead, n);        //创建单向循环链表
    printf("\n----------打印循环链表---------\n");
    PrintList(pHead);        //打印链表
    printf("\n----------打印出队情况---------\n");
    JosephusOperate(&pHead, m);        //运行
    return 1;
}

void CreatList(NodeType **ppHead, int n)        //创建有n个结点的循环链表pphead 
{
    int i = 0;
    int iPassword = 0;
    NodeType *pNew = NULL;
    NodeType *pCur = NULL;
    for (i = 1; i <= n; i++)
    {
        printf("输入第%d个人的密码:",i);
        scanf("%d", &iPassword);
        pNew = GetNode(i, iPassword);
        if (*ppHead == NULL)
        {
            *ppHead = pCur = pNew;
            pCur->next = *ppHead;
        }
        else
        {
            pNew->next = pCur->next;
            pCur->next = pNew;
            pCur = pNew;
        }
    }
    printf("完成单向循环链表的创建!\n");
}

NodeType *GetNode(int iId, int iPassword)
{
    NodeType *pNew = NULL;
    pNew = (NodeType *)malloc(sizeof(NodeType));
    if (!pNew)
    {
        printf("Error, the memory is not enough!\n");
        exit(-1);
    }
    pNew->id = iId;
    pNew->password = iPassword;
    pNew->next = NULL;
    return pNew;
}

void PrintList(NodeType *pHead)
{
    NodeType *pCur = pHead;
    if (!IsEmptyList(pHead))
    {
        printf("--ID-- --PASSWORD--\n");
        do
        {
            printf("%3d %7d\n", pCur->id, pCur->password);
            pCur = pCur->next;
        } while (pCur!=pHead);
    }
}

int IsEmptyList(NodeType *pHead)
{
    if (!pHead)
    {
        printf("The list is empty!\n");
        return 1;
    }
    return 0;
}

void JosephusOperate(NodeType **ppHead, int iPassword)
{
    int iCounter = 0;
    int iFlag = 1;
    NodeType *pCur = NULL;
    NodeType *pPrv = NULL;
    NodeType *pDel = NULL;
    pPrv = pCur = *ppHead;
    while (pPrv->next != *ppHead)
    {
        pPrv = pPrv->next;
    }
    while (iFlag)
    {
        for (iCounter = 1; iCounter < iPassword; iCounter++)
        {
            pPrv = pCur;
            pCur = pCur->next;
        }
        if (pPrv==pCur)
        {
            iFlag = 0;
        }
        pDel = pCur;
        pPrv->next = pCur->next;
        pCur = pCur->next;
        iPassword = pDel->password;
        printf("第%d个人出列(密码:%d)\n", pDel->id, pDel->password);
        free(pDel);
    }
    *ppHead = NULL;
    getchar();
}
  • 1
    点赞
  • 23
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
使用循环队列可以解决约瑟夫环问题。在这个问题中,循环队列的每个位置都代表一个人,初始时队列中有n个人。从第p个人开始报数,报到m的人将被淘汰。然后从下一个人开始重新报数,直到只剩下一个人为止。循环队列的实现思想与使用数组类似,但需要注意处理队列中人数不断减少的情况。使用循环队列解决约瑟夫环问题的代码如下: ```cpp #include<iostream> #include<queue> using namespace std; void Josephus(int n, int p, int m) { queue<int> arr; // 初始化编号 for (int i = 0; i < n; i++) { arr.push((p - 1 + i) % n + 1); } int count = 1; // 记录队头的报号 int data; while (!arr.empty()) { data = arr.front(); // 取出队头的数据 arr.pop(); if (count == m) { cout << data << " "; // 如果报到m,则输出该人的编号 count = 1; continue; } arr.push(data); // 报号不是m的人重新入队列 count++; } return; } int main() { int n, p, m; cout << "Input n, p and m: "; while (cin >> n >> p >> m) { if (n == 0 && p == 0 && m == 0) { cout << "Over!" << endl; break; } cout << "Data in turn: "; Josephus(n, p, m); cout << endl; cout << "Input n, p and m: "; } return 0; } ``` 这段代码使用循环队列实现了解决约瑟夫环问题的功能。通过输入n、p和m来确定问题的规模和初始条件。程序会依次输出每次报数淘汰的人的编号,直到最后只剩下一个人。<span class="em">1</span><span class="em">2</span><span class="em">3</span> #### 引用[.reference_title] - *1* *2* *3* [【数据结构】基于数组和循环队列解决约瑟夫问题](https://blog.csdn.net/db895166315/article/details/107847538)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v93^chatsearchT3_1"}}] [.reference_item style="max-width: 100%"] [ .reference_list ]

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值