数据结构作业1-约瑟夫环问题

数据结构课作业,上网找了一圈发现没有和我们题一样的。自己写一个分享给有需要的同学。

题目如下:

约瑟夫(Josephus)环问题:编号为1,2,3,…,n的n个人按顺时针方向围坐一圈,每人持有一个密码(正整数)。一开始任选一个正整数作为报数的上限值m,从第一个人开始按顺时针方向自1开始顺序报数,报到m时停止。报m的人出列,将他的密码作为新的m值,从他在顺时针方向上的下一人开始重新从1报数,如此下去,直到所有人全部出列为止。建立n个人的单循环链表存储结构,运行结束后,输出依次出队的人的序号。

题目要求循环单链表完成,先放一下结构体,很简单的一个单链表的存储结构。

typedef struct LNode   //定义单链表节点类型 
{
	int data;      //数据域
	struct LNode *next; //指针域,指向后继节点 
} LinkList;

单链表的循环体现在建表上,这里采用尾插法(右插法)建表,以保证链表是正序的。链表头结点也存放数据。

建表函数没有返回值,所以需要先定义一个单链表指针变量,在函数中引用。函数传三个参数,第一个参数是引用的循环单链表,第二个参数是保存单链表数据域的数组,第三个参数是单链表的长度。

void CreateListR(LinkList *&L, int a[], int n)
{
	LinkList *s, *r;
	int i;
	L = (LinkList *)malloc(sizeof(LinkList));
	r = L;
	for (i = 0; i < n; i++)
	{
		s = (LinkList *)malloc(sizeof(LinkList));
		s->data = a[i];
		r->next = s;
		r = s;
	}
	r->next = L->next;   //构造循环结构
	L = L->next;
}

因为约瑟夫环需要不断地让成员“出列”,所以还需要定义一个删除节点的函数。和单链表删除节点的函数基本一致,返回值是删除的节点的数据。传两个参数,一个参数是引用的循环单链表,一个是要删除节点的位置(从头结点开始第几个节点)。

int ListDelete(LinkList *&L, int i)
{
	int j = 0;
	int e;
	LinkList *p = L, *q;
	while (j < i - 1)
	{
		j++;
		p = p->next;
	}
	q = p->next;
	e = q->data;
	p->next = q->next;
	free(q);
	return e;
}

下面就是main函数了,也是约瑟夫环的主要功能实现之处。

由于第一次出列是用户输入的数据,所以第一次出列单独写一段代码。

之后的节点出列嵌套两个for循环,外层循环计数还剩几个节点没有出列,内层循环计数哪个节点需要出列。这里需要注意一个问题,节点出列之前要标定新的头指针的位置,出列之后再移动头指针。

int main()
{
	//建表
	LinkList *L;
	int n, m;
	printf("请输入人数,初始报数值。人数不得超过20\n");
	scanf("%d", &n);
	scanf("%d", &m);
	int a[20] = { 0 };
	int b[20] = { 0 };
	for (int i = 0; i < n; i++)
	{
		a[i] = i+1;
	}
	CreateListR(L, a, n);

	//操作第一个节点
	LinkList *p = L;
	int e;
	for (int i = 0; i < m; i++)   //标明新头指针位置
	{
		p = p->next;
	}
	e = ListDelete(L, m-1);
	b[0] = e;
	L = p;   //移动头指针

	//操作其他节点
	for (int i = 0; i < n - 1; i++)
	{
		LinkList *q = L;
		for (int j = 0; j < e; j++)   //标明新头指针位置
		{
			q = q->next;
		}
		e = ListDelete(L, e-1);
		b[i + 1] = e;
		L = q;   //移动头指针
	}

	//按顺序输出
	for (int i = 0; i < n; i++)
	{
		printf("%d", b[i]);
	}

	system("pause");
	return 0;
}

以上就是全部代码,第一次写博客,如有不正确之处还望海涵。

你可能感兴趣的:(数据结构作业1-约瑟夫环问题)