已知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;
}