约瑟夫(Josephu)问题:已知n个人(以编号1,2,3,…,代表)围坐成一圈。现在从编号为k的人开始报数,数到m的人出列;他的下一个人又从1开始报数,数到m的人又出列;依此重复下去,直到所有人全部出列。例如:当n=8,m=4,k=3 时,出列顺序为 6,2,7,4,3,5,1,8。
#include <stdio.h>
#include <stdlib.h>
#include <iostream>
using namespace std;
typedef struct node
{
int data;
struct node *next;
}Node,*Link;
//创建一个带有头节点的循环链表,控制从 k 开始计数
Link create(int n,int k)
{
Link head = NULL,p = NULL, pr = NULL; //pr是一个新节点 p前一个节点
int i;
for(i = 1;i <= n;i++)
{
p = (Link)malloc(sizeof(Node));
if(p == NULL)
{
cout << " 动态内存分配失败 ";
return NULL;
}
p->data = i;
if(head == NULL) //如果头节点指针为空 ,直接释放
{
head = p;
}
else
{
pr->next = p;
}
pr = p;
}
p->next = head; //循环结束,回到头节点,形成一个完整的循环链表
p = head;
//从第一个人开始计数
for(i = 1;i < k;i++)
{
pr = p;
p = p->next; //k个跳出循环
}
return p; //返回指定的第一个人
}
//传入链表并定义数字
void Josephus(Link p,int m)
{
Link pr = NULL;
int i;
cout << "出列顺序:\n";
while(p->next != p) //循环链表的首尾不相连
{
for(i = 1;i < m;i++)
{
pr = p;
p = p->next;
} //循环结束,出列
pr->next = p->next;
cout << p->data <<"\n"; //输出出列人顺序
free(p); // 释放
p = pr->next; //重新指向 新开始节点
}
cout << p->data;
return;
}
int main()
{
Link p = NULL;
int n,k,m;
cout << "总人数:";cin >> n;//输入总人数
if(n<=0){
cout << "请输入正确人数,总人数应为大于0的正整数!\n";
}
else{
cout << "出列数:";cin >> m; //出列数
cout << "开始编号:";cin>> k; //开始计数
p = create(n,k);
Josephus(p,m);
}
return 0;
}
验证:
输入:8,4,3
输出顺序: 6,2,7,4,3,5,1,8