约瑟夫问题(循环单链表求解)

来源:互联网 发布:保险网络推广 编辑:程序博客网 时间:2024/06/12 03:28

约瑟夫问题是个有名的问题:N个人围成一圈,从第K个开始报数,第M个将被杀掉,最后剩下一个,其余人都将被杀掉。例如N=6,K=1,M=5,被杀掉的顺序是:5,4,6,2,3,1。

/*用循环链表实现约瑟夫问题*/#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指向第k个结点,p指向第k-1个结点        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个出发结点      printf("删除的结点号是:\n");    while(index>last)    {        for(int i=1;i<m;i++)        {            r=p;            p=p->next;        }//p指向第m个结点,r指向第m-1个结点        r->next=p->next;//删除第m个结点        printf("%3d",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;}
0 0