猴子选大王循环链表实现
monkey

课程设计说明书
2.1.4 2.1.4.创建单向基本链表基本算法
创建循环单链表函数 采用头插法创建单向循环链表 Status CreateList(elemtype m) { List head, p; head = (List)malloc(sizeof(struct Node)); //*为头指针申请两个空间*// head->next = head; //*一共有 m 个猴子,所以建立含有 m 个结点的单向循环链表*// for (i = 1; i < m; ++i) { p = (List)malloc(sizeof(struct Node)); / /*为结点申请两个空间*// p->next = head->next; head->next = p; }//*利用 for 循环实现链表的创建*// p = head; //*将指针 p 指向表头*//
No.8
沈阳大学
课程设计说明书
2.1.6 2.1.6 主函数方案设计
No.9
在主函数中首先设计程序的登陆界面信息,用户可以根据界面的提示,完成猴子选大 王的基本操作过程,为了使操作更加人性化,使输入猴子的数目 m 和决定要淘汰的猴子 编号 n,通过键盘输入,若输入错误是(m<n),界面将用英文提示输入错误请重新输入, ,若输入正确,程序将显示运行后的结果,显示最后猴子大王的编号,并显示被淘汰猴子 的编号,程序运行完毕。 在主函数中,在用户输入结束后,分别调用创建链表函数 CreateList(elemtype m)和猴 子选大王参数 LinkedList(elemtype num_monkey, elemtype number),经过一些列的运 算,最后得出猴子大王的编号,及其被淘汰的猴子的编号,以上即为函数的基本功能的 实现过程。
猴子选大王

[题目]第1.1猴子选大王问题一:实验内容:M只猴子要选大王,选举办法如下:所有猴子按1,2……n编号围成一圈,从第一号开始顺序1,2……m,凡是报m号的退出圈外,如此循环报数直到圈内只剩一只猴子时这只猴子就是大王。
二:实验要求:利用单向循环链表模拟此过程,输出选出的大王编号。
三:程序的设计思想:(1)问题分析:“猴子选大王”问题是约瑟夫环问题的一个特例。
由于本题目的数据元素个数不可知,所以可使用链表来动态的分配内存空间。
而该问题又是一个不断的循环问题所以用循环链表来实现。
(2)总体设计:首先生成一个空链表,并给n个结点分配空间,让单链表的表尾指针指向头结点则生成一个带有n个结点的循环单链表。
再给每只猴子建立顺序的编号。
现从第一个结点开始报数,依次顺序查找出报数为m的待出列的结点(猴子)通过q->next=p->next删除该结点后继续运行否则让q成为p的前驱指针。
最后当p->next==p时停止运行,得到p所指向的结点即为猴子选出大王的编号。
四:提供测试结果:定义 n=8, m=3,测试结果如下:对猴子进行编号!1号猴子:12号猴子:23号猴子:34号猴子:45号猴子:56号猴子:67号猴子:78号猴子:82号猴子报:2 3号猴子报:3 3号猴被淘汰4号猴子报:1 5号猴子报:2 6号猴子报:3 6号猴被淘汰7号猴子报:1 8号猴子报:2 1号猴子报:3 1号猴被淘汰2号猴子报:1 4号猴子报:2 5号猴子报:3 5号猴被淘汰7号猴子报:1 8号猴子报:2 2号猴子报:3 2号猴被淘汰4号猴子报:1 7号猴子报:2 8号猴子报:3 8号猴被淘汰7号猴子报:24号猴子报:34号猴被淘汰7号猴子报:1胜出:7号猴子Press any key to continue五:程序源代码#include <stdio.h>#include <stdlib.h>#define n 8#define m 3typedef struct monkey{int num;struct monkey *next;} Monkey;int main(){Monkey *p,*head,*q;int i;head=p=q=malloc(sizeof(Monkey));//建立头指针 for(i=1;i<n;i++) //给n个结点分配空间{p=malloc(sizeof(Monkey));q=p;}q->next=head; //建立循环链表p=head;printf("对猴子进行编号!\n");for(i=1;i<=n;i++) //给n只猴子分别建立顺序编号{p->num=i;printf("%d号猴子:%d\n",p->num,p->num);p=p->next;}i=0; //初始化p=head;while(1){i++;printf("%d号猴子报:%d\n",p->num,i);if(p->next==p) break; //判断还剩下最后一个结点时停止运行 if(i==m) //报道m的猴子淘汰{i=0;printf("%d号猴被淘汰\n",p->num);q->next=p->next;continue;}else{if(i==m-1) q=p;p=p->next;}}printf("胜出:%d号猴子",p->num); }。
约瑟夫问题及变种

“约瑟夫”问题及若干变种例1、约瑟夫问题(Josephus)[问题描述]M只猴子要选大王,选举办法如下:所有猴子按1…M编号围坐一圈,从第1号开始按顺序1,2,…,N 报数,凡报到N的猴子退出到圈外,再从下一个猴子开始继续1~ N报数,如此循环,直到圈内只剩下一只猴子时,这只猴子就是大王。
M和N由键盘输入,1≤N,M≤10000,打印出最后剩下的那只猴子的编号。
例如,输入8 3,输出:7。
[问题分析1]这个例题是由古罗马著名史学家Josephus提出的问题演变而来的,所以通常称为Josephus(约瑟夫)问题。
在确定程序设计方法之前首先来考虑如何组织数据,由于要记录m只猴子的状态,可利用含m个元素的数组monkey来实现。
利用元素下标代表猴子的编号,元素的值表示猴子的状态,用monkey[k]=1表示第k只猴子仍在圈中,monkey[k]=0则表示第k只猴子已经出圈。
程序采用模拟选举过程的方法,设变量count表示计数器,开始报数前将count置为0,设变量current 表示当前报数的猴子编号,初始时也置为0,设变量out记录出圈猴子数,初始时也置为0。
每次报数都把monkey[current]的值加到count上,这样做的好处是直接避开了已出圈的猴子(因为它们对应的monkey[current]值为0),当count=n时,就对当前报数的猴子作出圈处理,即:monkey[current]:=0,count:=0,out:=out+1。
然后继续往下报数,直到圈中只剩一只猴子为止(即out=m-1)。
参考程序如下:program josephus1a {模拟法,用数组下标表示猴子的编号}const maxm=10000;var m,n,count,current,out,i:integer;monkey:array [1..maxm] of integer;beginwrite('Input m,n:');readln(m,n);for i:=1 to m do monkey[i]:=1;out:=0; count:=0; current:=0;while out<m-1 dobeginwhile count<n dobeginif current<m then current:=current+1 else current:=1;count:=count+monkey[current];end;monkey[current]:=0; out:=out+1; count:=0end;for i:=1 to m doif monkey[i]=1 then writeln('The monkey king is no.',i);readlnend.[运行结果]下划线表示输入Input m,n:8 3The monkey king is no.7 {时间:0秒}Input m,n:10000 1987The monkey king is no.8544 {时间:3秒}[反思]时间复杂度很大O(M*N),对于极限数据会超时。
数据结构习题及答案 (7)

第五章数组和广义表一、选择题1. 常对数组进行的两种基本操作是()(A)建立与删除(B)索引和修改(C)查找和修改(D)查找与索引参考答案:C2.二维数组M的元素是4个字符(每个字符占一个存储单元)组成的串,行下标i的范围从0到4,列下标j的范围从0到5,M按行存储时元素M[3][5]的起始地址与M按列存储时元素( ) 的起始地址相同。
(A)M[2][4](B)M[3][4](C)M[3][5](D)M[4][4]参考答案:B3.数组A[8][10]中,每个元素A的长度为3个字节,从首地址SA开始连续存放在存储器内,存放该数组至少需要的单元数是()。
(A)80(B)100(C)240(D)270参考答案:C4.数组A[8][10]中,每个元素A的长度为3个字节,从首地址SA开始连续存放在存储器内,该数组按行存放时,元素A[7][4]的起始地址为()。
(A)SA+141(B)SA+144(C)SA+222(D)SA+225参考答案:C5.数组A[8][10]中,每个元素A的长度为3个字节,从首地址SA开始连续存放在存储器内,该数组按列存放时,元素A[4][7]的起始地址为()。
(A)SA+141(B)SA+180(C)SA+222(D)SA+225参考答案:B6.稀疏矩阵一般的压缩存储方法有两种,即()。
(A)二维数组和三维数组(B)三元组和散列(C)三元组和十字链表(D)散列和十字链表参考答案:C7.若采用三元组压缩技术存储稀疏矩阵,只要把每个元素的行下标和列下标互换,就完成了对该矩阵的转置运算,这种观点()。
(A)正确(B)错误参考答案:B8.设矩阵A是一个对称矩阵,为了节省存储,将其下三角部分按行序存放在一维数组B[1,n(n-1)/2]中,对下三角部分中任一元素ai,j(i<=j),在一组数组B的下标位置k的值是()。
(A)i(i-1)/2+j-1(B)i(i-1)/2+j(C)i(i+1)/2+j-1 (D)i(i+1)/2+j参考答案:B二、填空题1.己知二维数组A[m][n]采用行序为主方式存储,每个元素占k个存储单元,并且第一个元素的存储地址是LOC(A[0][0]),则A[0][0]的地址是_____________________。
约瑟夫问题

cout<<endl;
return 0;
}
约瑟夫问题:有n只猴子,按顺时针方向围成一圈选大王(编号从1到n),从第1号开始报数,一直数到m
,数到m的猴子退出圈外,剩下的猴子再接着从1开始报数。就这样,直到圈内只剩下一只猴子时,
这个猴子就是猴王,编程求输入n,m后,输出最后猴王的编号。
int main()
{
int i,j,nx[10000] = {0},n[10000] = {0},m[10000] = {1},counter[2] = {0};//数组要足够大才能不停止运行
{ j = j % nx[i]; //求余实现循环从0-n移动或用if判断实现循环
if(n[j] == 0)
{ counter[0]++; //计数器记录具有某一特点的数的次数
if(counter[0] % m[i] == 0)n[j] = 1,counter[1]+& = 0;j < nx[i];j++)
if(!n[j])cout<<j + 1<<endl;
for(j = 0;j < 10000;j++)n[j] = 0;for(j = 0;j < 2;j++)counter[j] = 0; //初始化需要重新使用的变量
for(i = 1;m[i - 1] != 0;i++) //利用m[]只有最后的值为0判定,不使用m[0]并赋值为1,其余默认为0
cin>>nx[i]>>m[i];
for(i = 1;m[i] != 0;i++)
C语言-猴子选大王

do//输入总个数
{
printf("请输入总个数(1-%d):",MAXN);
scanf("%d",&m);
}while((m<1)||(m>MAXN));
do//输入出圈时要数到的个数
{
printf("要数到的个数(1--%d):",m);
scanf("%d",&n);
}
for(i=m-1;i>=0;i--)
printf("%4d",a[i]);
printf("\n");
}
}
3.#include<stdio.h>
#include<stdlib.h>
#define MAXN 100 /*定义猴子总数*/
void main()
{
int i,j,*a,m,n,s1,w;
do//输入总个数
printf("\n");
}
}
4.#include<stdio.h>
#include<stdlib.h>
#define MAXN 100 //最大个数
struct Node
{
int data;
struct Node *next;
};
void main()
{
struct Node *head, *s, *q, *t;
for(j=s1;j<i;j++) //原来第i+1个至倒数第i个元素依次向前移动一个位置。
Res_猴子选大王2

5.4.8 实验项目5-14:猴子选大王1、实验名称:猴子选大王2、实验目的:(1)熟练使用循环控制。
(2)熟练理解和掌握二维数组存储结构的使用技巧。
3、实验任务(1)实验内容:一群猴子要选新猴王。
新猴王的选择方法是:让n只候选猴子围成一圈,从某位置起顺序编号为1~n号。
从第1号开始报数(从1到3),凡报到3的猴子即退出圈子,接着又从紧邻的下一只猴子开始同样的报数。
如此不断循环,最后剩下的一只猴子就选为猴王。
请问是原来第几号猴子当选猴王?(2)实验要求:输入一个正整数n(n<=100),写一个程序来模拟这个过程,输出猴王的序号。
测试用例:4、实验要点分析(1)问题分析:用循环的方法模拟选猴王的过程。
一种简单的方法是对n只猴子用1~n 编号,编号存放在大小为n的一维整数数组中,若某编号的猴子要退出圈子,则把其编号改为-1。
若数组中只剩一个非-1的编号时,该编号的猴子就是大王。
开始时数组中的元素是从1到n的整数,表示都在“圈子”中,凡报到3的猴子退出圈子,即置为-1。
再依次查找下一只在“圈子”中的猴子,并重新开始报数。
这个过程进行n-1次,就只剩下一只编号不是-1的猴子了。
这种方法在寻找“下一个在圈子中的猴子”时可能会遇到很多“-1”而浪费时间。
另一种改进的方法是把n只猴子用0~n-1编号,数组的下标表示猴子的编号,数组元素的值表示相邻下一只在圈子中的猴子编号。
比如,n=5时,初始的数组M的内容如下表: 下标:0 1 2 3 4当2号猴子(报数轮到3)退出圈子时,1号猴子的下一只相邻猴子就是3号猴子了,实现时只需一个赋值M[1]=M[2](即原来2号猴子的下一只相邻猴子成了1号猴子的下一只相邻猴子)。
数组M的内容变成了下表:下标:0 1 2 3 4这样做的好处有两个,一是第i号猴子的下一只相邻猴子就是M[i],不需要用一个循环去找了;二是不用当心数组M下标的访问会越界。
(2)实现要点:1)循环控制结构。
用C编写程序猴子选大王

