1、 实验报告 中山大学 数学学院 课程 设计题目: 约瑟夫环 问题 一 问题描述 设 有编号为 1,2, , n 的 n 个 ( n0) 个人 围城一个圈 , 每个人持有一个密码 m, 从第 1 个人 开始报数,报到 m时停止报数,报 m的人出圈,再从他的下一个人 起 重新报数,报 到 m时 停止报数 , 报 m的人出圈 , , 知道 所有人全部出圈为止 。 当 任意 给定 n和 m后 ,求 n个人出圈的次序。 二 基本要求 1. 建立 数据模型,确定储存结构; 2. 对 任意 n个人,密码为 m,实现约瑟夫环问题; 3. 出圈 的顺序可以依次输出,也可以用 一个 数组存储。 三 概要设计 1.
2、 数据结构 的设计 1.由于 约瑟夫环问题本 身 具有循环性质,考虑采用循环链表 ; 2.为了 统一对表中任意 结点 的操作 , 循环链表不带头 结点 ; 3.为了方便的进行计数,选用尾指针; 2. 算法的设计 由于约瑟夫环所需的数据结构为不带头指针的循环链表,所以在单链表的基础上,需要对构造函数进行改造 ; 约瑟夫环的实现过程中已经把链表所占用的空间释放掉,因此,析构函数只需采用默认析构函数 ,输出单链表时采用要改变终止条件 。综合来看,需要构造的函数 只有三 个,一个是构造函数,一个是 PrintList 函数,一个是实现约瑟夫环算法的函数。 1. 构造函数 ; 1.工作指针 r, s初始
3、化;控制循环变量 i初始化; 2.为 rear申请空间;将 an-1的值赋给 rear的指针域 ; r指向 rear的指针域 ; 3.重复执行下述操作,直到 i等于 n-2 3.1 为 s申请空间; 3.2 将 ai的值赋给 s的数据域 ; 3.3 将 s插入到 r ; 3.4 r指针后移; 4.将 rear插入到 r之后; 2. void PrintList() ; 1. 工作指针 p初始化; 2. 重复以下操作,直到 p-等于 rear; 2.1 输出 结点 p的数据域; 2.2 工作指针 p后移 3. 输出 rear的数据域 3. void YueSeFuHuan( int m, int
4、 n); 1. 工作指针 p, pre初始化;计数器 count初始化; 2. 重复以下操作,直到 pre等于 p; 2.1 如果 count=m,输出 p的数据域;删除 p结点 ;计数器 count初始化; 2.2 否则工作指针 pre, p后移; count+; 3. 删除 p结点 ; 3. 抽象数据类型的设计 ADT CircleLinkList Data 循环链表中的元素具有相同类型,相邻元素通过指针域具有前驱和后继的关系,第一个 结点 是最后一个 结点 的后继 Operation InitCircleLinkList 前置条件:循环链表 不存在 输入:数组的头指针,数组的长度 功能:
5、循环链表的初始化和赋值 输出:无 后置条件:一个具有数据的循环链表 DestroyCircleLinkList 前置条件:循环链表已存在 输入:无 功能:销毁循环链表 输出:无 后置条件:释放循环链表所占用的存储空间 PrintList 前置条件:循环链表已存在 输入:无 功能:遍历操作,按序号依次输出循环链表中的元素 输出:循环列表的各个数据元素 后置条件:线性表不变 YueSeFuHuan 前置条件:循环链表已存在 输入:循环列表长度 n,各个对象拥有的密码 m 功能:依照一定的次序删除各个对象,输出每次删除的对象序号 输出:每次删除的对象的序号 后置条件:线性表置空 四 详细设计 1 设
6、计 抽象数据类型 对应的 C+类定义。 1. InitCircleLinkList: template CircleLinkList:CircleLinkList(DataType a,int n) Node*r,*s; rear=new Node; r=rear; rear-data=an-1; /尾指针的数据的赋值 for(int i=0;i; s-data=ai; r-next=s;r=s; r-next=rear; 2. DestroyCircleLinkList: CircleLinkList:CircleLinkList() Node*q=NULL; while(rear-next
7、)!=rear) /这里由于不能直接判定是否循环终止,所以需要看后继是否为 rear本身 q=rear; rear=rear-next; delete q; delete rear; /还剩下头指针没有被释放 3. PrintList: template void CircleLinkList:PrintList() Node*p=rear-next; while(p!=rear) coutdatanext; coutdata void CircleLinkList:YueSeFuHuan(int n,int m) Node*p,*pre; pre=rear;/这里不应该加 * p=rear-
8、next; int count=1; while(pre!=p) if(count=m) coutdatanext=p-next; if(p=rear) rear=pre;/删除到对位 结点 要进行判断; delete p; p=pre-next; count=1; else pre=p; p=p-next; count+; delete p; 2 设计 每个数据成员 。 Node*rear; /* struct Node DataType data; Node*next; ;*/ 3 设计 主函数。 #include using namespace std; #include “CircleLinkList.cpp“ int main() const int n=10; const int m=3; int r10=1,2,3,4,5,6,7,8,9,10; CircleLinkListL(r,10); cout*rear; /* struct Node DataType data; Node*next; int Code; ;*/ 结构体中增加一个 Code,在 YueSeFuHuan 中的循环外再嵌套一个循环存储 Code,原循环在找到被删 结点 后,读取 Code,删除 结点 ,跳出原循环即可。