约瑟夫环,已知n个人,(编号从1、2、3、4......n),围在一张圆桌上,从编号为startnum的人开始报数,报到outnum的人出列,接着从下一个人开始从1报数,数到outnum的人又出列;依次规律重复下去,知道所有人全部出列,请写出出列的依次序号数。
这是一个约瑟夫环问题,用单链表来做,具体地:
1.建立一个无头结点的循环链表,依次编号1、2、3、4......n;
2.将临时首个指针p移动到开始报数的人的位置,以前保存该位置的前驱节点r->next=p(为了方便删除p);
3.开始报数,同时p和r向后移动,当报到outnum时,将p点删除,然后p重新赋值后面一个节点,r跟上;
4.若所有节点删除完毕,停止;否则继续执行第3部。
具体代码如下:
#include<iostream> using namespace std; struct Node { int data ; Node *next; }; //约瑟夫环儿的问题,一共len 个人 从第startnum个人开始报数 //数到outnum的人出列 求 出列序号是什么 void josephus(int Len,int startnum,int outnum) { Node *head=(Node*)malloc(sizeof(Node)); if (head==NULL)//判断内存是否申请成功 { return ; } head->next=NULL; head->data=1; Node *curr=head;//建立循环链表的时候的临时指针 for (int i=2;i<=Len;i++) { Node* pNew = (Node*)malloc(sizeof(Node)); pNew->data=i; curr->next=pNew; curr=pNew; } curr->next=head;//尾节点后继为头指针,构成循环链表 Node *p=head;//删除节点时用的当前指针 Node *r=curr;//r始终是p的前驱 while(--startnum)//将p移动到开始数的位置startnum { r=p; p=p->next; } while (Len--) { for ( int num=outnum;--num;r=p,p=p->next);//寻找要删除的位置 r->next=p->next;//将删除位置的后继位置赋值给前驱的后继指针 cout<<p->data<<" ";//打印删除节点序号 free(p); p=r->next;//将p重新赋值为第一个报数的人 } } void main() { josephus(12,1,2); }
执行结果如下图: