约瑟夫环(Josephus)循环链表解决

关于约瑟夫环的简单思路技巧
题目要求:
分析题目:
设编号为1,2,3,4…n的n个人顺时针坐一圈,约定编号为K的人按顺时针从1开始报数,数到m的人出列,他的下一位从1开始 报数…

默认第一次输入刚开始的序号,之后选择到谁就用谁的密码,并把它删掉。

思路分析:正常情况下取到P节点密码m后,p.pre=p.next;for(i=0;im;i++);删除节点,从他的下一个节点开始循环。一般情况可以,但是需要考虑密码为0,1的特殊情况(密码为1,需要删除当前节点,以及第一次键入为1的特殊情况),较复杂。

现提供一种较简单的思路:永远让指针指向实际链表开始应该数的第一个节点的前一个节点,从而避免考虑1,0的情况。首先开始第一次由键入开始序号时,先让结点指针指向列表的最后一位,以键入的第一个数开始数,数到最后还是让节点指向实际应该节点的前一位。直到最后链表里只有一个节点时结束循环,并输出接收到的顺序。

话不多说,上代码:

while (p->next != L1)//找到尾指针,此时结点指针p在最后一位节点,第一次默认从第一个开始数,应该指向最后一位
	{
		p = p->next;
		r = p;
	}
while (p->next != p)
	{
		for (gg = 1; gg < ss; gg++)//指针移动( ss-1 )次,移动到将要删除节点的前一个节点
		{
			p = p->next;//指针移动
		}
		m = p->next->date.m;//取出序号,以及下一次循环的ss
		ss = p->next->date.n;
		A[kk] = m;
		kk++;//添加到输出数组
		p->next = p->next->next;//删除应该删除的节点,此时指针还是旨在应该开始节点的上一位

	}

较完整代码

typedef struct number
{
	int m;//存储其所在的位置
	int n;//存储其数据
}number;
typedef struct londe
{
	number date;//数据类型存储为结构体
	struct londe *next;//指向下一个节点
}londe, *Linklist;//指向结构体的指针
int A[7] = {0,0,0,0,0,0,0};//接受返回的顺序,全局,限制7个

Linklist *  inn()
{
	number S;
	Linklist *L = NULL;//创建空链表
	londe *q, *r = NULL;//新建节点,尾部插入添加一个尾指针
	int m = 1, n;//m:存储的第几个   n:存储的数字
	printf("请输入7个人所依次所拿的密码\n");
	for (m; m < 8; m++)
	{
		scanf_s("%d", &n);//存储到结构体里
		S.m = m;//序号
		S.n = n;//密码
		q = (londe *)malloc(sizeof(londe));
		q->date = S;//赋值给节点
		if (L == NULL)
		{
			L = q;//直接赋值第一个节点
		}
		else//判断为空,本例中无用
		{
			r->next = q;
		}
		r = q;//尾指针总是指向最后一个节点
	}
	if (r != NULL)
		r->next = L;//指回去第一个节点
	return L;
}
int main()
{
	int i = 1,k;
	int kk = 0;//数组专用
	int gg = 1;//判断链表为1的情况
	int ss=1;//接受传来的第一次定义的要循环的m值;
	int m, n;//接受返回链表结构体所包含的序号以及数值
	Linklist *L1 = NULL;//接受返回链表
	printf("请输入第一次判断的ss值\n\n");
	scanf_s("%d", &ss);
	L1 = inn();//接受循环的列表
	londe *p = L1;//新建节点指向L,遍历L;
	londe *r=NULL;//尾指针

	while (p->next != L1)//找到尾指针,此时结点指针p在最后一位节点,第一次默认从第一个开始数,应该指向最后一位
	{
		p = p->next;
		r = p;
	}

	while (p->next != p)
	{
		for (gg = 1; gg < ss; gg++)//指针移动( ss-1 )次,移动到将要删除节点的前一个节点
		{
			p = p->next;//指针移动
		}
		m = p->next->date.m;//取出序号,以及下一次循环的ss
		ss = p->next->date.n;
		A[kk] = m;
		kk++;//添加到输出数组
		p->next = p->next->next;//删除应该删除的节点,此时指针还是旨在应该开始节点的上一位

	}
	A[kk] = p->date.m;//最后一个数,提取添加
	for (i = 0; i < 7; i++)
	{
		printf("输出顺序为 %d \n",A[i]);
	}
	scanf_s("%d", &k);
	return 0;
}

在这里插入图片描述

算是第一次小总结吧,欢迎指正,另外思路是自己想的,如有和其他相重复/接近的,声明不是抄袭哈!

猜你喜欢

转载自blog.csdn.net/S_qasdweed/article/details/84191248