约瑟夫问题实验报告

  • 格式:doc
  • 大小:306.08 KB
  • 文档页数:7

X X X X X X X X

实验报告

课程: 数据结构 班级: 姓名: 学号:

成绩: 指导教师: 实验日期: 2012.3

实验密级: 预习程度: 实验时间:

仪器组次: 必修/选修: 必修 实验序号: 01

实验名称: 线性结构的应用——约瑟夫问题

实验目的与要求:

编程实现约瑟夫问题。假设有n个人围圈而坐,现在从第k人开始数数,数到m的人出列,紧接着的后续人又从1开始数数,到m出列,如此重复下去,直到全体人员出列。编程实现新出列的数字序号输出。

实验仪器:

名称

型号 数量

微机 1

- 2 - 一、概要设计

本程序使用了循环链表这一数据结构。循环链表在普通链表的基础上,将最后一个节点的指针域指向头结点。具体定义为:

typedef struct CLNode{

int data;

struct CLNode *next;

}Node;//定义单向循环链表结构体,并令最后一个指针指向头结点

流程图如下:

注:在*处调用子函数 为head分配存储空间,如果内存不够,结束程序

head=head->next;

head->data=i;

i++; head==NULL? i<=n?

为p分配存储空间,如果内存不够,结束程序

pr->next=p;p->data=i;

p->next=head; pr=p; 开始

从主函数中接受头结点指针head,n

i=1,Node *p=NULL,

Node *pr=head;

返回head 是

是 否

图2——子函数:建立n阶循环链表,返回链表的头指针

图1——主函数 开始

输入总人数(n)、从第几个人开始数(k)、数到第几个人出列(m)

构造n项循环链表*

执行”head=head->next”k次,修改头指针指向 Node *head=NULL;int i=0;

按顺序输出?

否 是

是 否

结束 释放链表剩余存储空间 输出head->data 实现报数并出列* head!=head->next? 直接按顺序输出 - 3 -

二、详细设计

本程序核心算法主要有两部分:一是建立循环链表,二是实现目标人员的出列。

建立循环链表:

1.判断原链表是否为空,是的话,执行第2步,否则,执行第3步;

2.为头结点head分配存储空间,并令其指针域指向本身,head->data=1,用pr指向head,返回第1步;

3.判断计数器i(初始为2)是否不大于n,是的话,执行第4步,否则,执行第5步;

4.为节点p分配存储空间,并令其指针域指向head,给p->data赋值为i,令pr->next=p,用pr指向head,i增1,返回第3步;

5.返回head到主函数。

实现目标人员的出列:

1.输入从第k个人开始报数,在主函数中实现头指针的移动,修改后,执行第2步;

2.判断链表中的节点数是否大于1,是的话,执行第3步,否则,执行第5步;

3.调用子函数Search,定义指针 :Node *p=head,执行第4步;

4.根据输入中第m个人出列,移动指针p m-1次,令其指向要出列的目标节点,输出其数据域p->data,并令此节点之后的第一个节点为head,删除目标节点,返回head到主函数,执行第2步;

5.输出head->data,并释放链表的剩余空间,结束程序。

代码清单: 此时,p->data便是出列编号,输出其值

删除p指向的节点,令p之后的节点为head

返回head 开始

从主函数中接受head和m

int i=1;

Node *p=head;

Node *pre=NULL;

执行:”pre=p;p=p->next;”m次,模拟报数并移动指针

图3——子函数:当链表中的结点个数大于1,调用此函数,实现目标出列,并删除该节点,另该节点下一结点为头结点,返回修改后的头结点 - 4 -

#include

#include

typedef struct CLNode{

int data;

struct CLNode *next;

}Node;//定义单向循环链表结构体

Node* Creat(Node* head,int n);

Node* Search(Node* head,int m);

int main()

{

int m,n,k,j;

Node *head=NULL;

printf("How many person?");

scanf("%d",&n);

if(n<=0){

printf("Can't be zero!\n");

exit(0);

}

head=Creat(head,n); //建立链表

printf("Which number do you want to start:");

scanf("%d",&k);

printf("Which number should be out:");

scanf("%d",&m);

for(j=1;j

head=head->next;

}

printf("\n");

if(m==1){//如果是按顺序输出,不必调用Search函数

for(j=0;j

printf("output number is:%d\n",head->data);

head=head->next;

}

}

else{

while(head!=head->next){

head=Search(head,m);//返回修改后的头结点

}

if(head!=NULL){

printf("output number is:%d\n",head->data);//输出最后的节点

}

}

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

free(head);

return 0;

}

/*Create函数:参数为Node型结点指针和数量n

-建立单循环链表,如果成功,返回该链表的头指针*/

Node* Creat(Node *head,int n) {

Node *p=NULL;

Node *pr=head;

int i;

for (i=1; i<=n;i++){

if (head==NULL)

{

head=(Node*)malloc(sizeof(Node));

if(head==NULL){

printf("Allcate memory error!\n");

exit(1);

}

head->next=head;

head->data=i;

pr=head;

}

else

{

p=(Node*)malloc(sizeof(Node));

if(p==NULL){

printf("Allcate memory error!\n");

exit(1);

}

pr->next=p;

p->data=i;

p->next=head;

pr=p;

}

}

return head;

}

/*Search函数:输出从head开始数第m个结点的数据域,令该结点之后的结点为头结点,

并返回它,数据域从它开始再次循环*/

Node* Search(Node *head,int m)

{

int i=1;

Node *cur_p=head,*pre=NULL;//head为开始数1的人

while(i

pre=cur_p;

cur_p=cur_p->next;

i++;

}

printf("output number is:%d\n",cur_p->data);

pre->next=cur_p->next;

head=pre->next;//修改头指针

free(cur_p);//删除该节点

return head;

}