C语言单链表实现约瑟夫环

1.约瑟夫环问题

编号为1,2…n的人按顺时针方向围坐一圈,每个人持有一个密码(正整数)。开始任选一个整数作为报数上限m,从第一个人顺时针自1开始顺时针报数,报到m时停止报数。报到m的人出列,将他的密码作为新的m值,从他顺时针方向上的下一个人开始重新从1报下去,如此下去,直到所有的人全部出列为止。

例如,m的初值为20;n=7,7个人的密码依次是3,1,7,2,4,8,4。求出列的顺序。

2.问题分析

1.要实现报数,必须有一个数来计数,判断是否到m。

2.出列,用单链表实现即将此节点从单链表中删除。所以,必须有两个指针,一个指向当前节点,一个指向当前节点的上一个节点。删除操作主要用这两个节点来完成。

模拟图如下,第一个数字为序号,第二个数字为密码
C语言单链表实现约瑟夫环_第1张图片

3.C语言实现

C语言实现,采用不带头结点的循环单链表实现,因此我们需要一个头指针来指明链表的开始,又因为要循环,所以需要一个尾指针来指明链表的尾。

1.以下为初始化循环单链表的过程。此处注意返回值为结构体类型的指针,返回链表的头指针H

typedef struct node 
{
	int serial;
	int code;
	node *next;
}Josephring,*JS;

JS init_ring()
{
	int n,i;
	JS Temp;
	JS rear,H;
	printf("请输入n的取值:");
	scanf("%d",&n);
	rear = H = NULL;
	for (i=1;i<=n;i++)
	{
		printf("请输入第%d个人的密码值:",i);
		Temp = (JS)malloc(max * sizeof(JS));
		Temp->serial = i;
		scanf("%d",&Temp->code);
		if (H == NULL)
		{
			H = Temp ;
		}
		else
		{
			rear->next = Temp;
		}
		rear = Temp;  //表尾指针指向新的节点;
	}
	rear->next = H ;
	return H;
}

2.接下来实现出列过程

void circle()
{
	JS q = NULL;
	JS p = init_ring();
	int m,i;
	i=1;
	printf("请输入开始循环的m值m=");
	scanf("%d",&m);
	while (p->next!=p)
	{
		q = p;
		p = p ->next;
		i++;
		if (i==m)
		{
			printf("序号为%d的人出列\n",p->serial);
			m = p->code ;//他的密码作为新的m值;
		    printf("m=%d\n",m);
			q ->next = p->next;
			free(p);
			p = q ->next;
			i=1;
			
		}	
		
	}
	printf("序号为%d的人出列\n",p->serial);
	free(p);
	
}

JS p = init_ring();意思是p指针指向头结点。
此处举例一次出列的过程:
m=20;
执行到i++时,p,q指针情况如下:
C语言单链表实现约瑟夫环_第2张图片
再执行

q ->next = p->next;
free(p);
p = q ->next;

free§在链表中表示就是2(用红色标出)那条线断开,当然在计算机中是内存释放。
C语言单链表实现约瑟夫环_第3张图片

然后继续循环。

运行结果截图给出:
C语言单链表实现约瑟夫环_第4张图片

你可能感兴趣的:(算法练习)