09. 约瑟夫环
一、什么是约瑟夫环
约瑟夫问题为:设编号为 1, 2, ……, n 的 n 个人围坐一圈,约定编号为 k (1≤ k ≤ n) 的人从 1 开始报数,数到 m 的那个人出列,她的下一位又从 1 开始报数,数到 m 的那个人又出列,以此类推,知道所有人出列为止,由此可以产生一个出队编号的序列。
假设一共有 5 个人(n = 5),从第一个人开始报数(k = 1),数到 2 的那个人出列(m = 2),得到的出队编号如下:
约瑟夫环的表示:
typedef int ElementType;
typedef struct LNode {
ElementType Data;
struct LNode * Next;
} LNode, * Josephus;
生成约瑟夫环:
/**
* @brief 生成约瑟夫环
*
* @param count 小孩个数
* @return Josephus 指向约瑟夫环的第一个节点的指针
*/
Josephus GenerateJosephus(int count)
{
Josephus first = NULL, current = NULL, s = NULL;
for (int i = 0; i < count; i++)
{
if (i == 0)
{
first = (Josephus)malloc(sizeof(LNode));
first->Data = i + 1;
first->Next = first;
current = first;
}
else
{
s = (Josephus)malloc(sizeof(LNode));
s->Data = i + 1;
s->Next = first;
current->Next = s;
current = s;
}
}
return first;
}
获取约瑟夫环的小孩出圈队列:
/**
* @brief 获取约瑟夫环的小孩出圈队列
*
* @param first 约瑟夫环
* @param count 小孩个数
* @param start 从哪个小孩开始报数
* @param number 报数间隔
*/
void GetJosephusQuene(Josephus first, int count, int start, int number)
{
Josephus s = NULL;
Josephus current = first;
if (first == NULL || count < 1 || start < 1 || start > count || number < 1)
{
printf("参数输入有误!\n");
return;
}
// 报数前,current指针移动start-1次
for (int i = 0; i < start - 1; i++)
{
current = current->Next;
}
// 创建一个辅助指针,帮助完成小孩出圈
Josephus helper = first;
// helper指针指向current指针前一个位置
while (helper->Next != current)
{
helper = helper->Next;
}
// 开始报数,让current和helper指针同时移动number-1次,然后出圈,直到圈中只有一个小孩
while (current->Next != current)
{
// 让current和helper指针同时移动number-1次
for (int i = 0; i < number - 1; i++)
{
current = current->Next;
helper = helper->Next;
}
// 此时,current指针指向的就是要出圈的小孩
printf("小孩%d出圈\n", current->Data);
s = current;
current = current->Next;
helper->Next = current;
free(s);
}
printf("最后一个小孩是%d\n", current->Data);
}
打印生成的约瑟夫环:
/**
* @brief 打印约瑟夫环
*
* @param first 约瑟夫环的开始节点
*/
void PrintJosephus(Josephus first)
{
Josephus current = first;
if (current == NULL)
{
return;
}
while (1)
{
printf("%d ", current->Data);
if (current->Next == first)
{
break;
}
current = current->Next;
}
printf("\n");
}
main() 函数:
int main(void)
{
Josephus first = 0, current = 0, helper = 0;
int count = 0, start = 0, number = 0;
printf("请输入小孩个数:");
scanf("%d", &count);
printf("请输入从第几个小孩开始报数:");
scanf("%d", &start);
printf("请输入报数间隔:");
scanf("%d", &number);
first = GenerateJosephus(count);
printf("生成的约瑟夫环如下:\n");
PrintJosephus(first);
GetJosephusQuene(first, count, start, number);
return 0;
}