接着上一篇写线性表的插入删除操作的文章,试着实现了约瑟夫环的应用。
约瑟夫环问题:
有n个小朋友,围绕一圈循环报数,报到m的小朋友出列,剩余人继续循环报数,直到所有人都出列。
分析:这个问题用线性表来分析的话,怎么找到要出列的小朋友是最关键的问题。
举例来说,一共有8个人,循环报数到4的人出列,则情况如下所示:
线性表下标:0 1 2 3 4 5 6 7
小朋友编号:1 2 3 4 5 6 7 8
第一次循环,下标为3 的小朋友要出列,随后其他小朋友前移,剩余7个小朋友;
线性表下标:0 1 2 3 4 5 6 7
小朋友编号:1 2 3 5 6 7 8
第二次循环,下标为6的小朋友出列,剩余6个小朋友;
线性表下标:0 1 2 3 4 5 6 7
小朋友编号:1 2 3 5 6 7
第三次循环:下标为3的小朋友出列,前移后剩余5个小朋友;
……
依次进行,寻找规律,可以发现,出列的下标 t 满足一个公式:t=(t+m-1)%n;t初始赋值为0
如第一次,t=(0+4-1)%8=3,符合;
第二次,t=(3+4-1)%7=6;
……
编程实现:
void Josephus(CSqlist L, int nIndex, int m)
{
L.n = nIndex;
int t = 0;//t 是用来实现出列的参数,公式t=(t+m-1)%n
//给线性表赋初值
for (int i = 0; i < nIndex; i++)
{
L.pelem[i] = i + 1;
}
//开始报数出列
while (L.n > 0)
{
t = (t + m - 1) % L.n;
cout << L.pelem[t] << " ";
//找到要出列的,类似删除算法,将要出列的后面向前移动
for (int j = t+1; j < L.n; j++)
{
L.pelem[j - 1] = L.pelem[j];
}
L.n--;//线性表数量减一
}
}
在测试程序中需要先新建一个空白表,再调用约瑟夫环的函数,如下:
int main()
{
CSqlist cL;
if (Init_List(cL))
cout << "建立空白线性表成功!" << endl;
Josephus(cL, 8, 4);
return 0;
}
附:上一篇文章中的线性表定义和新建空白表函数:
typedef struct
{
int* pelem; //线性表基址
int n; //当前线性表元素个数
int nListsize; //线性表的存储容量
}CSqlist;
//新建空白表
bool Init_List(CSqlist &L)
{
L.pelem = (int*)malloc(INIT_LIST_SIZE * sizeof(int));//分配地址空间
if (!L.pelem) //存储分配失败
{
cout << "地址分配失败!" << endl;
exit(OVERFLOW);
}
else
{
L.n = 0; //初始线性表长度为0
L.nListsize = INIT_LIST_SIZE; //初始线性表的容量为100
return true;
}
}
【后记】
加油加油加油