Josephus(约瑟夫)问题分别用循环链表和数组实现


#include<iostream>
using namespace std;
void Josephus(int n,int m,int k)
{
    int *a=new int [10000],i;
    int count=0;//计算被退出的人数(n-1)
    int t=0;//1,2,3..m报数记数变量
    for(i=0;i<n;i++)
        a[i]=i+1;
    i=k-1;
    while(count<n-1)//只剩下一个时退出循环
    {
        if(a[i]!=0)
            t++;
        if(t==m)
        {
            t=0;//记数归0
            printf("%4d",a[i]);//依次输出删除的编号
            a[i]=0;//给删除的数组赋0

            count++;//退出人数加1    
        }
        i++;
        if(i==n)
            i=0;//报数到末尾后i恢复为0
    }
    for(i=0;i<n;i++)
        if(a[i]!=0)
        {
            printf("\n最后剩余的结点是:%4d\n",a[i]);
            return;
        }
}
int main()
{
    int n,m,k;
    cout<<"请输入结点的个数:"<<endl;
    scanf("%d",&n);
    cout<<"请输入报道报数周期是:"<<endl;
    scanf("%d",&m);
    cout<<"请输入从第几个数开始报数:"<<endl;
    scanf("%d",&k);
    Josephus(n,m,k);
    return 0;
}

