您的位置:首页 > 编程语言 > C语言/C++

C++循环链表实现约瑟夫问题

2013-09-24 16:17 465 查看
约瑟夫问题(有时也称为约瑟夫斯置换,是一个出现在计算机科学数学中的问题。在计算机编程的算法中,类似问题又称为约瑟夫环。又称“丢手绢问题”)

据说著名犹太历史学家 Josephus有过以下的故事:在罗马人占领乔塔帕特后,39 个犹太人与Josephus及他的朋友躲到一个洞中,39个犹太人决定宁愿死也不要被敌人抓到,于是决定了一个自杀方式,41个人排成一个圆圈,由第1个人开始报数,每报数到第3人该人就必须自杀,然后再由下一个重新报数,直到所有人都自杀身亡为止。然而Josephus 和他的朋友并不想遵从。首先从一个人开始,越过k-2个人(因为第一个人已经被越过),并杀掉第k个人。接着,再越过k-1个人,并杀掉第k个人。这个过程沿着圆圈一直进行,直到最终只剩下一个人留下,这个人就可以继续活着。问题是,给定了和,一开始要站在什么地方才能避免被处决?Josephus要他的朋友先假装遵从,他将朋友与自己安排在第16个与第31个位置,于是逃过了这场死亡游戏。
我写了一个循环链表来实现约瑟夫问题,其实没必要这么复杂,只需要用一个vector或者是数组即可,以下是我写的代码:

1.循环链表头文件:

#ifndef __CircleList_H__
#define __CircleList_H__

#include <iomanip>
#include <iostream>
#include <ctime>
#include <cassert>
using namespace std;

#define LEN 20
#define RANLEN 100
typedef int ElemType;

typedef struct Lnode
{
ElemType data;  //值域
Lnode *next;    //next指针
}Lnode;

class CircleList
{
private:
Lnode *head;//头指针
Lnode *curr;//当前指针
int count;  //循环链表中元素个数
public:
CircleList();//构造函数,只有一个头结点
~CircleList(){delete head;}//析构函数
Lnode *CreateCircleList(const int& n,const int& mark);//创建循环链表,n表示的是循环链表中的元素个数,mark为1的时候表示升序,-1的时候表示降序,0的时候表示随机
void TraverseCircleList();  //遍历整个循环链表
//	void InsertNode(const ElemType& item,int pos);  //向循环链表中指定位置插入节点
bool IsEmpty(){ return head->next == head; } //判断链表是否为空
//	Lnode *Index(int pos);  //返回指定位置的Lnode指针
ElemType GetElem(int pos);  //返回指定位置的data值
Lnode *Next();  //返回下一个节点的指针
Lnode *Reset(int pos);  //将curr指针指向指定的位置并返回
ElemType DeleteNext();  //删除curr指针指向的下一个节点
Lnode* GetCurrNode(); //返回curr指针
ElemType DeletePosNode(int pos);  //删除指定位置的节点

};
#endif


2.循环链表.cpp文件

#include "stdafx.h"
#include "CircleList.h"

CircleList::CircleList()
{
head = new Lnode;
head->next = head;
curr = NULL;
count = 0;
}

Lnode *CircleList::CreateCircleList(const int& n,const int& mark)
{
int i,j,min;
ElemType temp;
ElemType a[LEN];
Lnode *tempNode = NULL;
srand((unsigned)time(NULL));//用于产生随机数的种子
count = n;
for(i = 0; i < LEN; i++ )
{
a[i] = rand()%RANLEN;  //产生100以内的随机数,保存在a数组中,a数组的长度为LEN=20个,也即n不能超过20
cout<<a[i]<<setw(3);
if( i == LEN -1 )
cout<<endl;
}
//选择排序
for( i = 0; i < LEN-1; i++)
{
min = i;
for( j = i+1; j < LEN;j++ )
{
if( a[min] > a[j] )
min = j;
}
if( min != i )
{
temp = a[min];
a[min] = a[i];
a[i] = temp;
}
}
for( i = 0; i < LEN; i++ )
{
cout<<a[i]<<setw(3);
if( i == LEN - 1)
cout<<endl;
}
head->next = curr = tempNode = new Lnode;
switch(mark)
{
case -1://表示降序排列
curr->data = a[0];
curr->next = head;
for(i = 1;i < n; i++ )
{
curr = new Lnode;
curr->data = a[i];
tempNode->next = curr;
tempNode = tempNode->next;
curr->next = head;
}
break;
case 0://表示随机排列
curr->data = rand()%RANLEN;
curr->next = head;
for( i = 1; i < n; ++i )
{
curr = new Lnode;
curr->data = rand()%RANLEN;
tempNode->next = curr;
tempNode = tempNode->next;
curr->next = head;
}
break;
case 1://表示升序排列
curr->data = a[LEN-1];
curr->next = head;
for( i = 2; i <= n; ++i )
{
curr = new Lnode;
curr->data = a[LEN-i];
tempNode->next = curr;
tempNode = tempNode->next;
curr->next = head;
}
break;
default:cerr<<"mark error!"<<endl;
}
return head;
}

void CircleList::TraverseCircleList()
{
Lnode *search = head;
cout<<"遍历链表结果:"<<endl;
while( search->next != head )
{
search = search->next;
cout<<search->data<<setw(3);
}
}

ElemType CircleList::GetElem(int pos)
{
int i = 0;
Lnode *search = head;
for( i = 0; i < pos; i++ )
{
search = search->next;
}
return search->data;
}

ElemType CircleList::DeletePosNode(int pos)
{
assert( pos > 0 );
int i = 0;
ElemType data;
Lnode *search = head->next;
curr = head;
for( i = 1; i < pos; i++ )
{
curr = curr->next;
search = search->next;
}
curr->next = search->next;
search->next = NULL;
data = search->data;
delete search;
count--;
return data;
}

Lnode *CircleList::Next()
{
if( curr->next == head )
curr = curr->next->next;
else
curr = curr->next;
return curr;
}

Lnode *CircleList::Reset(int pos)
{
int i;
curr = head;
for( i = 0; i < pos; i++ )
{
curr = curr->next;
}
return curr;
}

ElemType CircleList::DeleteNext()
{
ElemType data;
Lnode *search = NULL;
if( curr->next != head )
{
search = curr->next;
curr->next = curr->next->next;
data = search->data;
search->next = NULL;
delete search;
}
else
{
search = curr->next->next;
curr->next->next = search->next;
data = search->data;
search->next = NULL;
delete search;
}
return data;
}

Lnode* CircleList::GetCurrNode()
{
return curr;
}


3.约瑟夫函数以及主函数的.cpp文件

// CircleListAndJosephProblem.cpp : 定义控制台应用程序的入口点。
//

#include "stdafx.h"
#include "CircleList.h"

//约瑟夫问题,n表示人数,m表示数多少个数,x表示第一次从哪个人开始数数
void JosephProblem(int n,int m,int x)
{
int i,j;
CircleList cl;
cl.CreateCircleList(n,1);
cout<<"未报数之前人的编号顺序:"<<endl;
cl.TraverseCircleList();
cout<<endl;
cl.Reset(x-1);
for( i = 0; i < n-1; i++ )
{
for( j = 0; j < m-1; j++ )
cl.Next();
cout<<cl.DeleteNext()<<"元素被删除!"<<endl;
}
cout<<"最后剩下的元素为:"<<cl.GetCurrNode()->data<<endl;
}

int _tmain(int argc, _TCHAR* argv[])
{
/*
CircleList cl;
cl.CreateCircleList(10,1);
cl.TraverseCircleList();
cl.DeletePosNode(2);
cout<<"删除后的链表为:"<<endl;
cl.TraverseCircleList();
*/
JosephProblem(10,3,1);
return 0;
}


如果您那么细心的看完代码后,发现有什么问题,希望您能够给我留言提出,只有不断发现不足,才能一直前进!!!
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息