湖南人文科技学院计算机系课程设计说明书课程名称: 数据结构课程代码:题目: 猴子选大王年级/专业/班: 06级计算机科学与技术专业一班学生姓名:学号:06408109 06408102 06408107 0640812206408103指导教师: 刘刚常开题时间: 2008 年 6 月16 日完成时间: 2008 年 6 月29 日目录摘要 (3)一、引言 (4)二、设计目的与任务 (4)三、设计方案 (5)1、总体设计 (5)2、详细设计 (8)3、程序清单 (14)4、程序调试与体会 (22)5、运行结果 (23)四、结论 (24)五、致谢 (24)六、参考文献 (25)摘要本文首先介绍顺序表和链表并作以比较,我们分别使用循环队列和循环链表来解决猴子选大王的问题,程序使用了C语言编写,有很少一部分函数是用C++编写的,有比较详细的中文注释并在VC++下调试运行通过。
整个程序使用中文界面,并有相应的提示信息,便于操作和程序运行。
关键词:循环队列;循环链表;存储结构AbstractThis paper details the difference of sequence list and linklist.We respectively use queue and circular queue and circular linked list to solve the seek elected king of the monkey problem . The procedure write with C language ,a very small part function is used by the C + +,and has chinese explanatory note.What’s more,it was debugged in VC++ debugger and run very well.The whole procedure,with Chinese interface and thecorresponding hints,is convenient to run and easy to be operated.Keywords : circular queue;circular linked list ;storage structure《数据结构》课程设计——猴子选大王一、引言数据结构是一门非常重要的基础学科,但是实验内容大都不能很好的和实际应用结合起来。
- 1、下载文档前请自行甄别文档内容的完整性,平台不提供额外的编辑、内容补充、找答案等附加服务。
- 2、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
- 3、如文档侵犯您的权益,请联系客服反馈,我们会尽快为您处理(人工客服工作时间:9:00-18:30)。
C++n只猴子围成一圈,顺时针方向从1到n编号。
之后从1号开始没顺时针方向让猴子从1,2,...,m依次报数,凡是报到m的猴子,就让其出圈,取消候选资格。
然后不停地按顺时针方向逐一让报到m者出圈,是的剩下的一个就是猴王。
#include <iostream>using namespace std;struct monkey //结构声明{int num; //整型数,用于记录猴子号monkey *next; //monkey结构指针};monkey *head,*tail; //monkey结构指针,全局变量void creat(int nn) //被调用函数{ //函数体开始int i; //整型变量i,用于计数monkey *p,*q; //声明monkey结构指针p,qp=new monkey; //为p分配内存空间p->num=1; //初始化p结点num域为1p->next=NULL; //初始化p结点next域为空head=p; //链表头指针head赋值为pq=p; //q赋值为pfor(i=2;i<=nn;i=i+1) //利用循环结构构造链表{p=new monkey; //为p配内存空间p->num=i; //初始化p结点num域为i,表示猴子号q->next=p; //将p点加到链表尾部q=p; //让指向链表尾部结点p->next=NULL; //链表尾部指向空}tail=q; //链表尾tail->next=head; //链表尾部指向链表头,形成循环链表}//被调用函数select,mm表示结点删除间隔void select(int mm){ //函数体开始int x=0; //声明整型值x,并初始化为0monkey *p,*q; //声明指针变量p,qq=tail; //q赋值给tail,指向循环链表尾部do //直到型循环,用于循环删除指定间隔的结点{p=q->next; //p赋值给相邻的下一个结点x=x+1; //x加1if(x%mm==0) //x是否整除mm{cout<<"被删除的猴子号为"<<p->num<<"号\n";q->next=p->next; //删除此结点delete p; //释放空间p=NULL;}elseq=p; //q指向相邻的下一个结点p}while(q!=q->next); //剩余结点数不为1,则继续循环head=q; //head指向结点q,q为链表中剩余的一个结点} //函数体结束int main() //函数体开始{int n,m; //声明整型变量n,mhead=NULL; //初始化head为空cout<<"请输入猴子的个数\n"; //提示信息cin>>n; //输入待插入结点的数据cout<<"请输入间隔\n"; //提示信息cin>>m; //输入间隔creat(n); //调用函数creat建立循环链表select(m); //调用函数select,找出剩下的猴子cout<<"猴王是"<<head->num<<"号\n"; //输出猴王delete head; //删除循环中最后一个结点return 0;} //函数体结束c//实现目标:分别列出出列的猴子,然后得出最后的大王,(我认为没必要猴子数m要大于n!..所以没有这方面的提示~~)//问题分析:通过对“猴子选大王”问题的分析,由于本题目的数据元素的个数不可预知,所以使用链表。
链表是动态的,可以在需要的时候增长和减少其长度,而数组是在编译时分派内存的,事业其大小是不可改变的,而且会出现内存浪费的情况。
我认为单循环链表能较好,在建立循环链表时,因为链表的大小由输入决定,因此与匹配的结点数也是变化的,所以要进行动态内存分配。
//测试用例:m=10;n=4,最后求出成为猴王的猴子号:结果:大王是5号:(太搞笑了,大家都用这个用例,第五号可真幸运!~)//不健全的地方:1.没有对输入为字母,非正数(例如0)进行出错判断,结果大王会是第一号猴子。
(我觉得也可以不改啊~~没有“正常的”猴子,下一个真正的猴子当然是大王)2.如果正数但是非整数,输出为……(我没试过=——=!)//猴子选大王源代码:#include"stdio.h"//用双引比尖括号好的原因是可以在本环境外部查找这个头文件滴..#include"stdlib.h"typedef struct Node{int data;struct Node *next;}Node,*LinkList;void CreatLinkList(LinkList *L,int m)// 创建循环链表 m为猴子总数{Node *p, *q;int i; (*L) = (LinkList)malloc(sizeof(Node));if ((*L) == NULL)//这里是什么意思?{printf("Memory allocation failed,goodbye~~");exit(1);}p = (*L);p->data = 1;//为什么错误数据会返回“第一号猴子”的值?是这里初始化的么?(如果是可以换成0的说~)for (i = 2; i <= m; i++){q = (LinkList)malloc(sizeof(Node));if (q == NULL){printf("Mmory allocation failed,goodbye~~");exit(1);}q->data = i;p->next = q;p = q;}p->next =(*L);}void King(LinkList *L, int n, int m){Node *p, *q;int k;int j = 1; p = (*L);for (; m > 1; m--){k = 1;while (k != n){p = p->next;k++;}printf("第%d个出队列的是%d号猴子,\n", j++, p->data);p->data = p->next->data;q = p->next;p->next = p->next->next;free(q);}printf("最终结果:大王是第%d号猴子。
\n",p->data);}int main(void){int m, n;LinkList L; printf("请输入猴子总数m,和数到那个猴子出队n,(逗号隔开):");scanf("%d%d",&m,&n);//在这后面加判断、提示部分。
for循环判断.. CreatLinkList(&L, m);King(&L, n, m);sistem("pause");return 0;}题目描述:n 只猴子要选大王,选举方法如下:所有猴子按 1,2 ……… n 编号并按照顺序围成一圈,从第 k 个猴子起,由1开始报数,报到m 时,该猴子就跳出圈外,下一只猴子再次由1开始报数,如此循环,直到圈内剩下一只猴子时,这只猴子就是大王。
输入数据:猴子总数n ,起始报数的猴子编号k ,出局数字m 输出数据:猴子的出队序列和猴子大王的编号代码修改了一天才完成,第一次是用多个函数写的,但是发觉C 语言没有引用参数这个特性,使得形参指针不能被直接修改,必须靠返回值来修改才行,这样太麻烦了...于是第二次写的时候就没有使用函数,直接在main()里完成了循环链表的操作,感觉应该没什么问题,哪位大牛看出问题跟我说下,thx...1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 /*约瑟夫问题(猴子选大王)循环链表C 语言实现Slyar 2009.3.31*/#include <stdio.h>#include <stdlib.h>/* 定义链表节点类型 */typedef struct node{int data ;struct node *next ;}linklist ;int main ()19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 {int i , n , k , m , total ; linklist *head , *p , *s , *q ; /* 读入问题条件 */ printf ("请输入猴子的个数:"); scanf ("%d", &n ); printf ("请输入要从第几个猴子开始报数:"); scanf ("%d", &k ); printf ("请输入出局数字:"); scanf ("%d", &m ); /* 创建循环链表,头节点也存信息 */ head = (linklist *) malloc (sizeof (linklist )); p = head ;p ->data = 1;p ->next = p ;/* 初始化循环链表 */ for (i = 2; i <= n ; i ++) {s = (linklist *) malloc (sizeof (linklist )); s ->data = i ;s ->next = p ->next ; p ->next = s ; p = p ->next ; }/* 找到第 k 个节点 */ p = head ;for (i = 1; i < k ; i ++) {p = p ->next ; }/* 保存节点总数 */ total = n ;printf ("\n 出局序列为:"); q = head ;/* 只剩一个节点时停止循环 */ while (total != 1) {/* 报数过程,p 指向要删除的节点 */ for (i = 1; i < m ; i ++) {p = p ->next ; }/* 打印要删除的节点序号 */ printf ("[%d] ", p ->data );63646566676869707172737475767778798081828384/* q 指向p 节点的前驱*/while(q->next != p){q = q->next;}/* 删除p 节点*/q->next = p->next;/* 保存被删除节点指针*/s = p;/* p 指向被删除节点的后继*/p = p->next;/* 释放被删除的节点*/free(s);/* 节点个数减一*/total--;}/* 打印最后剩下的节点序号*/printf("\n\n猴子大王为第[%d] 号\n\n", p->data); free(p);//system("pause");return0;}实验二#include<iostream.h>#include<conio.h>#include<stdlib.h>#define OK 1#define ERROR 0#define OVERFLOW 0typedef int Status;typedef struct LNode{int data;struct LNode *next;}LNode,*LinkList;void CreatList_L(LinkList &L,int n){L=(LinkList)malloc(sizeof(LNode));L->next=NULL;int i; LinkList q,p;q=L;for(i=n;i>0;--i){p=(LinkList)malloc(sizeof(LNode));cin>>p->data;q->next=p;p->next=NULL;q=p;}}//尾插法void output(LinkList &L){ LinkList p;p=L->next;while(p){cout<<p->data;p=p->next;}}//输出函数Status ListInsert_L(LinkList &L,int i,int e){ LinkList p,s;int j;p=L;j=0;while(p&&j<i-1){p=p->next;++j;}if(!p||j>i-1)return ERROR;s=(LinkList)malloc(sizeof(LNode));s->data=e;s->next=p->next;p->next=s;return OK;}void main(){LinkList L;CreatList_L(L,4);output(L);ListInsert_L(L,2,5);output(L);}void CreatList_L(LinkList &L,int n){L=(LinkList)malloc(sizeof(LNode));L->next=NULL;int i; LinkList p;for(i=n;i>0;--i){p=(LinkList)malloc(sizeof(LNode));cin>>p->data;p->next=L->next;L->next=p;}}//头插法。