约瑟夫环实验报告
报告人:又是一个新的人类?
(一)实验描述和要求
实验描述: 已知n个人(以编号1,2,3…n分别表示)围坐在一张圆桌周围。从编号为k的人开始报数,数到m的那个人出列;他的下一个人又从1开始报数,数到m的那个人又出列;依此规律重复下去,直到圆桌周围的人全部出列。
实验要求:
- 实验①
用单向循环链表存储结构模拟此过程,按照出列的顺序印出各人的编号.
测试数据:m的初值为20;n=7,7个人的密码以此为:3,1,7,2,4,8,4 最先的m值为6
(也就是说这种情况是数字题目给定)
- 实验②
用顺序存储(数组) 方式实现
测试数据:密码m可以任意(正、负均可,不是事先存储,每次运行随机产生)
(二)主要仪器设备
CLion 、 VS (恕我直言,clion我没跑出过一次,用它是因为复制粘贴写出的代码好看)
(三)实验简述
1.一群人围在一起坐成 环状(如:N)
2.从某个编号开始报数(如:K)
3.数到某个数(如:M)的时候,此人出列,下一个人重新报数
4.一直循环,直到所有人出列 ,约瑟夫环结束
(四)实验步骤与调试分析
实验思路:
(实验①)用单项循环链表实现 :
1.从编号k开始(k=6)报数,那么顺序应该是4 6 5 3 7 1 2
2.一群人围成环状,则可以用单向循环链表实现,这个比较好理解
3.循环条件是圈内的人数大于1,即while(p->next!=p)指针实现
(实验②)用顺序储存的方式(数组)实现:
刚开始写起来困难是因为没有掌握循环数组的方法 有一个要记下的公式
错误思想是每一次数完后删除该数重新排一次再数
现在想起来就伤心,这样需要用后一个去代替前一个来删除已经报完的数字,时间复杂度很高
所以简便方法是用数组表达一个利用公式 (i+m-1) %n,找出要输出数组的下标i
删除操作可以把这个数字换成产生的随机数之外的数字
1.每个人的密码存放在一个数组 a 中,主函数中决定人数的个数以及报数的上限值 m,设计一个函数实现对应的操作。函数的形参有整型数组 a、整数 n 和 m,
2.n 用来接收传递的人数,m 用来接收报数上限,函数的返回值为空;函数体中输出出列人的顺序。
3. 函数中利用循环访问数组中 n 个元素,每次访问元素,设定内循环连续访问 m 个元素,元素访问的下标为 k,访问到第 m 个元素时,如果元素不是 101,此时输出元素 a[k],再设定 a[k] 为
101,继续访问后面的元素。(用101的原因是在产生的随机数之外)
针对实验①
在这里插入链表的相关操作(熟悉操作的小伙伴们可以直接跳过
1)规范的构建一个新的循环单链 // 副标题 《如何让老师认为自己已经掌握数据结构之格式写标准》
循环单链表和双链表都是只要掌握好单链表的基本操作就可以了
#include<stdio.h>
#include<stdlib.h>
Typedef struct LNode {
ElemType data; //数据域
struct LNode *next; //指针域
}LNode, *LinkList; // *LinkList为LNode类型的指针
细节注意,双链表: ‘ DuL‘
typedef struct DuLNode{
ElemType data; //数据域
struct DuLNode *prior; //前驱指针域
struct DuLNode *next; //后继指针域
} DuLNode , *DuLinkList ;
2)单链表的建立有两种方法:头插法和尾插法
头插法
void CreateListF(LinkList *&L, ElemType a[ ], int n)
{
LinkList *s; int i;
L = (LinkList *)malloc(sizeof (LinkList) ); //创建头结点
L->next = NULL; //空链表
for (i=0; i<n; i++){
s = (LinkList *) malloc (sizeof(LinkList)); //创建新结点
s->data = a[<