问题 C: Josephus问题(Ⅰ)

问题 C: Josephus问题(Ⅰ)

题目描述
n个人排成一圈,按顺时针方向依次编号1,2,3…n。从编号为1的人开始顺时针"一二"报数,报到2的人退出圈子。这样不断循环下去,圈子里的人将不断减少。最终一定会剩下一个人。试问最后剩下的人的编号。

要求程序模拟题意来实现,使用不带头结点的循环链表。本题只需要提交两个函数CreateList和 Execute的实现, 请注意提交语言使用C++。


/*********************************/
/*CreateList创建一个从1到n的不带头结点的循环链表,返回指向结点1的头指针*/
LinkList CreateList(int n);
/*Execute从链表中删除一个人。
*@h 不带头结点的单循环链表 
*@k,h指向的结点为第1个结点,删除第k个结点(含循环绕回的情况),k保证大于1.
*Execute返回第k+1个结点的指针
*/
LinkList Execute(LinkList h, int k);
/*********************************/


为方便同学们测试,下面提供除两个函数外的其他代码。
#include<iostream>
using namespace std;

typedef struct LNode
{
    int data;
    struct LNode *next;
} LNode, *LinkList;

int main()
{
    int n;
    while(cin >> n)
    {
        LinkList h;
        h = CreateList(n);
        while(--n)
            h = Execute(h, 2);
        cout << h->data << endl;
        delete h;
    }
    return 0;
}

输入
不超过1000组数据。
每组数据一行,每行一个正整数,代表人数n。 (1 <= n <= 1000)

输出
每组输入数据输出一行, 仅包含一个整数,代表最后剩下的人的编号。

样例输入 Copy
7
2
样例输出 Copy
7
1
提示
第一组数据出队顺序: 2 4 6 1 5 3

解题步骤

模拟题意
每次报数为2的人出局,即出局的人的后一位为重新开头
示例输入7的运算逻辑如下
在这里插入图片描述
下面是对代码的详细解析:

  1. 头文件和命名空间

    • 包含 <iostream> 头文件,用于输入输出操作。
    • 使用 using namespace std; 来避免在标准库类型和函数前加 std::
  2. 链表节点结构体定义

    • 定义了一个结构体 LNode,包含一个 int data 成员变量和一个指向同类型结构体的指针 next。这个结构体用于表示链表中的节点。
  3. 类型别名定义

    • 使用 typedef 创建了 LNode, *LinkList 的别名,方便后续代码中使用。
  4. 创建链表函数 CreateList

    • 接受一个整数参数 n,表示链表中节点的数量。
    • 动态分配一个新节点作为链表的起始节点,并初始化其数据为 1。
    • 使用循环动态分配更多的节点,并按顺序设置它们的数据,从 2 到 n。
    • 将链表的最后一个节点的 next 指针指向链表的起始节点,形成循环。
    • 返回指向链表起始节点的指针。
  5. 执行删除操作函数 Execute

    • 接受一个链表头指针 h 和一个整数 k,表示要删除的节点的序号(从 1 开始)。
    • 通过循环找到第 k-1 个节点,即要删除节点的前一个节点。
    • 将前一个节点的 next 指针指向要删除节点的下一个节点,从而删除了第 k 个节点。
    • 更新链表头指针 h 为删除操作后的下一个节点。
    • 释放要删除节点的内存。
    • 返回更新后的链表头指针。
  6. 主函数 main

    • 从标准输入读取整数 n,直到输入结束。
    • 使用 CreateList 函数创建一个长度为 n 的循环链表。
    • 使用循环调用 Execute 函数删除第 2 个节点,直到只剩下一个节点。
    • 输出剩余节点的数据。
    • 释放链表头节点的内存。
  7. 程序结束

    • 返回 0,表示程序正常结束。

代码逻辑分析

  • 这段代码模拟了一个约瑟夫环问题(Josephus problem),其中 n 表示初始人数,每次删除第 2 个节点,直到只剩下一个节点。
  • CreateList 函数创建了一个循环链表,Execute 函数实现了删除指定节点的操作。
  • 主函数中的循环模拟了约瑟夫环问题的迭代过程。

改进建议

  • 移除 Execute 函数中的 h=x->next; 这行代码,因为它是多余的。
  • main 函数中,可以在删除操作后更新 h 的值,例如使用 h = Execute(h, 2);
  • 考虑增加对输入有效性的检查,确保 n 是一个合理的正整数。

代码实现

这里因为小编的链表部分学的不是很好,所以找朋友指导了一下

代码如下(创建循环链表):

/*创建一个从1到n的不带头结点的循环链表,返回指向结点1的头指针*/
LinkList CreateList(int n){
    LinkList ans=new LNode;
    LinkList sum=ans;
    sum->data=1;
    for(int i=2;i<n+1;i++){
        sum->next=new LNode;
        sum=sum->next;
        sum->data=i;
    }
    sum->next=ans;
    return ans;
}//创建题目运算过程中所需要的循环链表,用以存储答案所存在的数字区间

代码如下(存储数据):

/*Execute从链表中删除一个人。
h为不带头结点的单循环链表,h指向的结点为第1个结点,
删除第k个结点(含循环绕回的情况),k保证大于1,Execute返回第k+1个结点的指针*/
LinkList Execute(LinkList h, int k){
    LinkList sum=h;
    for(int j=1;j<k-1;j++){sum=sum->next; }//不用分配新内存,直接使用原定义所用链表内存
    LinkList x=sum->next;
    sum->next=x->next;
    h=x->next;
    delete x;
    return h;
}
//在所存储的循环链表中查找答案所在正确位置并将其位置固定为h节点

完整代码

#include<iostream>
using namespace std;

typedef struct LNode
{
    int data;  //编号 
    struct LNode *next;
}LNode, *LinkList;

/*创建一个从1到n的不带头结点的循环链表,返回指向结点1的头指针*/
LinkList CreateList(int n){
    LinkList ans=new LNode;
    LinkList sum=ans;
    sum->data=1;
    for(int i=2;i<n+1;i++){
        sum->next=new LNode;
        sum=sum->next;
        sum->data=i;
    }
    sum->next=ans;
    return ans;
}

/*Execute从链表中删除一个人。
h为不带头结点的单循环链表,h指向的结点为第1个结点,
删除第k个结点(含循环绕回的情况),k保证大于1,Execute返回第k+1个结点的指针*/
LinkList Execute(LinkList h, int k){
    LinkList sum=h;
    for(int j=1;j<k-1;j++){sum=sum->next; }
    //不用分配新内存,直接使用原定义所用链表内存
    LinkList x=sum->next;
    sum->next=x->next;
    h=x->next;
    delete x;
    return h;
}

int main()
{
    int n;
    while(cin >> n)
    {
        LinkList h;
        h = CreateList(n);
        while(--n)
            h = Execute(h,2);
        cout << h->data << endl;
        delete h;
    }
    return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值