实验2 线性表及其应用——约瑟夫环

该实验旨在通过线性表的数据结构,使用C++实现约瑟夫环问题。实验要求利用单向循环链表模拟过程,按照出列顺序输出编号。测试数据为m初始值为20,7个人的密码,最终输出正确的出列顺序。程序设计需要用户输入初始报数上限,并读取各人密码,最大人数限制为30,且链表不使用头结点。
摘要由CSDN通过智能技术生成

【实验目的】

帮助学生熟练掌握线性表的基本操作在顺序和链式两种存储结构上的实现,其中以各种链表的操作和应用作为重点内容。

【实验内容及要求】

  1. 问题描述:约瑟夫问题的一种描述是:编号为1,2,…,n的n个人按顺时针方向围坐一圈,每人持有一个密码(正整数)。一开始任选一个正整数作为报数上限值m,从第一个人开始按顺时针方向自1开始顺序报数,报到m时停止报数。报m的人出列,将他的密码作为新的m的值,从他在顺时针方向上的下一个人开始重新从1报数,如此下去,直至所有人全部出列为止。试设计一个程序求出出列顺序。
  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≤30。此题所用的循环链表中不需要“头结点”,请注意空表和非空表的界限。

【实验代码】

#include <iostream>
using namespace std;

struct circularList
{
    int number;
    int passward;
    circularList *next;
};

circularList * createList(int n); // 创建循环链表
int getLength(circularList *); // 获取链表长度
int getIndex(circularList *, circularList *); // 获取指定元素索引
circularList * deleteList(circularList *, int); // 删除结点

int main() {
    int m, n; // m为报数初始上限值,n为总人数
    cout << "请输入报数初始上限值:" << endl;
    cin >> m;
    cout << "请输入参与报数的总人数" << endl;
    cin >> n;

    if(n < 1 || m < 1)
    {
        cout << "人数或初始报数值非法!" << endl;
        return 0;
    }

    circularList * josephRing;
    josephRing = createList(n);
    circularList * head = josephRing;

    while(true)
    {
        if(getLength(josephRing) == 1)
        {
            deleteList(head,1);
            cout << "报数完毕!" << endl;
            break;
        }

        for(int i = 0; i < m - 1; i++)
        {
            josephRing = josephRing->next;
        }

        m = josephRing->passward;

        if(getIndex(head,josephRing) == 1)
        {
            josephRing = head = deleteList(head,getIndex(head,josephRing));
        } else
        {
            josephRing = deleteList(head,getIndex(head,josephRing));
        }
    }

    return 0;
}

circularList * createList(int n) // 创建循环链表
{
    circularList * head, * q, * p; // q为了新建结点,p为了在各个结点中运行,head是链表头部结点
    head = q = NULL;

    cout << "请依次输入每个人的密码: " << endl;
    for(int i = 0; i < n; i++)
    {
        q = new circularList;
        q->number = i + 1;
        cin >> q->passward;

        if(head == NULL)
        {
            head = q;
        }
        else
        {
            p->next = q;
        }
        p = q;
    }
    p->next = head;
    cout << "循环链表创建成功! " << endl;

    return head;
}

int getLength(circularList * head)
{
    circularList * p = head;
    int n = 0;

    if(p->next == head)
    {
        return 1;
    }

    while(true)
    {
        n++;
        p = p->next;
        if(p->next == head)
        {
            n++;
            break;
        }
    }
    return n;
}

int getIndex(circularList * head, circularList * jos)
{
    int n = 0;
    circularList * p = head;

    if(p->next == head)
    {
        return 1;
    }

    while(true)
    {
        if(p == jos)
        {
            n++;
            break;
        }
        n++;
        p = p->next;
    }
    return n;
}

circularList * deleteList(circularList * head, int n) // 删除结点
{
    circularList * p = head, * q; // p为了在各个结点中运行,q为了储存要删除的结点,head是链表头部结点
    if(n < 0 || n > getLength(head))
    {
        cout << "索引超出范围,删除失败!" << endl;
        return head;
    }

    if(n == 1)
    {
        for(int i = 0; i < getLength(head) - 1; i++)
        {
            p = p->next;
        }
        q = p->next;
        p->next = q->next;
        head = p->next;
    }
    else
    {
        while(n-- > 2)
        {
            p = p->next;
        }
        q = p->next;
        p->next = q->next;
    }

    cout << q->number << " " << "出列!" << endl;
    delete q;

    return p->next;
}
  • 0
    点赞
  • 14
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

Jegret

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

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

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

打赏作者

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

抵扣说明:

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

余额充值