题目:

代码:

Josephus.h

typedef int Status; // 一个新类型Status 表明操作成功与否的状态,如果函数成功返回整形值1,否则返回整型值0
struct Lnode { // 单链表结点类型
    int data; // 信息存储
    Lnode *next; // 下一结点地址
};
typedef Lnode Linklist ;

///函数声明
Status CreatJosephus_L ( Linklist &L , int n ) ; // 依次输入整数1-n的n个元素的值到链表的结点的数据单元,建立约瑟夫环用指针L指向第一个结点
Status OutputJosephus_L ( Linklist &L , int n ) ; // 从结点 L 开始,输出n个元素
void MenuSelect ( Linklist &L ) ; // 处理链表L
using namespace std ;

Josephus_app

#include<stdio.h>
#include<iostream>
#include"Josephus.h"
using namespace std ;
Status CreatJosephus_L ( Linklist &head , int n ) {
    Lnode *L = &head ; // 记录头结点地址
    if ( n<=0 ) { // 序列长度 n 不合法
        return 0 ;
    }
    int temp;
    scanf( "%d", &temp ) ;
    L->data = temp ; // 为第一个节点赋值
    n = n - 1 ;
    while( n-- ) { // 循环 n 次,依次添加每一个节点
        L->next = new(Lnode) ; // 新建下一个节点
        L = L->next ; // L 指向下一个节点
        scanf( "%d", &temp ) ;
        L->data = temp ;
    }
    L->next = &head ; // 尾结点连回头结点,形成循环链表
    return 1;
}
Status CreatJosephus_L2 ( Linklist &head , int n ) { // 自动生成序列
    Lnode *L = &head ; // 记录头结点地址
    if ( n<=0 ) { // 序列长度 n 不合法
        return 0 ;
    }
    int temp = 1;
    L->data = temp ; // 为第一个节点赋值
    n = n - 1 ;
    while( n-- ) { // 循环 n 次,依次添加每一个节点
        L->next = new(Lnode) ; // 新建下一个节点
        L = L->next ; // L 指向下一个节点
        temp++;
        L->data = temp ;
    }
    L->next = &head ; // 尾结点连回头结点,形成循环链表
    return 1;
}
Status OutputJosephus_L ( Linklist &h , int n ) { // 从k开始报数,报数到m此人出列,输出所有人出列序列
    int m, k;
    /// 输入参数
    printf( "please input k and m :" ) ;
    scanf( "%d%d", &k, &m ) ; // 输入 k 和 m
    printf( "the seq with parameter( k=%d,m=%d ) is :\n", k, m ) ;

    /// 按参数模拟报数
    Lnode *p = &h ; // 取得头结点地址
    k-- ;
    if ( k<0 || m<0 ) { // 参数 k或m 不合法
        return 0 ;
    }
    while( k-- ) { // 首先从头结点开始向后报数k-1个(找到编号为k的人)
        p = p->next ;
    }
    while( n>0 ) { // 之后以 m 为周期一次输出每个出列的人的信息
        /// 此时 p 指向的人的报数为 1
        for( int i=2; i<m; i++ ) { // 从当前 p 向后找到报数为 m-1 的人,用 p 指向他
            p = p->next ;
        }
        printf( "%d ", p->next->data ) ; // 输出报数为m的人的信息
        p->next = p->next->next ; // 报数为 m-1 的人的下一人 指向 报数为 m 的人的下一人(删除报数为m的结点)
        p = p->next ; // p指向新的报数为 1 的人
        n--; // 循环链表人数-1
    }
    printf( "\n" ) ;
    return 1;
}

void MenuSelect ( Linklist &L ) {
    int op = -1 , st1 , st2 ;
    int n ; // 链表长度
    while( op != 0 ) {
        printf( "please select op: " ) ;
        scanf( "%d", &op ) ;
        switch ( op ) { // 功能选择
            case 0 : // 功能0:退出程序
                printf( "over !\n" ) ;
                break;
            case 1 : // 功能1:输入链表
                printf( "please input n:" ) ;
                scanf( "%d", &n ) ; // 输入链表长度
                printf( "please input seq :") ;
                st1 = CreatJosephus_L ( L , n ) ; // 输入n个数字建立循环链表,若成功则st=1
                if ( st1 == 0 ) { // 建立失败
                    printf( "error!\n" ) ;
                }
                break;
            case 2 : // 功能2:输入参数并模拟输出出队序列
                st2 = OutputJosephus_L( L , n ) ;
                if ( st2 == 0 ) { // 输出失败
                    printf( "error\n" ) ;
                }
                else { // 输出成功
                    printf( "successful\n" ) ;
                }
                break;
            default :
                printf( "error!\n" ) ;
        }
    }
}

Josephus_Main

#include<stdio.h>
#include<iostream>
#include"Josephus.h"
using namespace std ;

int main() {
    Linklist head ; // 建立链表
    MenuSelect( head ) ;
    return 0;
}
/* input: 5 1 2 3 4 5 1 3 样例解释: 序列长度 n = 5 参数:k=1,m=3 第一次 出队元素:3 剩余序列:4 5 1 2 第二次 出队元素:1 剩余序列:2 4 5 第三次 出队元素:5 剩余序列:2 4 第四次 出队元素:2 剩余序列:4 第五次 出队元素:4 剩余序列: */

运行截图: