c++c语言使用单链表循环解决出圈(约瑟夫问题)超详细

前言:

不知道单链表的可以先看看我之前的文章    我还是个初学者 所以不懂的地方还很多 望谅解。c ++c语言单链表头插法尾插法以及删除结点的操作(简化版) 学习笔记

一.问题

设有n个人围坐一圈并按顺时针方向从1到n编号,从第1个人开始进行1到m的报数,报数到第个m人,此人出圈,再从他的下一个人重新开始1到m的报数,如此进行下去直到所剩下一人为止。

输入

输入多行,每行2个数,分别表示n和m.

输出

计算每一行中最后剩下这个人的编号.

样例输入

10 3

样例输出

4

二.解题思路

因为题目涉及循环以及删除元素操作 可以运用单链表循环 可快速查找删除结点. 因为最终只剩一人时结束,所以当单链表循环里 单链表里只剩一个结点循环(即 结点指向本身)时,宣告结束。

三.解决问题步骤

1.创建一个单链表

#include<iostream>
using namespace std;
//创建单链表
typedef struct Node
{
    int data;
    struct Node* next;
}Node;

2.定义n,m,输入n,m

3.将数据传入链表之中

首先 仍是以单链表的形式 运用for循环 进行尾插数据操作  使最后一个元素指向第一个元素 完成链表循环 

int n, m;
    cin >> n>>m;
    
    
        Node * head = new Node; //定义首结点head  并分配空间 将head data域 指向1
        head->data = 1;           
        Node* p = new Node;    //定义 p结点 = head结点 作为head结点的分身
        p = head;
        for (int i = 2; i <= n; i++) //将从2到n 分别被指向每一个结点的data域
        {
                Node* node = new Node;  //定义新结点node 并为其分配空间 
                node->data = i;         //node data域 指向 i
                p->next = node;         //首结点 p 指向 node 
                p = node;      //最后再将 node地址 给p  作为node的分身 下一轮p为node的值
                head->data++;  //更新链表的长度(不写问题也不大)
        }
        //循环结束 将单链表成为单链表循环  
        p->next = head;  //最后一个元素连接第一个元素

4.定义 i = 1; Node * q = new Node;

定义一个i值,每次i +1= m时,进行结点删除,然后直到仅剩一个结点,即为所求值。

 int i = 1;
 Node* q = head; //q在下层循环使用 先声明定义

5.while死循环为大框架

whlie(true)
{

}

6.在while大框架里进行操作

 继续内层while循环 来进行不断删减 循环条件 为 head->next != head head的值是不断更新的 意为当最后一个结点指向本身时 打破该while循环  先看一遍代码 

首先 默认从2开始,因为最少2人才能进行这个游戏,即若m = 2 时,通过if语句判断条件,1 指向 3 删除2 再将 3 的地址赋予 1 ;继续进行操作 此时依然满足判断条件 1 指向 5 删除 4  将 5 的地址 赋予 1 以此类推...

 若 m != 2,则 if语句最后 i=1; 的用途就出来了,听我分析: 若是 m = 4 ,则刚开始 i = 1,进行if判断 无法通过,进行else语句  head进行地址++,即从 1 变成了 2,i++ => i =2; 继续进行循环 if判断 无法通过 进行else语句 head进行地址++ ,即从 2 变成了 3,i++ => i = 3;  继续进行循环 if判断成功, 进行删除操作 ,将 3 指向 5 删除4 ,再将 5 的地址赋予 3  i 又 变回了 1 ,此时 3继续进行else语句 地址++  5 变成=> 6 再一次进行else语句 地址++ 6 变成=> 7,此时进行了两次i++ i=3又满足了 i + 1 = m 继续进行删除 以此类推...若没有if语句中的i = 1;第一次正常删除 但在进行第二次删除时 仅仅只是相邻数的删除操作  5 指向 7 删除 6 

 while (head->next != head)//当第一个元素独自循环
            {
                if (i + 1 == m) // 满足此条件 进行结点删除操作
              {
              q = head->next;             删除head 指向下一个结点        
              head->next = q->next;              
              delete(q);             
              head = head->next;    并将 head 下一个的下一个结点 赋予给 head
              i = 1;               
              }
                else
                {
                    head = head->next;  //head = 下一个结点的地址
                    i++;
                }
            }

7.若只剩最后一个人 结束while死循环

当内层while循环不再执行时,head此时的data域的值 为 最终值                                                       此时再break 外层while死循环 即 满足head-> next = head break

while(true)
{
 while (head->next != head)//当第一个元素独自循环
            {
                if (i + 1 == m) // 满足此条件 进行结点删除操作
              {
              q = head->next;             删除head 指向下一个结点        
              head->next = q->next;              
              delete(q);             
              head = head->next;    并将 head 下一个的下一个结点 赋予给 head
              i = 1;               
              }
                else
                {
                    head = head->next;  //head = 下一个结点的地址
                    i++;
                }
            }
 if (head->next = head)
            {
                break;
            }
}

8.在外层while循环外输出最终值head->data

  cout << head->data << endl;

四.完整代码

#include<iostream>
using namespace std;
//创建单链表
typedef struct Node
{
    int data;
    struct Node* next;
}Node;

int main()
{
    int n, m;
    cin >> n>>m;
    
    
        Node * head = new Node;
        head->data = 1;
        Node* p = new Node;
        p = head;
        for (int i = 2; i <= n; i++)
        {
                Node* node = new Node;
                node->data = i;
                p->next = node;
                p = node;
                head->data++;
        }
        p->next = head; //最后一个元素连接第一个元素
        //定义一个i值,每次 i + 1 = m时,此结点删除,然后直到仅剩一个结点,即为所求值。
        int i = 1;
        Node* q = new Node;
        while (true)
        {
            while (head->next != head)//当第一个元素独自循环
            {
                if (i + 1 == m)
                {
                    q = head->next;          // 不加 i = 1               加 i = 1    
                    head->next = q->next;   //  m = 3 i = 1               m = 3 i = 1           
                    delete(q);             //   head = 2 i = 2            head = 2 i = 1 
                    head = head->next;    //    head = 4 i = 2            head = 5 i = 2
                    i = 1;               //     head = 6 i = 2            head = 7 i = 1 
                }
                else
                {
                    head = head->next;
                    i++;
                }
            }
            if (head->next = head)
            {
                break;
            }
        }
        cout << head->data << endl;
    return 0;
}

五.代码运行结果

六.c语言格式

注意:(我使用的是vs2022 scanf的写法为scanf_s)

完整代码:

#include<stdio.h>
#include<stdlib.h>
//创建单链表
typedef struct Node
{
    int data;
    struct Node* next;
}Node;

int main()
{
    int n, m;
    scanf_s("%d%d", &n, &m);


    Node* head = (Node*)malloc(sizeof(Node));
    head->data = 1;
    Node* p = new Node;
    p = head;
    for (int i = 2; i <= n; i++)
    {
        Node* node = new Node;
        node->data = i;
        p->next = node;
        p = node;
        head->data++;
    }
    p->next = head; //最后一个元素连接第一个元素
    //定义一个i值,每次 i + 1 = m时,此结点删除,然后直到仅剩一个结点,即为所求值。
    int i = 1;
    Node* q = (Node*)malloc(sizeof(Node));
    while (true)
    {
        while (head->next != head)//当第一个元素独自循环
        {
            if (i + 1 == m)
            {
                q = head->next;          // 不加 i = 1               加 i = 1    
                head->next = q->next;   //  m = 3 i = 1               m = 3 i = 1           
                free (q);            //   head = 2 i = 2            head = 2 i = 1 
                head = head->next;    //    head = 4 i = 2            head = 5 i = 2
                i = 1;               //     head = 6 i = 2            head = 7 i = 1 
            }
            else
            {
                head = head->next;
                i++;
            }
        }
        if (head->next = head)
        {
            break;
        }
    }
    printf("%d", head->data);
    return 0;
}

  • 3
    点赞
  • 15
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 1
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

小苏先生.

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

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

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

打赏作者

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

抵扣说明:

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

余额充值