循環鏈表解決帶密碼的約瑟夫環問題

約瑟夫環

什麼是約瑟夫環?

這裏用循環鏈表實現一個帶密碼的約瑟夫環

意思是有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;
}

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章