/*用数组实现约瑟夫问题比较上面的更复杂,自己想的,没参考书上的。*/
#include<iostream>
using namespace std;
void Josephus(int n,int m,int k)
{
    int *a=new int [10000],i;
    int count=0;//计算被退出的人数(n-1)
    int t=0;//1,2,3..m报数记数变量
    int l=1;//while退出循环条件
    for(i=0;i<n;i++)
        a[i]=i+1;
    while(l)
    {
        for(i=k-1;i<n;i++)
        {
            if(a[i]!=0)
            {

                t++;
                if(t==m)
                {
                    t=0;//记数归0
                    printf("%4d",a[i]);//依次输出删除的编号
                    a[i]=0;//给删除的数组赋0
                    count++;//退出人数加1    
                }
            }
            if(count==n-1)
            {
                l=0;//循环终止
                break;    
            }
        }
        k=1;//非第一次时将i变为从0开始
    }
    for(i=0;i<n;i++)
        if(a[i]!=0)
        {
            printf("\n最后剩余的结点是:%4d\n",a[i]);
            return;
        }
}
int main()
{
    int n,m,k;
    cout<<"请输入结点的个数:"<<endl;
    scanf("%d",&n);
    cout<<"请输入报道报数周期是:"<<endl;
    scanf("%d",&m);
    cout<<"请输入从第几个数开始报数:"<<endl;
    scanf("%d",&k);
    Josephus(n,m,k);
    return 0;
}
/*用循环链表实现约瑟夫问题*/
#include<iostream>
#include<stdlib.h>
using namespace std;
typedef struct LNode
{
    int data;
    struct LNode *next;
}LNode,*LinkList;
void Josephus(int n,int m,int k)
{
    LinkList p,r,list=NULL;
    int i;
    for(i=1;i<=n;i++)
    {
        p=(LinkList)malloc(sizeof(LNode));//申请一个新的链结点
        p->data=i;//存放第i个结点的编号
        if(list==NULL)
            list=p;
        else
            r->next=p;
        r=p;
    }
    p->next=list;//至此,建立一个循环链表
    p=list;
    for(i=1;i<k;i++)
    {
        r=p;
  /*请注意,此行不是多余的,因为当k!=1,但m=1时如果没有这条语句,此时删除动作无法完成*/
        p=p->next;
    }//此时p指向第1个出发结点
    while(p->next!=p)
    {
        for(i=1;i<m;i++)
        {
            r=p;
            p=p->next;
        }//p指向第m个结点,r指向第m-1个结点
        r->next=p->next;//删除第m个结点
        printf("%4d",p->data);//依次输出删除结点的编号
        free(p);//释放被删除结点的空间
        p=r->next;//p指向新的出发结点
    }
    printf("\n最后剩余的结点是:%4d\n",p->data);//输出最后一个结点的编号
}
int main()
{
    int n,m,k;
    cout<<"请输入结点的个数:"<<endl;
    scanf("%d",&n);
    cout<<"请输入报道报数周期是:"<<endl;
    scanf("%d",&m);
    cout<<"请输入从第几个数开始报数:"<<endl;
    scanf("%d",&k);
    Josephus(n,m,k);
    return 0;
}
/*任务:
一群小孩围成一圈,任意假定一个数m,从第一个小孩起,顺时针方向数,每数到第m个小孩时,该小孩便离开。小孩不断离开,圈子不断缩小。最后剩下的一个小孩便是胜者。求胜者的编号?
要求
以面向对象技术进行程序设计
建立环状链表类
程序便于维护与扩张:如易于对小孩数量n和数数间隔m进行变化
改变获胜者数量,使其可设为任意值
可中途增加小孩人数
*/
/*结构体实现*/
#include<iostream>
#include<stdlib.h>
using namespace std;
typedef struct LNode
{
    int data;
    struct LNode *next;
}LNode,*LinkList;
class Jos
{
private:
    int n,m,k,last;//结点个数,报数周期,报数起始数.
    int index;//标记剩余人数,标记插入时r第一个的指向.
    LinkList list,r;
public:
    Jos(){list=NULL;r=NULL;}
    void set();
    void Josephus();
    void Insert();
    void is_add();
    void print_Josephus();
}XPY;
void Jos:: set()//插入函数
{
    cout<<"请输入结点的个数:"<<endl;
    scanf("%d",&n);
    cout<<"请输入报道报数周期是:"<<endl;
    scanf("%d",&m);
    cout<<"请输入从第几个数开始报数:"<<endl;
    scanf("%d",&k);
    cout<<"请输入剩余个数:"<<endl;
    scanf("%d",&last);
}
void Jos:: Josephus()//建立一个循环链表
{
    LinkList p;
    int i;
    index=n;//结点个数赋初值
    for(i=1;i<=n;i++)
    {
        p=(LinkList)malloc(sizeof(LNode));//申请一个新的链结点
        p->data=i;//存放第i个结点的编号
        if(list==NULL)
            list=p;
        else
            r->next=p;
        r=p;
    }
    p->next=list;//至此,建立一个循环链表
}
void Jos:: Insert()//循环链表的插入
{
    LinkList p=(LinkList)malloc(sizeof(LNode));
    p->data=n+1;
    n++;//个数加1
    index++;//个数加1
    p->next=r->next;
    r->next=p;
    r=p;
}
void Jos:: is_add()//中途添加函数
{
    printf("是否添加成员(Y/N)\n");
    char ch;
    cin>>ch;
    while(1)
    {    
        system("cls");
        ch=tolower(ch);//转换为全小写的
        if(ch=='y')
            Insert();
        else if(ch=='n')
            break;
        else
            printf("输入有误\n");
        system("cls");
        printf("是否继续添加成员(Y/N)\n");
        cin>>ch;
    }
}
void Jos:: print_Josephus()//循环的执行
{
    LinkList p=list;
    for(int i=1;i<k;i++)
    {
        r=p;
        /*请注意,此行不是多余的,因为当k!=1,但m=1时如果没有这条语句,此时删除动作无法完成*/
        p=p->next;
    }//此时p指向第1个出发结点
    while(index>last)
    {
        for(i=1;i<m;i++)
        {
            r=p;
            p=p->next;
            
        }//p指向第m个结点,r指向第m-1个结点
        r->next=p->next;//删除第m个结点
        printf("删除的结点号是:%d\n\n",p->data);//依次输出删除结点的编号
        free(p);//释放被删除结点的空间
        is_add();
        p=r->next;//p指向新的出发结点
        index--;//删除结点,个数减1
    }
    while(index--)//胜利者的输出
    {
        printf("\n最后剩余的结点是:%4d\n",p->data);//输出最后一个结点的编号
        p=p->next;
    }
}
int main()
{
    XPY.set();
    XPY.Josephus();
    XPY.print_Josephus();
    return 0;
}
/*数组实现*/
#include<iostream>
using namespace std;
class Jos
{
private:
    int *a,length,data;
    int n,m,k,last;//结点个数,报数周期,报数起始数.
public:
    Jos()
    {
        a = new int [1000000];
    }
    void set();
    void is_add();
    void print_Josephus();
}XPY;
void Jos:: set()//插入函数
{
    cout<<"请输入结点的个数:"<<endl;
    scanf("%d",&n);
    cout<<"请输入报道报数周期是:"<<endl;
    scanf("%d",&m);
    cout<<"请输入从第几个数开始报数:"<<endl;
    scanf("%d",&k);
    cout<<"请输入剩余个数:"<<endl;
    scanf("%d",&last);
}
void Jos:: is_add()//中途添加函数
{
    printf("是否添加成员(Y/N)\n");
    char ch;
    cin>>ch;
    while(1)
    {
        ch=tolower(ch);//转换为全小写的
        if(ch=='y')
            a[n++]=n+1;
        else if(ch=='n')
            break;
        else
            printf("输入有误\n");
        printf("是否继续添加成员(Y/N)\n");
        cin>>ch;
    }
}
void Jos::print_Josephus()
{
    int i;
    int count=0;//计算被退出的人数(n-1)
    int t=0;//1,2,3..m报数记数变量
    for(i=0;i<n;i++)
        a[i]=i+1;
    i=k-1;
    while(count<n-last)//只剩下一个时退出循环
    {
        if(a[i]!=0)
            t++;
        if(t==m)
        {
            t=0;//记数归0
            printf("删除的结点为:%4d\n",a[i]);//依次输出删除的编号
            a[i]=0;//给删除的数组赋0
            count++;//退出人数加1    
            is_add();
        }
        i++;
    
        if(i==n)
            i=0;//报数到末尾后i恢复为0
    }
    for(i=0;i<n;i++)
        if(a[i]!=0)
            printf("\n最后剩余的结点是:%4d\n",a[i]);
}
int main()
{
    XPY.set();
    XPY.print_Josephus();
    return 0;
}
    
原文地址:https://www.cnblogs.com/heqinghui/p/2711709.html