链表学习-----------------------------------约瑟夫环的链表实现和数组实现【详细的解析】

约瑟夫环问题

已知 n 个人(n>=1)围坐一圆桌周围,从 1 开始顺序编号,从序号为 1 的人开始报数,顺时针数到 m 的那个人出列。下一个人又从 1 开始报数,数到m 的那个人又出列。依此规则重复下去,直到所有人全部出列。请问最后一个出列的人的初始编号。

【要求

输入人数 n,所报数 m,输出最后一个人的初始编号。

约瑟夫环问题解决思路

首先因为是圆桌问题,使用链表解决的话需要构建循环链表

接着是出列问题,这里我的设计思路是将指向链表的指针移动到需要出列的人的位置,然后根据正常的链表删除进行操作即可。

我最近喜欢上了链表,所以就想水几发试试,试着写上自己的题解,希望许多像我一样努力的人能少走弯路。

给出两种解决的代码,一种链表,一种数组。

详细代码如下:

(1)链表:

#include<iostream>
#include<algorithm>
#include<string.h>
using namespace std;
typedef struct LNode{
    int data; //数据域
    struct LNode *next; //指针域
}LNode,*LinkList; //*LinkList为LNode类型
int n,m;
LinkList head,p,r;
int main()
{
    //ios::sync_with_stdio(false); //可要可不要,主要是关闭缓冲区域
    cin>>n>>m;
    head = new LNode; //创建一个头结点
    head->data = 1; //头结点的数据域置为1
    head->next = NULL; //头结点的指针域为空
    r = head; //让指针r指向head指向的结点,头结点head不移动
    for(int i=2;i<=n;i++) //这个for循环是为了利用尾插法建好链表
    {
        p = new LNode; //生成一个新的结点
        p->data = i; //数据域为i
        p->next = NULL; //指针域为空
        r->next = p; //这两句是为了移动尾指针使之始终指向新生成的指针
        r = p;
    }
    r -> next = head; //首尾相连,循环链表建好
    r = head; //因为head是头指针,没有移动,我们在输出的时候让r重新从头(指向头结点)开始
    for(int i=1;i<=n;i++) //输出操作
    {
        for(int j=1;j<=m-2;j++) //要找第m个位置,先找第m-2个位置
            r = r -> next; //这一步一旦成功,这时r指针就指向了第m-1个位置
        cout<<r->next->data<<' '; //因为r指针指向第m-1个位置,所以r->next就连接了第m个结点,这是输出第m个结点的数据域
        r->next = r->next->next; //删除第m个结点
        r = r->next; //r指向删除的结点所连接的后续结点,因为每出队一个,就要从下一个位置重新开始
    }
}

运行结果:

(2) 数组实现:

 

#include<iostream>
#include<algorithm>
#include<string.h>
using namespace std;
const int maxn = 1e5+10;
int a[maxn],b[maxn];
void solve(int n,int m)
{
    int j=0,countee=0;
    for(int i=0;i<n;i++) //习惯数组下标从0开始
        a[i] = i+1;
    for(int i=0;j!=n;i++)
    {
        if(a[i] == -1) //将首尾相连,类似一个循环数组
            i = 0;
        if(a[i]!=0 && a[i]!=-1) //中间的情况,继续进行数的自加
            countee++;
        if(countee==m) //将第m位的数存起来
        {
            b[j++] = a[i];
            a[i] = 0;
            countee = 0;
        }
    }
    for(int i=0;i<n;i++) //依次输出
        cout<<b[i]<<' ';
    cout<<endl;
}
int main()
{
    int n,m;
    while(cin>>n>>m)
    {
        memset(a,0,sizeof a);
        memset(b,0,sizeof b);
        a[n] = -1; //这一步赋一下值
        solve(n,m);
    }
    return 0;
}

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值