约瑟夫环问题。

([写在前面]这题是数据结构的作业,网上找了半天没找到答案,只好到处借鉴一下,硬搞出来了…)
[问题描述] 设有n个人围坐一圈,现从某个人开始报数,数到m的人出列,接着从出列的下一个人开始重新报数,数到m的人又出列,如此下去,直到所有人都出列为止。试设计确定他们的出列次序序列的程序。
[基本要求] 选择单向循环链表作为存储结构模拟整个过程,并依次输出出列的各人的编号。
(1)根据下面给出的部分源码,理解题意,在有下划线的位置上删除下划线,编写需要的语句,将程序完整化,并要求调试成功。
(2)根据屏幕调试的实际情况填写调试过程
[实现提示] 由于该问题是由古罗马著名史学家Josephus提出的问题演变而来,所以通常称之为Josephus问题。
程序运行之后,首先要求用户指定初始报数的上限值,可以n<=30,此题中循环链表可不设头结点,而且必须注意空表和“非空表”的界限。如:n=8,m=4时,若从第一个人,设每个人的编号依次为1,2,3,…开始报数,则得到的出列次序为4 8 5 2 1 3 7 6,如下图所示,内层数字表示人的编号,每个编号外层的数字代表人出列的序号。

直接上代码


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

#pragma warning (disable:4996)
using namespace std;

/*定义链表的结点*/

typedef struct node
{
	int num;
	struct node *next;
}Lnode, *Linklist;


/*初始化单向循环链表head*/

void linkinit(Linklist &head)
{
	int num = 0;
	head = NULL;
}

/*使n个人围成一圈,生成不带头结点的单向循环链表,头指针为head,并给每个人表识号数*/
/*先生成不带头结点的单向链表的方法:在单向循环链表最后一个结点后插入*/
/*最后生成单向循环链表的方法:将最后一个结点的指针指向头指针,形成循环链表*/

Linklist linkcreate(Linklist &head, int n)
{
	Linklist s, tail;  /* s是指向动态分配新结点的指针,tail是指向链表的最后一个结点的指针*/
	int i;
	s = (Linklist)malloc(sizeof(Lnode));
	if (!s) return head;
	s->num = 1;
	head = s;
	tail = s;
	for (i = 2; i <= n; i++)
	{
		s = (Linklist)malloc(sizeof(Lnode));
		if (!s) return head;
		s->num = i;        /* 将表识号i的值赋给新结点*/
		tail->next = s;        /* 在tail指针后插入一个新结点*/
		tail = s;
	}
	tail->next = head;   /* 最后一个结点的指针指向头指针,形成循环链表*/
	return head;
}/*linkcreate*/


/*现从第1结点开始报数,数到m的结点从单向循环链表中删除,并输出结点的编号*/
void linktraverse(Linklist head)
{
	Linklist  p;
	printf("the circle_linklist is :");
	printf("%4d", head->num);
	p = head->next;
	while (p->next != head->next)     /* 判断游历p指针是否指向头结点*/
	{
		printf("%4d", p->num);
		p = p->next;
	}


	printf("\n");
}
Linklist linkselect(Linklist &head, int m)
{
	Linklist  p, q;
	
	int i, t;
	p = head->next;
	t = 1;
	q = head;/* p是单向循环链表中游历的指针,指向当前报数的结点;q为p的前趋指针*/
	p = q->next;

	printf("the Joseohus_linklist is :");
	while (q != p)
	{
		t++;    /* 累计报一次数*/
		if (t%m == 0)      /* 数到m的人出列*/
		{
			printf("%4d", p->num);
			cout << endl;
			q->next = q->next->next;       /* 删除p指向的结点*/
			free(p);           /* 回收p结点占用的存储空间*/
			p = q->next;
			//linktraverse(head);
		}
		else
		{
			p = p->next;        /* p指向当前报数的结点的下一个结点;q为p的前趋指针*/
			q = q->next;
		}
		
	}
	head = p;
	return head;    /* 返回当前单向循环链表*/
}/*linkselect*/


/*单向循环链表的输出*/




/*主函数main()*/

int main()
{
	int n, m;
	Linklist  head;
	printf("\ninput the total number: ");
	scanf("%d", &n);
	printf("\ninput the number to call: ");
	scanf("%d", &m);
	linkinit(head);
	linkcreate(head, n);   /* 调用linkcreate()函数,创建n个结点的单向循环链表*/
	if (head == NULL) printf("malloc failure...\n");
	else  linktraverse(head);
	linkselect(head, m);   /* 调用linkselect()函数,求解Josephus问题,依次输出出列的各结点的编号*/
	printf("\nthe last one is : %d\n", head->num);
}/*main*/
  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值