循环链表解决Josephus环轮流报数问题

#include<stdio.h>
#include<stdlib.h>
#include<math.h>
#include<string.h>

/**
 *@Name:Josephus环轮流报数问题 
 *@Description:
 * 问题描述:
 * 设有n个人围坐在一个圆桌周围,现从第s个人开始报数,数到第m的人出列,然后从出列
 * 的下一个人重新开始报数,数到第m的人又出列...如此反复直到所有的人全部出列为止。 
 * 问题:对于任意给定的n,s和m,求出按出列次序得到的n个人员的序列。
 * 
 * 解决方案:循环链表 
 *	1、创建一个包含n个结点的循环链表模拟n个人玩轮流报数出局游戏(1,2,3,.....n)。
 * 2、从当前结点出发,每隔一定的数量(游戏设定的出局数)删除一个结点,只到剩下最后一个结点。
 * 3、最后一个结点就是所要求解的游戏前的那个人的编号。 
 *@Author:Freedoman
 *@Date: 2014-8-6
 */


struct Node {
    int data;						
    struct Node * next;
};
typedef struct Node * PNode;


/*-------游戏准备:创建包含n个结点的循环链表---------*/
PNode createCirLinkedList(int n){
    PNode head = NULL,p = NULL,temp;
    int i;
    for(i = 0; i < n; i ++){
    	// 第1个结点 
    	if(i == 0){
    		temp = (PNode)malloc(sizeof(head));
    		head = temp;
    		p = head;
    		temp->data = i+1;
    		temp->next = head;
    	}else{
	    	// 以后的结点
			temp = (PNode)malloc(sizeof(head));
			temp->data = i + 1;
			temp->next = head;
			p->next = temp;
			p = temp;
	    }
    }
    return head;
}
/*-----------从头结点出发查找第s个结点--------*/
PNode findElement(PNode head,int s){
	PNode p = head;
	int i;
	for(i = 2; i<= s; i++){
		p = p->next;
	}
	return p;
} 


/*-----------游戏开始:迭代删除结点-------------*/
int deleteElement(PNode head,int m){
	PNode p = head;
	int i;
	while(p != p->next){
		
		// 轮流报数,p迭代到要出局的前一个结点 
		for(i = 0; i < m-2; i++){
			p = p->next;
		} 
		// 打印下一个要出局的数字
		printf("出局>>>>%d\n",p->next->data);
		// 出局(删除结点) 
		p->next = p->next->next;
		// 迭代进入下一轮 
		p = p->next;
		continue; 
	}
	// 打印出最一个剩余的
	printf("出局>>>>%d\n",p->data); 
	return 0;
} 

/*-------打印当前循环链表-----------------*/
void printCirLinkedList(PNode head){
    PNode p = head;
    printf("打印[");
    do{
  		printf(" %d ",p->data);
  		p = p->next;
    }while(p != head);
    printf(" %d ",p->data);
    printf("]\n");
}

int main(){
    int n,s,m;
    printf("请输入参与者个数n >>>");
    scanf("%d",&n);
    printf("请输入起始编号s >>>");
    scanf("%d",&s);
    printf("请输入间隔m >>>");
    scanf("%d",&m);
    PNode head = createCirLinkedList(n);
    printCirLinkedList(head);
    findElement(head,s); 
    deleteElement(head,m); 
    return 0;
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值