C++面向对象方法求解约瑟夫环问题
来源:互联网 发布:linux下安装php环境 编辑:程序博客网 时间:2024/06/10 05:48
约瑟夫问题有很多种解法及其变种,这里的约瑟夫环问题是这样的:
约瑟夫环(约瑟夫问题)是一个数学的应用问题:已知n个人(以编号1,2,3...n分别表示)围坐在一张圆桌周围。从编号为k的人开始报数,数到m的那个人出列;他的下一个人又从1开始报数,数到m的那个人又出列;依此规律重复下去,直到圆桌周围的人全部出列.
大多数的约瑟夫环问题解法是利用面向过程的方法编写的(其实我没有看过多少。这里我给出一个利用C++面向对象的编程思想编写的代码,用于解决上面的约瑟夫环问题。这里的核心算法也是动态链表。
首先阐述一下我的算法思想:
要将这个结点踢出局外,也就是将它上一个结点的指向下一个结点的指针指向要出局的结点的下一结点,同时为了保持这个环,还要设置要出局的结点的下一结点的指向上一结点的指针指向要出局的结点的上一结点。如图:
最后不要忘了删除那个不要的结点。对分配在堆上的对象,C++是要手动进行内存管理的。
上面是主要的思想,下面是算法的实现
ReNode StartAgain(_Josephus*)是一个主要的函数,大家应该也注意到了前面的返回类型ReNode到底是什么呢?下面我来和大家说说吧。
ReNode的定义如下:
ReNode StartAgain(_Josephus*)的函数定义如下:
最后我们来看看最后一个函数void Josephus::Action();它的作用是将每一轮要出局的人的编号保存在类的jose中,jose是一个[code=c]vectot<int>[/code],用于保存整个游戏的结果,并且开始新一轮的游戏,直到所有人都出局。
函数void Josephus::Action();的定义如下:
下面给出完整的实现代码:
在文件中josephus.h
约瑟夫环(约瑟夫问题)是一个数学的应用问题:已知n个人(以编号1,2,3...n分别表示)围坐在一张圆桌周围。从编号为k的人开始报数,数到m的那个人出列;他的下一个人又从1开始报数,数到m的那个人又出列;依此规律重复下去,直到圆桌周围的人全部出列.
大多数的约瑟夫环问题解法是利用面向过程的方法编写的(其实我没有看过多少。这里我给出一个利用C++面向对象的编程思想编写的代码,用于解决上面的约瑟夫环问题。这里的核心算法也是动态链表。
首先阐述一下我的算法思想:
每个参加游戏的人看做是一个链表中的一个结点,结点的内容为:
想像一下n个人围坐成一圈,手拉着手。这里的链表实现也是一样的,将n个结点首尾相连,形成一个环。像这样:
现在假设某一结点是表头,如:
要将这个结点踢出局外,也就是将它上一个结点的指向下一个结点的指针指向要出局的结点的下一结点,同时为了保持这个环,还要设置要出局的结点的下一结点的指向上一结点的指针指向要出局的结点的上一结点。如图:
最后不要忘了删除那个不要的结点。对分配在堆上的对象,C++是要手动进行内存管理的。
上面是主要的思想,下面是算法的实现
首先定义结点:
struct _Josephus{int data;//当前的数据点_Josephus* previous;//上一个结点_Josephus* next;//下一个结点};然后定义操作的类
//操作类class Josephus{public:Josephus() = delete;Josephus(int count, int number) :Count(count), Number(number){}~Josephus();void CreateLink();//创建整个链表,并保存表头在head里。整个链表将构成一个环void Action();//利用创建好的链表,并返回结果vector<int> jose;//保存的结果private:int Count;//参加游戏的人数int Number;//关键数字m_Josephus* head;//表头ReNode StartAgain(_Josephus*);//传入(新的)开始的结点,返回ReNode并且完成搭桥过程};void CreateLink();将用于创建这个链表,并将表头保存在Josephus类的数据成员head中。 函数定义如下:
void Josephus::CreateLink(){_Josephus* head=new _Josephus;//表头_Josephus* next;//下一个结点_Josephus* curr;//当前结点head->data = 1;curr = head;for (int i = 1; i < this->Count; i++){next = new _Josephus;curr->next = next;next->data = i + 1;next->previous = curr;curr = next;}//将这个链表构成一个环next->next = head;head->previous = next;this->head = head;}这个函数应该不难,大家先这样看看吧。
ReNode StartAgain(_Josephus*)是一个主要的函数,大家应该也注意到了前面的返回类型ReNode到底是什么呢?下面我来和大家说说吧。
ReNode的定义如下:
//下面是辅助类struct ReNode{int result;//当前轮的结果_Josephus* curr;//下一轮开始的结点位置};成员result保存的是要出局的那个人的编号,而curr是下一轮要开始的结点。有了这个辅助结构,算法会简单很多。
ReNode StartAgain(_Josephus*)的函数定义如下:
ReNode Josephus::StartAgain(_Josephus* head){ReNode node;int num=1;//用于循环计数,从1开始if (head->next == head)//如果当前结点的下一结点是其本身,则游戏结束——因为只有一个结点了{//设置ReNodenode.curr = NULL;//这里设置为空是为了退出Action的while循环node.result = head->data;}else{/*过程:1.进行计数2.得到ReNode3.设置当前轮游戏结果的上一结点的下一结点为当前轮游戏结果的下一结点和 当前结点的下一结点的上一结点为当前结点的上一结点——相当于将这个结点踢出局外,游戏人数将减少一个*///步骤1.进行计数while (num!=this->Number){head = head->next;num++;}//退出while时,head刚好是数到this->Number的那个结点//步骤2.得到ReNode//设置ReNodenode.curr = head->next;node.result = head->data;//步骤3.head->previous->next = head->next;head->next->previous = head->previous;////进行内存管理——释放游离的结点的内存delete head;}return node;}
最后我们来看看最后一个函数void Josephus::Action();它的作用是将每一轮要出局的人的编号保存在类的jose中,jose是一个[code=c]vectot<int>[/code],用于保存整个游戏的结果,并且开始新一轮的游戏,直到所有人都出局。
函数void Josephus::Action();的定义如下:
void Josephus::Action(){ReNode node;while (this->head!=NULL){node = StartAgain(this->head);//从head处开始游戏,并返回ReNodethis->jose.push_back(node.result);//得到每一轮的游戏结果this->head = node.curr;//下一轮开始的结点}}到此,整个算法的思想和主要的代码都列出来了。
下面给出完整的实现代码:
在文件中josephus.h
#pragma once#ifndef __JOSEHPUS__HH#define __JOSEHPUS__HH#include<vector>using std::vector;//真正的结点struct _Josephus{int data;//当前的数据点_Josephus* previous;//上一个结点_Josephus* next;//下一个结点};//下面是辅助类struct ReNode{int result;//当前轮的结果_Josephus* curr;//下一轮开始的结点位置};//操作类class Josephus{public:Josephus() = delete;Josephus(int count, int number) :Count(count), Number(number){}~Josephus();void CreateLink();//创建整个链表,并保存表头在head里。整个链表将构成一个环void Action();//利用创建好的链表,并返回结果vector<int> jose;//保存的结果private:int Count;int Number;_Josephus* head;//表头ReNode StartAgain(_Josephus*);//传入(新的)开始的结点,返回ReNode并且完成搭桥过程};#endif在文件josephus.cpp中
#include "Josephus.h"Josephus::~Josephus(){delete head;}void Josephus::CreateLink(){_Josephus* head=new _Josephus;//表头_Josephus* next;//下一个结点_Josephus* curr;//当前结点head->data = 1;curr = head;for (int i = 1; i < this->Count; i++){next = new _Josephus;curr->next = next;next->data = i + 1;next->previous = curr;curr = next;}//将这个链表构成一个环next->next = head;head->previous = next;this->head = head;}void Josephus::Action(){ReNode node;while (this->head!=NULL){node = StartAgain(this->head);//从head处开始游戏,并返回ReNodethis->jose.push_back(node.result);//得到每一轮的游戏结果this->head = node.curr;//下一轮开始的结点}}ReNode Josephus::StartAgain(_Josephus* head){ReNode node;int num=1;//用于循环计数,从1开始if (head->next == head)//如果当前结点的下一结点是其本身,则游戏结束——因为只有一个结点了{//设置ReNodenode.curr = NULL;//这里设置为空是为了退出Action的while循环node.result = head->data;}else{/*过程:1.进行计数2.得到ReNode3.设置当前轮游戏结果的上一结点的下一结点为当前轮游戏结果的下一结点和 当前结点的下一结点的上一结点为当前结点的上一结点——相当于将这个结点踢出局外,游戏人数将减少一个*///步骤1.进行计数while (num!=this->Number){head = head->next;num++;}//退出while时,head刚好是数到this->Number的那个结点//步骤2.得到ReNode//设置ReNodenode.curr = head->next;node.result = head->data;//步骤3.head->previous->next = head->next;head->next->previous = head->previous;////进行内存管理——释放游离的结点的内存delete head;}return node;}最后还有一个用于辅助的头文件,内容如下:
在NHelper.h中
#include<iostream>#ifndef __NAMESPACEHELPER__HH__#define __NAMESPACEHELPER__HH__#define NH__HH using std::cin;using std::cout;using std::endl;#endif
0 0
- C++面向对象方法求解约瑟夫环问题
- 约瑟夫问题求解(C++)
- 2种方法求解约瑟夫环问题
- 三种方法求解约瑟夫环问题
- 求解约瑟夫环问题
- 约瑟夫环问题求解
- C语言求解约瑟夫问题
- 约瑟夫环出圈问题三种求解方法
- 约瑟夫问题三种求解方法
- 约瑟夫问题的笨方法求解程序
- 求解约瑟夫问题两种方法
- 面向对象编程 约瑟夫问题简要分析
- 使用顺序表求解约瑟夫环问题
- 使用单链表求解约瑟夫环问题
- 使用循环双链表求解约瑟夫环问题
- 约瑟夫环问题求解--程序+详细注解
- 约瑟夫环问题求解(Java代码)
- 约瑟夫环问题的数学求解
- java设计模式之---工厂模式
- 南洋理工OJ——24 素数距离问题
- Python:在指定目录下查找满足条件的文件
- 自定义ViewGroup实现瀑布流效果
- iOS 使用levelDB储存本地数据
- C++面向对象方法求解约瑟夫环问题
- 数据库连接池
- ui.layout
- ui.ImageView及其子类
- Java多个线程之间处理共享数据的方式
- 算法导论:动态规划
- ZOJ Problem Set - 3811 Untrusted Patrol
- Java4Andriod 从零学起 ---learn12
- 黑马程序员---从头开始,回忆JAVA基础之集合(一)