约瑟夫问题顺序表解决

修改时间2021/9/28        可以自动生成用户定义长度的链表,用户可以自定义起始位置和步                                        长

问题描述:

        设有n个人围坐在一个圆桌周围,现从第s个人开始报数,数到第m的人出列,然后从出列的下一个人重新开始报数,数到第m的人又出列,…,如此反复直到所有的人全部出列为止。Josephus问题是:对于任意给定的n,s和m,求出按出列次序得到的n个人员的序列。

      现以n=8,s=1,m=4为例,问题的求解过程如图2-15所示。图中s1指向开始报数位置,  若初始的顺序为 n1,n2,n3,n4,n5,n6,n7,n8。则问题的解为n4,n8,n5,n2,n1,n3,n7,n6。 

        我们现在用顺序表来解决这个问题。

int josephus_seqList(PSeqList josephus_seq, int s, int m)
{  
    /*求解约瑟夫问题的出列元素序列入口参数:已经存放数据的顺序表,起始位置s,数m。出口参数:1表示成功,0表示表中没有元素*/
    int s1; //用来存储要出队元素的位置,最小位置为0,最大位置为length-1
    int i; //循环变量
    int w; //要出队元素的值

    //如果表为空
    if ( !josephus_seq->length )
    {   
        printf("表中无元素\n"); 
        return 0;     
    }

    //因为数组的下标从0开始,s是位置从1开始,这样就将s1变成从0开始的位置
    s1 = s - 1;  
   
    printf("输出约瑟夫序列:\n");
   
    //表长等于0时,此时已经完成了全部的出队,终止循环
    for(i = josephus_seq->length; i>0; i--)
    {

        // if(josephus_seq->length)
        //找到下一个出列元素的下标
        s1 = (s1 + m - 1) % josephus_seq->length;   

        //输出要出队的值
        w = josephus_seq->data[s1];
        printf("%d\t", w);

        //将出队的元素删除
        Delete_SeqList(josephus_seq,s1+1); 
    } 

    return 1;  
} 

        下面给出上面用到的Delete_SeqList()函数

void Delete_SeqList(PSeqList p, int pos)
{
    int i; //循环变量

    //如果顺序表为空
    if( !p->length )
    {
        printf("顺序表为空,无法删除!\n");
        return;
    }
    
    //如果删除位置有误
    if(pos < 1 || pos > p->length)
    {
        printf("删除位置有错,无法删除!\n");
        return;
    }

    //删除操作
    for (i = pos; i < p->length; i++)
    {
        p->data[i - 1] = p->data[i];
    }
    
    //表长度减一
    p->length--;

    return;
}

        以及整个可以运行的代码

/*
    约瑟夫问题顺序表解决
    V1.0
    V1.5   用户可以自定义起始位置和步长
*/

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

typedef struct josephus
{
    int data[MAXSIZE];
    int length;
}SeqList, * PSeqList;


int josephus_seqList(PSeqList, int, int);
void Delete_SeqList(PSeqList, int);
PSeqList init_SeqList();

int main(void)
{
    int start;
    int step;

    PSeqList p;
    p = init_SeqList();

    printf("请输入起始位置:");
    scanf("%d", &start);

    printf("请输入步长:");
    scanf("%d", &step);

    josephus_seqList(p, start, step);

    return 0;
}

 /*求解约瑟夫问题的出列元素序列入口参数:已经存放数据的顺序表,起始位置s,数m。出口参数:1表示成功,0表示表中没有元素*/
int josephus_seqList(PSeqList josephus_seq, int s, int m)
{  
    int s1; //用来存储要出队元素的位置,最小位置为0,最大位置为length-1
    int i; //循环变量
    int w; //要出队元素的值

    //如果表为空
    if ( !josephus_seq->length )
    {   
        printf("表中无元素\n"); 
        return 0;     
    }

    //因为数组的下标从0开始,s是位置从1开始,这样就将s1变成从0开始的位置
    s1 = s - 1;  
   
    printf("输出约瑟夫序列:\n");
   
    //表长等于0时,此时已经完成了全部的出队,终止循环
    for(i = josephus_seq->length; i>0; i--)
    {

        // if(josephus_seq->length)
        //找到下一个出列元素的下标
        s1 = (s1 + m - 1) % josephus_seq->length;   

        //输出要出队的值
        w = josephus_seq->data[s1];
        printf("%d\t", w);

        //将出队的元素删除
        Delete_SeqList(josephus_seq,s1+1); 
    } 

    return 1;  
}

void Delete_SeqList(PSeqList p, int pos)
{
    int i; //循环变量

    //如果顺序表为空
    if( !p->length )
    {
        printf("顺序表为空,无法删除!\n");
        return;
    }
    
    //如果删除位置有误
    if(pos < 1 || pos > p->length)
    {
        printf("删除位置有错,无法删除!\n");
        return;
    }

    //删除操作
    for (i = pos; i < p->length; i++)
    {
        p->data[i - 1] = p->data[i];
    }
    
    //表长度减一
    p->length--;

    return;
}

//自动生成一个节点的数据域从一开始递增的顺序表
PSeqList init_SeqList()
{
    int len;
    int i;
    int val = 1;
    PSeqList p;
    
    p = (PSeqList)malloc(sizeof(SeqList));
    if(!p)
    {
        printf("分配失败!\n");
        exit(-1);
    }

    p->length = 0;

    printf("请输入你要生成的顺序表长度:(最大长度为100)\n");
     
    while (true)
    {
        scanf("%d", &len);
        if (100 < len)
        {
            printf("%d超出了可创建顺序表的最大长度!\n请重新输入!", len);
        }
        else
        {
            for (i = 0; i < len; i++)
            {
                p->data[i] = val;
                p->length++;
                val++;
            }
            break;
        }
        
    }
    
    
    return p;
}

  • 7
    点赞
  • 26
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值