1.实验题目
约瑟夫环
[问题描述]
约瑟夫(Joeph)问题的一种描述是:编号为1,2,…,n的n个人按顺时针方向围坐一圈,
每人持有一个密码(正整数)。一开始任选一个正整数作为报数上限值m,从第一个人开始
按顺时针方向自1 开始顺序报数,报到m时停止报数。报m的人出列,将他的密码作为新
的m值,从他在顺时针方向上的下一个人开始重新从1 报数,如此下去,直至所有人全部
出列为止。试设计一个程序求出出列顺序。
[基本要求]
利用单向循环链表存储结构模拟此过程,按照出列的顺序印出各人的编号。
[测试数据]
m的初值为20;密码:3,1,7,2,4,8,4(正确的结果应为6,1,4,7,2,3,5)。
[实现提示]
程序运行后首先要求用户指定初始报数上限值,然后读取各人的密码。设n≤30。
[选作内容]
向上述程序中添加在顺序结构上实现的部分。
2.需求分析
本演示程序用c++编写,完成单向循环链表的生成,向单向循环链表中插入元素,从单向循环链表中删除元素
输入的形式和输入值的范围:需要输入初始报数上限值m,人数n,n个密码。在所有输入中,元素的值都是整数,n<=30.
② 输出的形式:输出最后出列的人的顺序。
③ 程序所能达到的功能:完成约瑟夫问题
④ 测试数据:
输入m=20,n=7,密码依次为3,1,7,2,4,8,4
3.概要设计
1)为了实现上述程序功能,需要定义单链表的抽象数据类型:
typedef struct Node
{
int password;//存储密码,即m
int num;
struct Node* next;
}Node, * Link;
基本操作:初始化循环链表
phead = NULL;
操作结果:循环链表为空,头指针指向空
基本操作:向循环链表中插入密码
void CreateList(int n, Link& L) {//初始化链表
Link p, q;
q = L;
printf("请输入这%d个人的初始密码分别为:", n);
for (int i = 1; i <= n; i++) {
p = (Node*)malloc(sizeof(Node));
if (!p)
exit(1);
scanf_s("%d", &p->password);
p->num = i;
L->next = p;
L = p;
}
L->next = q->next;
free(q);
}基本操作:找到需要出列的人
void PrintList(Link& L, int m, int n) {//找位置
Link p, q;
p = L;
for (int i = 1; i <= n; i++) {
for (int i = 1; i < m; i++)
p = p->next;
q = p->next;
m = q->password;
printf("%d ", q->num);
p->next = q->next;
free(q);
}
}操作结果:将出列的人密码赋为0
4.详细设计
#include <stdio.h>
#include <stdlib.h>
#include <malloc.h>
typedef struct Node
{
int password;//存储密码,即m
int num;
struct Node* next;
}Node, * Link;
void InitList(Link& L) {//创建一个空的链表
L = (Node*)malloc(sizeof(Node));
if (!L)
exit(1);
L->password = 0;
L->num = 0;
L->next = L;
}
void CreateList(int n, Link& L) {//初始化链表
Link p, q;
q = L;
printf("请输入这%d个人的初始密码分别为:", n);
for (int i = 1; i <= n; i++) {
p = (Node*)malloc(sizeof(Node));
if (!p)
exit(1);
scanf_s("%d", &p->password);
p->num = i;
L->next = p;
L = p;
}
L->next = q->next;
free(q);
}
void PrintList(Link& L, int m, int n) {//找位置
Link p, q;
p = L;
for (int i = 1; i <= n; i++) {
for (int i = 1; i < m; i++)
p = p->next;
q = p->next;
m = q->password;
printf("%d ", q->num);
p->next = q->next;
free(q);
}
}
int main() {
Link L, p, q;
int n, m;
L = NULL;
InitList(L);
printf("初始密码为:");
scanf_s("%d", &m);
printf("总人数为:");
scanf_s("%d", &n);
CreateList(n, L);
printf("正确的输出为:");
PrintList(L, m, n);
printf("\n");
return 0;
}
5.调试分析
运行稳定,在建立链表的时候要细心,规范循环结构。对头节点的控制进行了多次的调试。对于数据的储存和删除也进行了多次的修改。
6.使用说明
先确定使用的人数范围,然后赋予每个人独自的密码,然后再规定起始读数范围。最后由程序作出最终的排序结果。