内容:顺序表实现约瑟夫环
约瑟夫环是一个数学的应用问题:已知n个人(以编号1,2,3...n分别表示)围坐在一张圆桌周围。从编号为k的人开始报数,数到m的那个人出列;他的下一个人又从1开始报数,数到m的那个人又出列;依此规律重复下去,直到圆桌周围的人全部出列。
操作:
从第k个人开始报数到m然后归1又报数到m,这样的说明很难用计算机语言表达出来,但若是从1开始报数到m然后归1又报数到m那就很简单了。
故第一步要做的是把前k个人放到第n个人的后面,如下
原表:1, 2, 3, 4, 5, 6, 7,……k-1, k, k+1,……n-1, n;
改后: k, k+1,……n-1, n, 1, 2, 3, 4, 5, 6, 7,……k-1;
第二步报数没什么问题,问题在顺序表中如何让报数到最后一个时下一个从第一个开始。这里引入一个计数变量,从1开始与遍历报数同步,到m时该变量归0,删除此时表中的数。
第三步,在第二步的基础上不断循环,直到赢家出现。
以下为代码实现:
头文件Joseph.h:
#pragma once
const int Max = 1000;
class JP {
private:
int length; //n
int count; //m
int J[Max];
int start; //k
public:
JP() { length = 0; start = 0; count = 0; } //建立0表
int Delete(int i); //删除操作,用于模拟算法抽出成员
void act1(); //动作1:初始化各值,带引导
void act2(); //动作2:换序操作
void act3(); //动作3:求出结果
};
类函数实现文件joseph.cpp:
#include<iostream>
#include"Joseph.h"
using namespace std;
int JP::Delete(int i) {
if (length == 0)throw"overflow";
if (i<1 || i>length)throw"location";
int x = J[i - 1];
for (int j = i; j < length; j++)
J[j - 1] = J[j];
length--;
return x;
}
void JP::act1() {
cout << "Input the first one (input > 0):";
cin >> start;
cout << "Input the counting number:";
cin >> count;
cout << "Input the overall number of people(input < 1000):";
cin >> length;
if (length < start)throw"error";
for (int i = 0; i < length; i++)
{
J[i] = i + 1;
}
}
void JP::act2() {
if (start<1 || start>length)throw"overflow";
else
{
int temp; //临时数据
for (int i = 1; i < start; i++) //重排循环次数
{
temp = J[0];
for (int i = 0; i < length; i++) //表中数据移动
{ J[i] = J[i + 1]; }
J[length - 1] = temp;
}
}
}
void JP::act3() {
int cou = 0;
while (length != 1) //胜者唯一循环条件
{
for (int i = 0; ; i++)
{
if (i == length)i = 0; //表尾重置i
cou++;
if (cou == count)
{
Delete(i + 1);
start = i + 1; //从删除的后一位重新开始数数
if (!(start > length))
act2();
cou = 0;
break; //跳出for循环
}
}
}
cout << "Winner number:" << J[0] << endl;
}
实现代码cpp:
#include"Joseph.h"
#include<iostream>
using std::cout;
using std::endl;
void main() {
JP s;
s.act1();
s.act2();
s.act3();
system("pause");
}
程序运行图之一:
经大数据测试,程序运行结果正确。
总结:
约瑟夫环在自然语言中并不难,难点在于转化成计算机语言,而且在转化过程中思路必须要很清晰,因为每一步都是有所关联的。(码字的时候写注释是个好习惯)。
一次编译通过,代码和算法都还可以优化,但是我比较懒。
有人问我为什么不用递归,递归算法简单。
首先,模拟算法比递归算法更直观,更容易理解,递归算法是要经过手动推理归纳,然后把结论引入到算法中,从而达到优化算法的目的。我个人认为在实践中应该使用递归,但在练习时还是用模拟算法更好。
其二,我在完成该代码时候还没有把递归公式推出来。。。。。。(重点)
第三,用递归的话根本不需要顺序表。
最后,给出公式Result= 【Result(n)=(Result(n-1)+m)%n】+k 其中n>1。