【C++编程】约瑟夫生者死者游戏

61 阅读6分钟

开启掘金成长之旅!这是我参与「掘金日新计划 · 12 月更文挑战」的第28天,点击查看活动详情.

生死游戏

  • 目标:①、掌握线性表的表示和实现 ②、学会定义抽象数据类型 ③、学会分析问题,设计适当的解决方案 ④、深入掌握栈和队列应用的算法设计。
  • **内容:**古代某法官要判决n个犯人的死刑,他有一条荒唐的法律,将犯人站成一个圆圈,从第s个人开始数起,每数到第d个犯人,就来出来处决,然后再从下一个开始数d个,数到的人再处决,……,直到剩下最后一个犯人予以赦免。

程序流程图: 程序流程图 **

  • 问题概述: ----采用顺序存储和链式存储分别实现线性表类。①、线性表的操作至少应包含:判断是否为空;返回线性表长度;返回指定序号的对象;设置指定序号对象的值,并返回原对象的值;在指定位置上插入对象;追加一个对象;删除指定位置上的对象,并返回被删除的对象;清空线性表。②、若使用链式存储的线性表类,其单链表结点类的构造方法应有:无参构造方法、有参数构造方法和两参数构造方法。③、约瑟夫生者死者游戏的程序实现,给出当犯人个数n、计数起始位置数s和计数间隔数d不同时的测试结果。

**

  • 源程序及系统文件使用说明

**

#include "stdafx.h"
#include <stdlib.h>
#include <iostream>
#define MaxSize 50
using namespace std;
typedef int ElemType;
typedef struct
{
	ElemType data[MaxSize];
	int length;
}
SqList; //顺序表类型
typedef struct LNode
{
	ElemType data;
	struct LNode * next;
}LinkNode;//单链表类型
void InitList(SqList *&L) //初始化线性表
{
	L=(SqList *)malloc(sizeof(SqList));
	L->length=0;
}
void DestroyList(SqList *&L) //销毁线性表
{
	free(L);
}
bool ListEmpty(SqList *L) //判断线性表是否为空表
{
	return(L->length==0);
}
int ListLength(SqList *L) //求线性长度
{
	return(L->length);
}
void DispList(SqList *L)//输出线性表
{
	for(int i=0;i<L->length;i++)
		cout<<L->data[i]<<"  ";	
	cout<<endl;
}
bool GetElem(SqList *L,int i,ElemType &e) //求线性表中某个数据元素值
{
	if(i<1 || i>L->length)
		return false;
	e=L->data[i-1];
	return true;
}
int LocateElem(SqList *L,ElemType e) //按元素值查找
{
	int i=0;
	while(i<L->length&&L->data[i]!=e)
		i++;
	if(i>=L->length)
		return 0;
	else
		 return i+1;
}
bool ListChange(SqList *&L,int i,ElemType e1,ElemType &e2) //修改数据元素
{
	if(i<1 || i>L->length)
		return false;
	e2=L->data[i-1];
	L->data[i-1]=e1;
	return true;
}
bool ListInsert(SqList *&L,int i,ElemType e) //插入数据元素
{
	int j;
	if(i<1||i>L->length+1)
		return false;
	i--;
	for(j=L->length;j>i;j--)
		L->data[j]=L->data[j-1];
	L->data[i]=e;
	L->length++;
	return true;
}
bool ListDelete(SqList *&L,int i,ElemType &e)  //删除数据元素
{
	int j;
	if(i<1 || i>L->length)
		return false;
	i--;
	e=L->data[i];
	for(j=i;j<L->length-1;j++)
		L->data[j]=L->data[j+1];
	L->length--;
	return true;
}
void ClearList(SqList*L) //清空线性表
{
L->length=0;  //将线性表的长度置为0
}
void YueSeFu(SqList *&L,int n,int s,int d) //顺序表实现约瑟夫
{   
	int i;
	int x;
	/*
	SqList *L;
	InitList(L);
	for(i=1;i<=n;i++)
	{   
		ListInsert(L,i,i);	
	}//创建线性表
	*/
	cout<<"犯人最开始的排序为:"<<endl;
    DispList(L);
	if(ListEmpty(L)==false)
	{while(ListLength(L)>1)
    {
		s=((s-1)-1+d+ListLength(L))%ListLength(L)+1;//如果从0起始换成1起始的话一个麻烦点的方法把定义域从[1,a]平移到[0,a-1]上就行了。
		if(ListDelete(L,s,x))
		cout<<" 序号为 "<<x<<" 的犯人被处决。"<<endl;
	}
	GetElem(L,1,x);//获取最后被释放的犯人序号
	cout<<" 序号为 "<<x<<" 的犯人被释放。"<<endl;
	}
	DestroyList(L);//销毁线性表
}
void InitList1(LinkNode * &L)//初始化线性表
{
	L=(LinkNode *)malloc(sizeof(LinkNode));
	L->next=NULL;
}
bool ClearList1(LinkNode *&L) //不删除L头结点 
 { //初始条件:线性表L已存在。操作结果:将L重置为空表 
   LinkNode * p, * q;
   p=L->next; // p指向第一个结点 //
   while(p) //没到表尾 
   {
     q=p->next;
     free(p);
     p=q;
   }
   L->next=NULL; /* 头结点指针域为空 */
   return true;
 }
