数据结构习题集上有有一个问题,名为约瑟夫环:
编号为1,2,3,···,n的n个人按顺时针方向围坐一圈,每人持有一个密码(正整数)。一开始任选一个正整数作为报数的上限值m,从第一个人开始按顺时针方向自1开始顺序报数,报到m时停止报数。报m的人出列,将他的密码作为新的m值,从他的顺时针方向上的下一个人开始重新从1报数,如此下去,直至所有的人全部出列为止。试设计一个程序求出出列顺序。
一看就知道是递归问题,而且是我没有实现过的循环链表。搞了几个小时,终乃成。
/*
约瑟夫问题:编号为1~n的n个人顺时针围圈,每人拿一密码。先选初值m,从第一个报数知道报m,
此人出列,以此人的密码当做新的m报数,直到n个人全部出列。求出列顺序。
*/
#include <iostream>
using namespace std;
typedef struct Joseph
{
int num; //人的编号
int password; //所携密码
Joseph *next;
}CircularLink, *CLL;
void createCL(CLL& L, int n);
CLL printOrder(CLL L, int m);
CLL deleteCL(CLL L, int i);
CLL getElem(CLL L, int i);
int CLLength(const CLL L);
int main()
{
int n,m;
CLL L;
cout << "The number of people: ";cin >> n;
cout << "The initial-value: ";cin >> m;
createCL(L,n);
cout << "Result:("; printOrder(L,m);cout << ")\n";
return 0;
}
void createCL(CLL& L, int n)
{
int i;
CLL p, q;
L = new CircularLink;
cout << "Enter person 1 's password: "; cin >> L->password;
L->num = 1;
L->next = L;
p = q = L;
for(i = 1; i< n; i++)
{
p = new CircularLink;
cout << "Enter person " << i + 1<< " 's password: ";cin >> p->password;
p->num = i + 1;
q->next = p;
q = p;
}
p->next = L;
}
int CLLength(const CLL L)
{
CLL p;
int length = 1;
for(p = L; p->next != L; p = p->next)
length++;
return length;
}
//获得某一轮中出列的编号
CLL getElem(CLL L, int i)
{
int j;
CLL p;
for(p = L, j = 1; j< i; j++, p = p->next);
return p;
}
//获得某一轮中出列编号的前一个
CLL deleteCL(CLL from, int i)
{
int j;
CLL p, q;
i = (i == 1)?( i + CLLength(from) ):i;
for(p = from, j = 1; j< i - 1; j++, p = p->next);
q = p->next;
p->next = q->next;
delete q;
return p->next;
}
CLL printOrder(CLL L, int m)
{
CLL p, output;
int tempPassword;
output = getElem(L,m);
//必须使用临时变量储存out->password,
//否则下面进行删除语句是会将output释放,不能应用于递归
tempPassword = output->password;
cout << output->num << ",";
p = deleteCL(L,m);
if(CLLength(p) == 1)
{
cout << p->num;
return NULL;
}
else
return printOrder(p,tempPassword);
}
最后那个注释说的内容,我可是花了一个多小时才发现。令我郁闷的是,两个相隔十万八千里的函数居然是会相互影响,不得不佩服动态储存之神奇啊。 编完查了下资料,这个程序是复杂了,如果想简单是可以的。不过我没这个时间,何况解决此问题的初衷是实现一次循环链表。