实验A—2 约瑟夫环问题

内容:顺序表实现约瑟夫环

约瑟夫环是一个数学的应用问题:已知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。



评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值