数据结构-约瑟夫问题(来筛选回答问题者的学号)

/*2018.9.26 数据结构作业  约瑟夫问题*/ 
/*问题描述:有n个人,编号为1,2,…, n,站成一圈, 每次第m个将会被处决,
            直到只剩下一个人。约瑟夫通过给出m来决定赦免其中的一个人。 
            例如当n=6,m=5时,5,4,6,2,3将会被依次处决,而1将会幸免            */ 
/*约瑟夫环(约瑟夫问题):    是

一个数学的应用问题:已知n个人(以编号1,2,3…n分别表示)
                            围坐在一张圆桌周围。从编号为k的人开始报数,
                            数到m的那个人出列;他的下一个人又从1开始报
                            数,数到m的那个人又出列;依此规律重复下去,
                            直到圆桌周围的人全部出列。*/ 
                            
//理解:输入开始的第几个人以及每次数几个人,不停循环喊号,直到剩下最后一个人
/*作业内容:用约瑟夫环写出学号删除系统,每次输入开始的地点以及每次的个数进行删除
            剩下的最后一个人进行作业的检查 */ 

//解法:构建循环链表 

 

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

typedef struct LinkList
{
	int data;
	struct LinkList *next; 
}LinkList;


/*链表初始化*/ 
void *star(LinkList **head)                     //初始化链表,然后方便输入 
{
	*head=(LinkList*)malloc(sizeof(LinkList));  //初始化分配内存,空间  
	 
}
 
//链表创建
void creat(LinkList *p,int a)
{
	LinkList *s;                                //链表创建 
	int i=a-1;  
	p->next=p;                                //学号赋值 
	p->data=a;
	while(i>0)                                     
	{
		s=(LinkList*)malloc(sizeof(LinkList));   
		s->next=p->next;
		s->data=i;                              //循环链表创建并赋值 
		p->next=s;                                 /*s=(DLinkList*)malloc(sizeof(DLinkList));         //分配新空间 
													s->next=head->next;                              //头查法建表 
													head->next=s;
													s->data=x; */ 
		i--;
	}
	
	
} 

//显示内容函数
//便于写程序过程中进行运行以便观察结构正确性
 
void show(LinkList *p,int a)
{
	LinkList *s;
	int i=1;
	s=p->next;
	
	while(i!=55)
	{
		printf("%d\n",s->data);
		s=s->next; 
		i++;
	}
} 

//筛选人员,选取函数 
void change(LinkList *p,int m,int n,int a)
{
	int num;
	int i=1;
	LinkList *s,*q,*w;                       //s为指向学号指针,q方便删除,w记录将要删除结点地址 
	s=p;
	q=p;
	while(s->data!=n)                        //如若没有找到学号为n的人,则继续循环,直到找到 
	{
		s=s->next; 
	}
	while(q->next!=s)                         //指针q指向前一位置,便于删除 
	{
		q=q->next;
	} 
//	q->next=s->next;
//	w=s;
//	s=s->next;
//	free(w);
	while(a!=1)                              //找每当找到一个人,则需要删除此人学号,然后继续寻找下一个人,直到剩下一个人,即a=1时 
	{
		if(i==m)                             //if语句,进行查数,如果到达想要删除的第几个数,则进行链表删除操作 
		{
			q->next=s->next;                 //所删除节点前一结点连接删除节点下一节点 
			w=s;                             //保存删除节点地址 
			a--;                             //因为删除数据,则数据总数减一 
			s=s->next;                       //指针s指向下一结点,继续查询 
			free(w);                         //释放删除节点 
			i=1;                             //重置i,重新查数 
			continue;                        //直接进行下一循环 
		}
		s=s->next;                           //如果没到达,则继续下一个结点计数 
		q=q->next;
		i++;                                 //计数器加一 
	}
	printf("%d",s->data);                    //输出最后剩下的学号 
}
  
int main() 
{
	LinkList *p;
	int n,m,num,a;                            //n为从第n个人开始,m为每次数m个数,num为选取人的学号,a为班级人数 
	printf("请输入班级人数:");
	scanf("%d",&a);
	printf("请输入从第几个人开始:");
	scanf("%d",&n);
	printf("请输入每次数几个数:");
	scanf("%d",&m);
	star(&p);                           //链表初始化 
	creat(p,a); 						//链表创建
//	show(p,a);                          //展示循环链表,便于观察是否创建成功                          
	change(p,m,n,a);					//选择函数,筛选人员 
	return 0;
}

 

 

 

//待解决问题:  1.链表头部初始化**head原因
//              2.循环链表创建 改变方式以后发现不好用了
                 /*尝试办法:
                              s->next=p->next;
                              p->next=s;
                               建立以后没有链接上,特意输出过多数,发现并没有循环输出
                */ 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值