約瑟夫環
什麼是約瑟夫環?
這裏用循環鏈表實現一個帶密碼的約瑟夫環
意思是有n個人,編號1-n,他們每個人手裏拿着屬於自己的密碼。大家按照編號坐成一圈,然後給定一個數m,然後大家從頭進行0-m報數,報到m的人出列,交出密碼,剩餘的人從這裏開始繼續報數,規則一樣...直到全部出列,問你最後的密碼是什麼?
easy
// 有頭結點循環鏈表實現約瑟夫環問題
#include<stdio.h>
#include<stdlib.h>
#define OK 1
#define ERROR 0
typedef int Status;
typedef struct rnode{
int num;//序號
int key;//密碼
rnode* next;
}rnode;
typedef rnode* ringlist;
Status creat(ringlist* L){
*L=(rnode*)malloc(sizeof(rnode));
if(*L==NULL){
printf("空間分配失敗!\n");
return ERROR;
}
(*L)->next=NULL;
return OK;
}
Status init(ringlist* L,int n){//
rnode* tail=*L;
for(int i=1;i<=n;i++){
rnode *newx;
newx=(rnode*)malloc(sizeof(rnode));
if(!newx){
printf("空間分配失敗!\n");
return ERROR;
}
newx->next=*L;
newx->num=i;
printf("輸入第%d個節點的密碼:",i);
scanf("%d",&newx->key);
// newx->key=i;
tail->next=newx;
tail=tail->next;
}
return OK;
}
int kill(ringlist L,int m,int res[]){//實現報m出列 ,結果存在res中
int cnt=0;//報數計數器
int len=0;//res數組計數器
rnode *p=L->next,*q=L,*del;
while(p!=q){//p==q時 表示只有頭節點
if(p==L){//一個循環 越過頭節點
p=p->next;
q=q->next;
continue;
}
cnt++;
if(cnt==m){
res[++len]=p->key;
del=p;
p=p->next;
q->next=p;
free(del);
cnt=0;
}
else{
p=p->next;
q=q->next;
}
}
return len;
}
void show(ringlist L){
rnode* p=L->next;
printf("\n");
while(p!=L){
printf("第%d個人的密碼是%d\n",p->num,p->key);
p=p->next;
}
printf("\n");
}
int main()
{
ringlist L;
int n,m,res[999],len;
printf("輸入人的個數: ");
scanf("%d",&n);
creat(&L);
init(&L,n);
show(L);
printf("輸入循環的基數:");
scanf("%d",&m);
len=kill(L,m,res);
printf("約瑟夫密碼是:\n");
for(int i=1;i<=len;i++)
printf("%d ",res[i]);
return 0;
}
還寫了一個沒有頭結點的,完全類似,唯獨判斷結束的地方有些修改
// 無頭結點循環鏈表實現約瑟夫環問題
#include<stdio.h>
#include<stdlib.h>
#define OK 1
#define ERROR 0
typedef int Status;
typedef struct rnode{
int num;//序號
int key;//密碼
rnode* next;
}rnode;
typedef rnode* ringlist;
Status init(ringlist* L,int n){//無頭結點插入多項式
*L=(rnode*)malloc(sizeof(rnode));
if(*L==NULL){
printf("空間分配失敗!\n");
return ERROR;
}
(*L)->num=1;
printf("輸入第1個節點的密碼:");
scanf("%d",&(*L)->key);
(*L)->next=*L;
rnode* tail=*L;
for(int i=2;i<=n;i++){
rnode *newx;
newx=(rnode*)malloc(sizeof(rnode));
if(!newx){
printf("空間分配失敗!\n");
return ERROR;
}
newx->next=*L;
newx->num=i;
printf("輸入第%d個節點的密碼:",i);
scanf("%d",&newx->key);
tail->next=newx;
tail=tail->next;
}
return OK;
}
int kill(ringlist L,int m,int res[]){//實現報m出列 ,結果存在res中
int cnt=0;//報數計數器
int len=0;//res數組計數器
rnode* p=L,*del;
rnode* pre=L;
int flag=1;
while(flag){
cnt++;
if(cnt==m){
//pre=p->next;
while(pre->next!=p)//找到前一個節點的位置,用於刪除當前節點
pre=pre->next;
res[++len]=p->key;
del=p;
p=p->next;
if(p->next==p)
flag=0;//判斷終點
pre->next=p;
free(del);
cnt=0;
}
else
p=p->next;
}
return len;
}
void show(ringlist L){
rnode* p=L->next;
printf("\n");
while(p!=L){
printf("第%d個人的密碼是%d\n",p->num,p->key);
p=p->next;
}
printf("\n");
}
int main()
{
ringlist L;
int n,m,res[999],len;
printf("輸入鏈表 的長度: ");
scanf("%d",&n);
init(&L,n);
show(L);
printf("輸入循環的基數:");
scanf("%d",&m);
len=kill(L,m,res);
printf("\n約瑟夫密碼是:\n");
for(int i=1;i<=len;i++)
printf("%d ",res[i]);
return 0;
}