void DestoryList1(LinkNode * &L)//销毁线性表
{
	LinkNode * pre=L,*p=L->next;
	while(p!=NULL)
	{
		free(pre);
		pre=p;
		p=pre->next;
	}
	free(pre);
}
bool ListEmpty1(LinkNode * L)//判断线性表是否为空表
{
	return(L->next==NULL);
}
int ListLength1(LinkNode * L)//求线性表的长度
{
	int n=0;
	LinkNode *p=L;
	while (p->next!=NULL)
	{
		n++;
		p=p->next;
	}
	return (n);
}
void DispList1(LinkNode *L)//输出线性表
{
	LinkNode *p=L->next;
	while(p!=NULL)
	{
		cout<<p->data<<"  ";
		p=p->next;
	}
	cout<<endl;
}
bool GetElem1(LinkNode *L,int i,ElemType &e)//求线性表的某个数据元素的值
{
	int j=0;
	LinkNode *p=L;
	if(i<=0)
		return false;
	while(j<i && p!=NULL)
	{
		j++;
		p=p->next;
	}
	if(p==NULL)
		return false;
	else
	{
		e=p->data;
		return true;
	}
}
bool ListChange1(LinkNode *L,int i,ElemType e1,ElemType &e2){//修改元素值
	int j=0;
	LinkNode *p=L;
	if(i<=0)
		return false;
	while(j<i && p!=NULL)
	{
		j++;
		p=p->next;
	}
	if(p==NULL)
		return false;
	else
	{
		e2=p->data;
		p->data=e1;
		return true;
	}
}
int LocateElem1(LinkNode *L,ElemType e)//按元素值查找
{
	int i=1;
	LinkNode *p=L->next;
	while(p!=NULL && p->data!=e)
	{
		p=p->next;
		i++;
	}
	if(p==NULL)
		return 0;
	else
		return (i);
}
bool ListInsert1(LinkNode * &L,int i,ElemType e)//插入数据元素
{
	int j=0;
	LinkNode * p=L,* s;
	if(i<=0)
		return false;
	while(j<i-1 && p!=NULL)
	{
		j++;
		p=p->next;
	}
	if(p==NULL)
		return false;
	else
	{
		s=(LinkNode *)malloc(sizeof(LinkNode));
		s->data=e;
		s->next=p->next;
		p->next=s;
		return true;
	}
}
bool ListDelete1(LinkNode *&L,int i,ElemType &e)//删除数据元素
{
	int j=0;
	LinkNode *p=L,*q;
	if(i<=0)
	return false;
	while(j<i-1 && p!=NULL)
	{
		j++;
		p=p->next;
	}
	if(p==NULL)
		return false;
	else
	{
		q=p->next;
		if(q==NULL)
			return false;
		e=q->data;
		p->next=q->next;
		free(q);
		return true;
	}
}
void Create_L(LinkNode *&L,int n)   //构造一个以L为头结点,长度为n的单链表,节点元素依次为1.2.3...n
{
	InitList1(L);
	for(int i=1;i<=n;i++)             //每循环依次增加一个结点,并为结点元素赋值
	{
		ListInsert1(L,i,i);
	}
	
}
void Create_L1(LinkNode * &L)   //改造为以L为头结点单循环链表,
{
	LinkNode * p,* q;
	p=L;
	while(p->next!=NULL)            
	{
		p=p->next;
	}
	q=L;
	L=L->next;
	p->next=L;
	free(q); //删除原先的头结点
	L=p;//让L对应第一个数据
}
void DispList2(LinkNode *L,int n)//输出单循环链表
{
	LinkNode *p=L->next;
	int i=0;
	while(i<n)
	{
		cout<<p->data<<"  ";
		p=p->next;
		i++;
	}
	cout<<endl;
}
void YueSeFu1(LinkNode * &L,int s,int d) //用单链表实现约瑟夫,即测试2
{
	LinkNode * p=L;int j=0;
	while(p&&j<s){p=p->next;j++;}   //找到开始报数的位置
	LinkNode * q;
	while(p->next!=p)
	{
		for(int i=1;i<=d-1;i++)
		{q=p;p=p->next;}
	cout<<" 序号为 "<<p->data<<" 的犯人被处决。"<<endl;    //输出被处决的序号
		q->next=p->next;             
		free(p);                      //删除结点,并释放被删除的结点空间              
		p=q->next;                   
	}
	cout<<" 序号为 "<<p->data<<" 的犯人被释放。"<<endl;   //输出最后一个犯人的序号
	free(p);
}
void Shunxucunchu() //顺序存储方式实现
{
	int Menu1;
	int a,b,c;
	SqList *L1;
	InitList(L1);
        do {
		cout << "************************************************************" << endl;
		cout << "***    1.判断是否为空                                    ***" << endl;
		cout << "***    2.返回线性表长度                                  ***" << endl;
		cout << "***    3.返回指定序号的对象                              ***" << endl;
		cout << "***    4.修改指定序号对象的值                            ***" << endl;
		cout << "***    5.在指定位置上插入对象                            ***" << endl;
		cout << "***    6.删除指定对象                                    ***" << endl;
		cout << "***    7.输出线性表                                      ***" << endl;
		cout << "***    8.清空线性表                                      ***" << endl;
         cout << "***    9.测试                                            ***" << endl;
		cout << "***    0.退出                                            ***" << endl;
		cout << "************************************************************" << endl;
		cout << "请输入您的选择:";
		cin >> Menu1;
		switch (Menu1)
		{
		case 1:
			system("cls");
			if(ListEmpty(L1))
				cout<<endl<<"此表为空!"<<endl<<endl;
			else
				cout<<endl<<"此表不为空!"<<endl<<endl;
			break;
		case 2:
			system("cls");
			cout<<endl<<"线性表的长度为:"<<ListLength(L1)<<endl<<endl;
			break;
		case 3:
			 system("cls");
			 cout<<"请输入指定的序号: ";
			 cin>>a;
			 if(GetElem(L1,a,b))//求线性表中某个数据元素值
			 cout<<endl<<"第"<<a<<"号的值为 "<<b<<endl<<endl;
			 else
				 cout<<endl<<"查无此值!"<<endl<<endl;
			break;
		case 4:
			system("cls");
			cout<<endl<<"请输入要修改的序号和修改的值: ";
			cin>>a>>b;
			if(ListChange(L1,a,b,c))
			cout<<endl<<"修改成功,修改前的值为 "<<c<<" ,修改后的值为 "<<b<<endl<<endl;
			else
				cout<<endl<<"修改失败!"<<endl<<endl;
			break;
		case 5:
			system("cls");
			cout<<endl<<"请输入要插入的序号和插入的值: ";
			cin>>a>>b;
			if(ListInsert(L1,a,b))
				cout<<endl<<"插入成功!"<<endl<<endl;
			else
			    cout<<endl<<"插入失败!"<<endl<<endl;
			
			break;
		case 6:
			system("cls");
			cout<<endl<<"请输入要删除的序号: ";
			cin>>a;
			if(ListDelete(L1,a,b))
			cout<<endl<<"删除成功! 删除的值为 "<<b<<endl<<endl;
			else
			    cout<<endl<<"删除失败!"<<endl<<endl;
			break;
		case 7:
			system("cls");
			cout<<endl<<"输出的线性表是:"<<endl;
			DispList(L1);
			cout<<endl;
			break;
		case 8:
			system("cls");
			ClearList(L1);
			cout<<endl<<"线性表已清空!"<<endl;
			break;
		case 9:
			system("cls");
			int n;             //定义犯人个数n
	        int s;            //定义计数起始位置s
	        int d;            //定义计数间隔数d
	        cout<<"请输入犯人个数n、计数起始位置数s和计数间隔数d:"<<endl;	
	        cin>>n>>s>>d;
	        YueSeFu(L1,n,s,d);   //用顺序表实现约瑟夫
			break;
		}
	} while (Menu1!=0);
}
void LianShiCuncChu()//链式存储实现 
{
			int Menu2;
	        int a,b,c;
	        LinkNode *L2;
	        InitList1(L2);  
			do {
		cout << "************************************************************" << endl;
		cout << "***    1.判断是否为空                                    ***" << endl;
		cout << "***    2.返回线性表长度                                  ***" << endl;
		cout << "***    3.返回指定序号的对象                              ***" << endl;
		cout << "***    4.修改指定序号对象的值                            ***" << endl;
		cout << "***    5.在指定位置上插入对象                            ***" << endl;
		cout << "***    6.删除指定对象                                    ***" << endl;
		cout << "***    7.输出线性表                                      ***" << endl;
		cout << "***    8.清空线性表                                      ***" << endl;
         cout << "***    9.测试                                            ***" << endl;
		cout << "***    0.退出                                            ***" << endl;
		cout << "************************************************************" << endl;
		cout << "请输入您的选择:";
		cin >> Menu2;
		switch (Menu2)
		{
		case 1:
			system("cls");
			if(ListEmpty1(L2))
				cout<<endl<<"此表为空!"<<endl<<endl;
			else
				cout<<endl<<"此表不为空!"<<endl<<endl;
			break;
		case 2:
			system("cls");
			 cout<<endl<<"线性表的长度为:"<<ListLength1(L2)<<endl<<endl;
			break;
		case 3:
			system("cls");
			 cout<<"请输入指定的序号: ";
			 cin>>a;
			 if(GetElem1(L2,a,b))//求线性表中某个数据元素值
			 cout<<endl<<"第"<<a<<"号的值为 "<<b<<endl<<endl;
			 else
				 cout<<endl<<"查无此值!"<<endl<<endl;
			break;
		case 4:
			system("cls");
			cout<<endl<<"请输入要修改的序号和修改的值: ";
			cin>>a>>b;
			if(ListChange1(L2,a,b,c))
			cout<<endl<<"修改成功,修改前的值为 "<<c<<" ,修改后的值为 "<<b<<endl<<endl;
			else
				cout<<endl<<"修改失败!"<<endl<<endl;
			break;
		case 5:
			system("cls");
			cout<<endl<<"请输入要插入的序号和插入的值: ";
			cin>>a>>b;
			if(ListInsert1(L2,a,b))
				cout<<endl<<"插入成功!"<<endl<<endl;
			else
			    cout<<endl<<"插入失败!"<<endl<<endl;			
			break;
		case 6:
			system("cls");
			cout<<endl<<"请输入要删除的序号: ";
			cin>>a;
			if(ListDelete1(L2,a,b))
			cout<<endl<<"删除成功! 删除的值为 "<<b<<endl<<endl;
			else
			    cout<<endl<<"删除失败!"<<endl<<endl;
			break;
		case 7:
			system("cls");
			cout<<endl<<"输出的线性表是:"<<endl;
			DispList1(L2);
			cout<<endl;
			break;
		case 8:
			system("cls");
			ClearList1(L2);
			cout<<endl<<"线性表已清空!"<<endl;
			break;
		case 9:
		    system("cls");
		    int n;             //定义犯人个数n
	        int s;            //定义计数起始位置s
	        int d;            //定义计数间隔数d
	        cout<<"请输入犯人个数n、计数起始位置数s和计数间隔数d:"<<endl;	
	        cin>>n>>s>>d;
	        LinkNode *L;
	        Create_L(L,n);    //创建循环单链表
	        cout<<"犯人最开始的排序为:"<<endl;
	        DispList1(L);   //输出线性表
	        Create_L1(L);//改造为单循环链表
	        YueSeFu1(L,s,d);  //用循环单链表实现约瑟夫	
			break;  
		}
	} while (Menu2!=0);
}
	int _tmain(int argc, _TCHAR* argv[])
{
	int Menu;
	do {
		cout << "************************************************************" << endl;
		cout << "******************欢迎来到约瑟夫生死游戏********************" << endl;
		cout << "***  1.使用顺序存储方法玩                                ***" << endl;
		cout << "***  2.使用链式存储方法玩                                ***" << endl;
		cout << "***  0.退出                                              ***" << endl;
		cout << "************************************************************" << endl;
		cout << "请输入您的选择:";
		cin >> Menu;
		switch (Menu)
		{
		case 1:
			system("cls");
			Shunxucunchu();//用顺序存储实现游戏
			break;
		case 2:
			system("cls");
			LianShiCuncChu();//用链式存储实现游戏
			break;
			}			
	} while (Menu!=0);
	return 0;
}

  • 开发环境与开发工具

**

  • 开发环境:windows

  • 开发工具:Microsoft Visual Studio 2010 选择依据:visual studio 2010是一个集成开发环境,利用它可以用C++、C#、VB、Java编程。

  • 1、民主化的应用程序生命周期管理,坚持打造一个功能平等、共同分担的平台以用于组织内的应用程序生命周期管理过程。

  • 2、符合新技术发展趋势;为开发者提供合适的工具和框架,以支持软件开发中最新的架构,开发和部署;

  • 3、是新一代平台首选:微软投资于市场领先的操作系统,工具软件和服务器平台,为用户创造高效的解决方案。

  • 4、高效的开发环境:Microsoft Visual Studio

    2010采用拖拽式便能完成软件的开发。简单的操作便可以实现界面的生成,同时拖拽的界面,也有相应的代码来实现功能。可以快速实现相应的用户需求功能。