C语言循环链表(不带头结点)解约瑟夫问题的一种变形

一.问题描述
约瑟夫(Joseph)问题的一种描述是:编号为 1,2,…,n 的 n 个人按顺时针方向围坐一圈,每人持有一个密码(正整数),一开始任选一个整数作为报数上限 m,从第一人开始按顺时针方向从自 1 开始顺序报数,报到 m 时停止报数。报 m 的人出列,将他的密码作为新的 m 值,从他的顺时针方向上的下一个人开始重新从 1 报数,如此下去,直至所有人全部出列为止,设计一个程序求出出列顺序。
二.要求:
利用单向循环链表存储结构模拟此过程,按照出列的顺序引出个人的编号。并且不需要头结点。
三.测试数据:
n=7,7个人的密码依次是3,1,7,2,4,8,4;m=6,正确的出列顺序为6,1,4,7,2,3,5

四.运行结果如下
C语言循环链表(不带头结点)解约瑟夫问题的一种变形_第1张图片
五.完整代码如下,详细见注释

#include"stdio.h"
#include"malloc.h"

typedef struct  //自定义结构体,
{
     
	int index,password;  //index存储每个人的序号,password存储每个人的密码
	struct  *next;
}Node,*Linklist;  //Node定义结点,Linklist定义指针
Linklist p,first,temp; //建立全局变量,方便

void Initlist(int n) //n个元素的链表
{
     
	int i,j,num;;
	first=(Node*)malloc(sizeof(Node));   //创建首元结点
	if (!first)
		return 0;
	
	p=first; //拷贝副本
	for( i=1;i<n;i++)
	{
     
		temp=(Node*)malloc(sizeof(Node)); //新建结点
		if (!temp)
			return 0;
		
		p->next=temp; //p一开始在表头,新结点插后
		p=temp;  //p向前移动
	}
    p->next=first; //尾部连接表头
    temp=first;    //让temp做first副本
	
    for( j=1;j<=n;j++)
    {
     
		temp->index=j;  //j是序号
		printf("请输入第%d个人的密码:",j);
		scanf("%d",&num);
		temp->password=num;  //存储密码
		temp=temp->next;
    }
    temp=p;  //这时候temp指向最后一个元素
}

void find(int m,int n)    
{
     
	int i,j;
	for(i=1;i<=n;i++)         
	{
     
		for(j=1;j<m;j++)      
			temp=temp->next; //temp指向第m-1个元素
		
		p=temp->next;    //p指向第m个元素
		m=p->password;  //更新m的值
		printf("%d,",p->index);  //输出出列人的序号
		temp->next=p->next;  //删掉p结点
		free(p);      //释放动态申请的结点空间
	}
	
	return 0;
}

void main()

{
        int m,n;   //m为报数初值,n为初始人数
printf("请输入报数初值m:");
scanf("%d",&m);
printf("请输入初始人数n:");
scanf("%d",&n);
Initlist(n);  //初始化循环链表
printf("出队的人依次是:");
find(m,n);    //开始淘汰

}

你可能感兴趣的:(笔记,链表,c语言,数据结构)