返回首页   进站必读

17.7 约瑟夫环


17.7 约瑟夫环

已知n个人(以编号1,2,3…n分别表示)围坐在一张圆桌周围。从编号为k的人开始报数,数到m的那个人出列;他的下一个人又从1开始报数,数到m 的那个人又出列;依此规律重复下去,直到圆桌周围的人全部出列。

解决约瑟夫环,可以采用循环链表的数据结构,就是将一个链表的尾元素指针指向队首元素。

解决问题的核心步骤:(程序的基本算法) 1、建立一个具有n个链结点的环形链表; 2、确定第1个报数人的位置; 3、不断从链表中删除链结点,直到链表为空。

typedef struct node *link;
struct node {
	unsigned char elem;
	link next;
};

void josephus(int n, int k, int m) //n为总人数,k为第一个开始报数的人,m为喊到m就出列的数字
{
	/* p为当前节点;r为辅助节点,指向p的前驱节点;head为头节点 */
	int i;
	link p, r, head = NULL;	/* 建立循环链表 */
	
	for (i = 0; i < n; i++)
	{
		p = (link)malloc(sizeof(*p));
		p->elem = i+1;
		if (head == NULL)
			head = p;
		else
			r->next = p;
		r = p;
	}
	p->next = head;		/* 使链表尾节点指向头节点,构成环状链表 */
	p = head;		/* 使p指向头节点 */

	/* 把当前指针移动到第一个报数的人 */
	for (i = 0; i < k; i++)
	{
		p = p->next;
	}

	/* 循环地删除队列节点 */
	while (p->next != p)
	{
		for (i = 0; i < m-1; i++)
		{
			r = p;
			p = p->next;
		}

		r->next = p->next;
		printf("被删除的元素:%4d\n", p->elem);
		free(p);
		p = r->next;
	}
	printf("最后一个元素:%4d\n", p->elem);
	free(p);
}

int main(void)
{
	josephus(9, 1, 5);
	return 0;
}