实验一约瑟夫环问题

  • 格式:pdf
  • 大小:244.45 KB
  • 文档页数:12

实验四 约瑟夫环问题

一、问题描述 设有编号为1,2,…n的n(n>0)个人围成一个圈.每个人持有个密码m。从第1个人开始报数,报到m时停止报数,报m的人出圈,再从他的下个人起重新报数,报到m时停止报数,报m的出圈……如此下去,直到所有人全部出圈为止。当任意给定n和m后,设计算法求n个人出圈的次序。 二、基本要求 (1)建立模型,确定存储结构 (2)对任意n个人,密码为m,实现约瑟夫环问题 (3)出圈的顺序可以依次输出,也可以用一个数组存储 三、实验步骤

1.需求分析

本演示程序用VC++编写,生成一个循环链表,输入人数输入密码,在执行报数输出操作,输出报数序列;

① 输入的形式和输入值的范围:输入的总共报数人数以及报数密码,在所有输入中,输入数据都为正整数。

② 输出的形式:在输出报数顺序是输出报数顺序序号对应报数本身编号。输出完成后输出是否重新进行提示信息。

③ 程序所能达到的功能:任意输入的报数人数people,及出列密码num输出报数出列顺序编号。

④ 测试数据:

A. 输入报数人数:50,初始化循环链表;

B. 输入报数密码:3,输出报数出列序列

2.概要设计

1)为了实现上述程序功能,需要定义循环链表的抽象数据类型:

ADT LinkList { 数据对象:D={ai|ai∈IntegerSet,i=0,1,2,…,n,n≥0}

数据关系:R={|ai,ai+1 ∈D}

基本操作:

creatcirlink(int n)

操作结果:建立循环链表并进行初始化

report_num(cirlink &hand,int m,int max)

初始条件:循环链表hand已建立;

操作结果:报数输出相应的元素data;

Game()

初始条件:循环链表hand已建立;

操作结果:输入报数人people数及密码num

Menu()

操作结果:在屏幕上显示操作菜单

}

2)本程序包含4个函数:

① 主函数main()

②显示操作菜单函数menu()

③报数出列函数report_num ()

④ 输入人数和密码函数Game()

3.详细设计

设计实现约瑟夫环问题的存储结构。由于约瑟夫环问题本身具有循环性质,考虑采用循环链表,为了统一对表中任意结点的操作,循环链表不带头结点。将循环链表的结点定义为如下结构类型: struct Node { int data; //编号 Node * next; };

建立一个不带头结点的循环链表并由头指针hand指示。

2) 关于约瑟夫问题的基本操作

建立循环链表

status creatcirlink(int n) { {

hand=(struct node*)malloc(LEN);

hand->data=1;

rear=hand;

for(i=2;i<=n;i++)

{

p=(struct node*)malloc(LEN);

p->data=i;

rear->next=p;

rear=p;

}

rear->next=hand;

return(OK);

}

void report_num(cirlink &hand,int m,int max)

{ int j=0,count=1;

p=hand;

do{q=p;

p=p->next;

count++;

if(count%m==0)

{

j++;

printf("\n\t\t\tj=%2d\tno=%2d",j,p->data);

q->next=p->next;

free(p);

p=q->next;

count++;

}

}while(j!=max);

}

void Game()

{

do{

scanf("%d",&people);

scanf("%d",&num);

hand=creatcirlink(people);

report_num(hand,num,people);

} }

int menu()

{

printf("\t\t\t 1.开始报数\n");

printf("\t\t\t 2.退出报数\n");

do{

scanf("%d",&k);

}while(k<1||k>2);

return k;

}

void main()

{

int n;

n=menu();

switch(n)

{

case 1 : Game();break;

case 2 : exit(0);

}

}

4.程序源码

#include #include

#include

#define Null 0

#define LEN sizeof(cirlink)

typedef struct node /*定义结点结构*/

{

int data;

struct node *next;

}cirlink;

cirlink *t;

cirlink *creatcirlink(int n) /*初始化建立单向循环链表*/

{

cirlink *hand,*rear=Null,*p;

int i=0;

hand=(struct node*)malloc(LEN);/*建立循环链表的头结点*/

hand->data=1;

rear=hand; /*尾指针初值为head*/

for(i=2;i<=n;i++)

{

p=(struct node*)malloc(LEN); /*生成新的结点*/

p->data=i; /*新结点的数据域输入数据*/

rear->next=p; /*将新结点插入表尾*/

rear=p; /*将表尾指针rear指向新的表尾*/ }

rear->next=hand; /*将表尾结点的指针域指向链表头结点*/

return(hand);

}

void report_num(cirlink *hand,int m,int max)/*报数输出函数*/

{

cirlink *q,*p;

int j=0,count=1;/*计数器初始化为1*/

p=hand;

printf("\n\t\t\t报数输出顺序为:");

do{q=p;/*p结点给q*/

p=p->next;/*p指针后移指向下一个结点*/

count++;/*计数器加1*/

if(count%m==0)/*当输入的count个结点能被m整除时输出该结点*/

{

j++;/*统计输出结点数*/

printf("\n\t\t\t第%d个\tno=%2d",j,p->data);

q->next=p->next;/*q的后继指向p的后继结点*/

free(p);/*释放结点p*/

p=q->next;/*q的后继结点给p*/

count++; /*计数器自加*/

}

}while(j!=max);/*当输出结点数大于等于结点总数时跳出循环*/ printf("\n");

}

void Game() /*输入数据函数*/

{

char c;

cirlink *hand;

int people=0,num=0;

do{

printf("\n\t\t\t请输入人数:");

scanf("%d",&people);

printf("\n\t\t\t请输入密码:");

scanf("%d",&num);

hand=creatcirlink(people);/*建立有people个结点的单循环链表并初始化*/

report_num(hand,num,people);/*报数输出出列顺序*/

printf("\t\t约瑟夫环问题报数结束是否重新开始?(Y/N)");

cin>>c; /*输入是否重新开始信息*/

if((c=='y')||(c=='n')) /*当输入为小写字母是转化为大写字母*/

c=c-32;

delete(t);/*释放t所指空间*/

}while(c=='Y');

}

int menu() /*菜单显示函数*/

{

int k;

printf("\t\t\t约瑟夫环问题功能模块:\n\n");

printf("\t\t\t 1.开始报数\n");

printf("\t\t\t 2.退出报数\n");

printf("\t\t ****************************\n");

do{

printf("\n\t\t\t请输入你的选择:");

scanf("%d",&k);

}while(k<1||k>2);/*当输入的选择小于1或大于2重新输入*/

return k;

}

void main() /*主函数*/

{

int n;

printf("\t\t 欢迎进入约瑟夫环问题报数系统\n");

printf("\t\t ****************************\n");

n=menu();

switch(n)

{

case 1 : Game();break;

case 2 : exit(0);

}