[实用参考]顺序表实现约瑟夫环的问题-C语言.doc
C语言单向循环链表实现实现约瑟夫环
C语言实现约瑟夫环问题------单向循环链表实现问题描述:有n个人围成一圈进行报数游戏,从第一个人开始报到m的人出圈,接下来有从下一个人开始,。
一次这样往复,直到最后一个人也出圈,求他们的出圈顺序?(例如8个人,凡报3的人出圈,则他们出圈顺序是3 ,6, 1,,5 ,2 ,8,4 ,7)#include<stdio.h>#include<stdlib.h>typedef struct node{int value;struct node *next;}NODE;//*********************建立循环链表(尾插法建立)***********//NODE *createlink(int number){NODE *head=NULL,*p=NULL,*q=NULL;int i=1;head=(struct node*)malloc(sizeof(struct node)); //***建立第一个节点***//head->value=i;p=head;for(i=2;i<=number;i++) //***建立剩下的number-1节点****//{q=(struct node*)malloc(sizeof(struct node));if(q==0) return 0;p->next=q;p=q;p->value=i;}p->next=head;return head;}//*****************建立约瑟夫环********************// void jose(NODE *p,int number,int n){int i,j,g=0;NODE *q=NULL;for(i=1;i<=number;i++){for(j=1;j<n-1;j++){p=p->next;}q=p->next; //***q用来记录要删除的节点*****//p->next=q->next; //****删去q节点******//p=p->next;printf("第%3d个出圈号是:%3d\n",i,q->value);free(q);}printf("\n");// p->next=NULL; 此表达式不能出现在此处,最后一个节点删除后就不存在了}//***********************主函数*************************//int main( ){int number=0;int n=0;printf("请输入总人数number和出拳编号n:\n");scanf("%d",&number);scanf("%d",&n);NODE *head=NULL;head=createlink(number);jose(head,number,n);system("PAUSE");return 1;}。
C实验报告约瑟夫斯环问题
约瑟夫斯(Josephus)问题的一种描述是:编号为1,2,…,n的n个人按顺时针方向围坐一圈,每人持有一个密码(正整数)。
一开始任选一个正整数作为报数上限值m,从第一个人开始按顺时针方向自1开始报数,报到m时停止报数。
报m的人出列,将他的密码作为新的m值,从他在顺时针方向下一个人开始重新从1报数,如此下去,直至所有的人全部出列为止。
试设计一个程序,按出列顺序印出各人编号。
2.基本要求:利用单向循环链表存储结构模拟此过程,按照出列的顺序印出各人的编号。
3.测试数据:m的初值为20;n=7,7个人的密码依次为:3,1,7,2,4,8,4。
m初值为6(正确的出列顺序应为6,1,4,7,2,3,5)。
4.简述每一部分的对象、目的和要求:(1)主函数部分:对象:链表;目的:创建新链表;要求:将该链表初始化。
(2)被调函数部分:对象:结构体;目的:创建循环链表并且模拟约瑟夫斯问题;要求:让链表首尾相接,并且释放原来单链表的头结点空间。
通过该函数的调用,依次输出各结点的编号,并且符合规则。
二.需求分析1.程序所能达到的基本可能:该程序用循环链表来模拟n个人顺时针围坐一圈,用链表中的每一个结点代表一个人,结点结构体中设置两个变量,分别存放其编号以及密码。
在输入初始密码后,对该链表进行遍历,直到遍历到第m个结点,释放其空间,使其出列。
然后用被释放空间结点的密码值作为新的密码值,重复上述过程,直至所有结点被释放空间出列,链表成为空链表。
2.输入输出形式及输入值范围:程序运行后显示提示信息:"Please input a data:",提示用户输入密码信息,在输入达预定次数后自动跳出该循环,同时循环链表创建成功,在主函数中有相应的输出给予检验。
然后程序显示提示信息:"Please input the number m:",提示用户输入初始密码,程序执行结束后会输出相应的出列结点的顺序,亦即其编号。
约瑟夫问题—顺序表完美实现
for(i=pst->length;i>0;i--)
{
s1=(s1+m-1)%i;
w=pst->pbase[s1];
printf("%d ",w);
delete_Seqlist(pst,s1+1);
}
printf("\n");
return(1);
}
void init_list(PSeqlist pst,int length)
void delete_Seqlist(PSeqlist pst,int m);
int jose(PSeqlist pst,int s, int m);
int main(void)
{
int s,m;
Seqlist p1;
init_list(&p1,20);
input_list(&p1);
printf("请输入开始位置s和间隔数m : ");
1.代码
#include <stdio.h>
#include <malloc.h>
typedef struct list
{
int * pbase;
int maxsize;
int length;
}Seqlist,* PSeqlist;
void init_list(PSeqlist,int);
void input_list(PSeqlist);
{
scanf("%d",&x);
if (x == -1)
break;
约瑟夫环C 代码及实验报告
{
outArray[k]=listArray[j];// 将 该 元 素 放 置 到 出 列 数 组
里,并输出
cout<<outArray[k]<<" ";
k++;
listArray[j]=0; //将出列元素置 0
i=1; //下一个元素从 1 开始重新报数
}
else
i++; //报数编号与出列编号不同时,继续报数
if(a[i]==1) {
j=j+a[i]; if(j==m) {
j=0; a[i]=0; k++; cout<<i<<" "; }
} if(i==n)
i=0; }
}
七、实验心得 李孟琪:该实验利用数组实现线性表,算法简便,但产生很多不必要的消耗,下 一步可以尝试采用单链表,双链表实现该问题。 李春阳:通过利用链表编写约瑟夫环,进一步掌握了约瑟夫环的原理,加深了对 链表使用的理解 雷鹤:这次实验遇到的最大问题是拘泥于基本要求中的利用数组来实现线性表, 并用线性表来实现约瑟夫环问题,在尝试用链表实现后问题变得简单了些;在插 入元素这一步费不少时间,头尾节点的移动关系也需要理解
四、详细设计
程序代码:
#include <iostream>
using namespace std;
main()
{
int n,m,k,j;
//n 为总人数,m 为出列编号
cin>>n>>m;
int *listArray=new int[n]; //将 n 个人放在大小为 n 的数组中
约瑟夫环(顺序表)
test:下标值。本次报数完之后,下一个 值为本单元中存放的值,即下一个 test =
P[test]
#include <stdio.h>// main(){
int i, p[17],test, head; // 设置循环控制变量、数组及两个数组下标指针 for(i=0;i<16;i++
p[i]=i+1; //存放下一个单元的下标值(位置号) p[16]=0; test=0; //起始位置(从哪开始报数) while(test!=p[test]){ // 位置号和该位置的下一位置相同时退出
(位置号) i + 1,即 P[ i ] = i + 1;到最后一个人的时候就循 环到第一个人,设置P[16] =0。
3
P[i] 1 2 3 4 5 6 7 8
0
i
01 2 34 5 6 7
16
head:下标值。由于报到3的倍数的 人要退出,为了保持循环顺序表的形 式,要改变退出的人的前一个的值, 例如:要改变P[1]的值使之变为3。 head用来标识报数的前一个人的下标 值,当报到3的倍数的人退出时,改 变前一个人的单元值为报到3的倍数 的人的单元值,使之保持循环顺序表 的形式。如此下去,当只有一个人的 时候test=p[test]。
指针指向的下一位置
test=p[head]; //记住出列位置
} printf(″\n%5d″,test); // 最后一个出列位置
}
❖ 例:设计一个程序求约瑟夫环的出列顺序。约瑟夫 (Joseph)问题:有17个人按顺时针方向围坐一周 (编号为0~16),从第0号的人开始从1报数,凡报到 3的倍数的人离开圈子,一直数下去,直到最后只剩下 一个人为止,问此人原来的位置是多少号?
(完整word版)C语言约瑟夫环问题
实验一:约瑟夫环问题一.实验目的:要求设计一个程序模拟约瑟夫环问题过程,求出出列编号序列。
二.实验内容:约瑟夫环问题:设编号为1,2,3,……,n的n(n>0)个人按顺时针方向围坐一圈,每个人持有一个正整数密码.开始时任选一个正整数做为报数上限m,从第一个人开始顺时针方向自1起顺序报数,报到m是停止报数,报m的人出列,将他的密码作为新的m值,从他的下一个人开始重新从1报数。
如此下去,直到所有人全部出列为止。
令n最大值取30。
要求设计一个程序模拟此过程,求出出列编号序列。
三.实验过程:用一个不带头结点的循环链表来处理Josephu 问题:先构成一个有n个结点的单循环链表,然后由k结点起从1开始计数,计到m时,对应结点从链表中删除,把被删除结点的密码作为新的m值,然后再从被删除结点的下一个结点又从1开始计数,直到最后一个结点从链表中删除算法结束。
#include〈stdio.h>#include<stdlib。
h〉#define MAX_NODE_NUM 30#define TRUE 1#define FALSE 0typedef struct NodeType{ int number;int password;struct NodeType *next;}NodeType;/*创建单向循环链表*/static void CreaList(NodeType **,const int);/*运行”约瑟夫环"问题*/static void StatGame(NodeType **, int);/* 打印循环链表*/static void PrntList(const NodeType *);/*得到一个结点*/static NodeType *GetNode(const int, const int);/*测试链表是否为空,空为TRUE,非空为FALSE */ static unsigned EmptyList(const NodeType *);int main(void){ int n,m;NodeType *pHead=NULL;while(1){printf("输入总的人数n(〈=%d):”,MAX_NODE_NUM);scanf("%d",&n);printf(”初始循环的密码为:”);scanf(”%d”,&m);if(n>MAX_NODE_NUM){printf("数字太大,请重新输入!\n");continue;}elsebreak;}CreaList(&pHead,n);printf("\n打印出原始每个结点的序列号和密码\n"); PrntList(pHead);printf(”\n最终每个结点退出的序列号和密码\n");StatGame(&pHead,m);return 0;}static void CreaList(NodeType **ppHead, const int n) {int i,iCipher;NodeType *pNew, *pCur;for(i=1;i〈=n;i++){printf("第%d个人的密码为:",i);scanf(”%d",&iCipher);pNew=GetNode(i,iCipher);if(*ppHead==NULL){*ppHead=pCur=pNew;pCur->next=*ppHead;}else{pNew-〉next=pCur—〉next;pCur-〉next=pNew;pCur=pNew;}}printf(”已完成结点初始化!\n”);}static void StatGame(NodeType **ppHead, int iCipher){int iCounter,iFlag=1,i=1;NodeType *pPrv, *pCur,*pDel;pPrv=pCur=*ppHead;while(pPrv—〉next!=*ppHead)pPrv=pPrv->next;while(iFlag){for(iCounter=1;iCounter〈iCipher;iCounter++){pPrv=pCur;pCur=pCur->next;}if(pPrv==pCur)iFlag=0;pDel=pCur;pPrv-〉next=pCur-〉next;pCur=pCur-〉next;iCipher=pDel—〉password;printf("第%d个退出的是序列号为%d的人,其密码为:%d\n",i, pDel—>number,pDel-〉password);free(pDel);++i;}*ppHead=NULL;}static void PrntList(const NodeType *pHead){const NodeType *pCur=pHead;if (EmptyList(pHead))return;do{printf("第%d 个人,密码:%d\n”,pCur->number,pCur->password);pCur=pCur—〉next;} while (pCur!=pHead);}static NodeType *GetNode(const int iId,const int iCipher){NodeType *pNew;pNew=(NodeType *)malloc(sizeof(NodeType));if(!pNew){printf("错误,内存不足!\n”);exit(—1);}pNew—>number=iId;pNew-〉password=iCipher;pNew—>next=NULL;return pNew;}static unsigned EmptyList(const NodeType *pHead){if(!pHead){printf(”列表为空!\n”);return TRUE;}return FALSE;}。
约瑟夫问题(循环链表)
约瑟夫问题(循环链表)问题描述:约瑟夫是犹太军队的⼀个将军,在反抗罗马的起义中,他所率领的军队被击溃,只剩下残余的部队40余⼈,他们都是宁死不屈的⼈,所以不愿投降做叛徒。
⼀群⼈表决说要死,所以⽤⼀种策略来先后杀死所有⼈。
于是约瑟夫建议:每次由其他两⼈⼀起杀死⼀个⼈,⽽被杀的⼈的先后顺序是由抽签决定的,约瑟夫有预谋地抽到了最后⼀签,在杀了除了他和剩余那个⼈之外的最后⼀⼈,他劝服了另外⼀个没死的⼈投降了罗马。
1//利⽤循环链表模拟约瑟夫问题,把41个⼈⾃杀的顺序编号输出2 #include<iostream>3 #include<malloc.h>4 #include<string.h>5 #include<stdlib.h>6 #include<stdio.h>7using namespace std;89 typedef struct Node{10int data;11struct Node *next;12 }Node,*LinkList;1314void InitList(LinkList &L){15 L = (LinkList)malloc(sizeof(Node));16if(!L)17 exit(0);18 L->next = NULL;19 }2021 LinkList CreatList(LinkList &L, int n){//尾插法创建单链表22 LinkList r,p;23 r = L;24for(int i = 1; i <= n; i++){25 p = (LinkList)malloc(sizeof(Node));26 p->data = i;27 r->next = p;28 r = p;29 }30 r->next = NULL;31 p->next = L->next;//尾部指向头部,循环链表32return p->next;//返回头结点的头指针(构成循环)33 }3435int main(){36int n = 41;37int m = 3;38 LinkList L,p;39 InitList(L);40 p = CreatList(L,n);41 LinkList temp;42 m %= n;43while(p != p->next){44for(int i = 1;i < m-1; i++){45 p = p->next;46 }47 printf("%d->",p->next->data);48//删除结点49//p->next->next;50 temp = p->next;51 p->next = temp->next;52free(temp);53 p = p->next;54 }55 cout<<p->data;56return0;57 }运⾏结果:关于约瑟夫问题的题⽬:n个⼈围成⼀个圈,每个⼈分别标注为1、2、...、n,要求从1号从1开始报数,报到k的⼈出圈,接着下⼀个⼈⼜从1开始报数,如此循环,直到只剩最后⼀个⼈时,该⼈即为胜利者。
实习报告一:用顺序表实现约瑟夫环
实习报告一:用顺序表实现约瑟夫环题目:用顺序表和循环链表实现约瑟夫环的出列顺序。
班级:06计算机B班姓名:学号:0621121005 完成日期:2008-6-14顺序表实现一、需求分析1.本程序中,需要输入的内容均为整型数,输入完成后以“回车符”作为结束标志。
2.程序以用户和计算机的对话方式执行,即在计算机终端上显示“提示信息”之后,由用户在键盘上输入程序的相关数据。
3.程序执行的命令包括:(1)请输入原始密码m和人数n(n不大于30);(2)请依次输入每个人的密码;(3)屏幕上将依次显示出列者的编号;(4)结束。
4.测试数据:m的初值为20;n=7,7个人的密码依次为:3,1,7,2,4,8,4。
实验结果应该为:6,1,4,7,2,3,5。
二、概要设计要用顺序链表实现上述的功能,需要一个抽象数据类型:顺序表。
1.顺序表数据类型定义:ADT sqlist {数据对象:D={ a i |a i∈elemset,i=1,2,…,n, n≥0}数据关系:R1={ <a i-1,a i> | a i-1,a i ∈D,i=2,3,…,n}基本操作:initlist_sq(&l)操作结果:构造一个空的顺序表l。
}ADT sqlist2.本程序包含一个模块:主程序模块:顺序表抽象数据类型;Int main(){接受命令;处理命令;}三、详细设计1.源程序#include<iostream>using namespace std;#define maxlen 30typedef int elemtype;typedef struct{elemtype elem[maxlen];int length;}sqlist;sqlist joseph;void initlist_sq(sqlist &l){l.length=0;}void jos(int m, int n){cout<<"请依次输入"<<n<<"个密码:";for(;joseph.length<n;joseph.length++)cin>>joseph.elem[joseph.length];//赋密码值cout<<"出列顺序为:";int i=-1;//i为数组下标(下一值为0)for(int k=0;k<n;k++){for(int j=0;j<m;){i=(i+1)%n;if(joseph.elem[i]!=0)j++;}cout<<i+1<<" ";m=joseph.elem[i];joseph.elem[i]=0;}cout<<endl;}void main(){int m,n;//m为密码,n为小孩个数cout<<"请输入初始密码m和人数n(n不大于30):";do{cin>>m>>n;if(n<1||n>30) cout<<"人数不合法,请重输(n不大于30):"<<endl;}while(n<1||n>30);initlist_sq(joseph);// 初始化线性表jos(m,n);}2.函数调用关系:main→jos。
C语言的循环链表和约瑟夫环
C语言的循环链表和约瑟夫环C语言的循环链表和约瑟夫环约瑟夫问题)是一个数学的应用问题,对于学习C语言四非常挺有帮助的,下面是店铺为大家搜集整理出来的有关于C语言的循环链表和约瑟夫环,一起了解下吧!循环链表的实现单链表只有向后结点,当单链表的尾链表不指向NULL,而是指向头结点时候,形成了一个环,成为单循环链表,简称循环链表。
当它是空表,向后结点就只想了自己,这也是它与单链表的主要差异,判断node->next是否等于head。
代码实现分为四部分:1. 初始化2. 插入3. 删除4. 定位寻找代码实现:1 2 3 4 5 6 7 8 9 1 0 1 1 1 2 1 3 1void ListInit(Node *pNode){int item;Node *temp,*target;cout<<"输入0完成初始化"<<endl; cin="">>item;if(!item)return ;if(!(pNode)){ //当空表的时候,head==NULLpNode = new Node ;if(!(pNode))exit(0);//未成功申请pNode->data = item;pNode->next = pNode;}else{//for(target = pNode;target->next!=pNode;target = target->next);4 15 16 17 18 19 2 0 2 1 2 2 2 3 2 4 2 5 2 6 2 7 2 8 2 9 3 0 3 1 3 2 3 3 3 4 3 5 3temp = new Node;if(!(temp))exit(0);temp->data = item;temp->next = pNode;target->next = temp;}}}void ListInsert(Node *pNode,int i){ //参数是首节点和插入位置Node *temp;Node *target;int item;cout<<"输入您要插入的值:"<<endl; cin="">>item;if(i==1){temp = new Node;if(!temp)exit(0);temp->data = item;for(target=pNode;target->next != pNode;target = target->next);temp->next = pNode;target->next = temp;pNode = temp;}else{target = pNode;for (int j=1;j<i-1;++j) target="target-">next;temp = new Node;if(!temp)exit(0);temp->data = item;temp->next = target->next;target->next = temp;}}void ListDelete(Node *pNode,int i){Node *target,*temp;if(i==1){for(target=pNode;target->next!=pNode;target=target ->next);temp = pNode;//保存一下要删除的首节点 ,一会便于释放6 37 38 39 4 0 4 1 4 2 4 3 4 4 4 5 4 6 4 7 4 8 4 9 5 0 5 1 5 2 5 3 5 4 5 5 5 6 5 7 5pNode = pNode->next;target->next = pNode;temp;}else{target = pNode;for(int j=1;j<i-1;++j) target="target-">next;temp = target->next;//要释放的nodetarget->next = target->next->next;temp;}}int ListSearch(Node *pNode,int elem){ //查询并返回结点所在的位置Node *target;int i=1;for(target = pNode;target->data!=elem && target->next!= pNode;++i)target = target->next;if(target->next == pNode && target->data!=elem)return 0;else return i;}</i-1;++j)></i-1;++j)></endl;></endl;>5 96 0 6 1 6 2 6 3 6 4 6 5 6 6 67 68 69 7 0 7 1 7 2 7 3 7 4 7 5 7 6 7 7 7 8 7 9 8约瑟夫问题约瑟夫环(约瑟夫问题)是一个数学的'应用问题:已知n个人(以编号1,2,3…n分别表示)围坐在一张圆桌周围。
顺序表实现约瑟夫环的问题,C语言
顺序表实现约瑟夫环的问题,C语言计算机科学与工程学院《算法与数据结构》试验报告[一] 专业班级 10级计算机工程02 试验地点计算机大楼计工教研室学生学号 1005080222 指导教师蔡琼学生姓名肖宇博试验时间 2012-2-29试验项目算法与数据结构试验类别基础性() 设计性() 综合性(?) 其它( )(1)掌握用VC++上机调试线性表的基本方法; 试(2)掌握顺序表的存储结构以及基本运算的实现。
验目的及要求成绩评定表类别评分标准分值得分合计积极出勤、遵守纪律上机表现 30分主动完成设计任务程序代码规范、功能正确程序与报告 70分报告详实完整、体现收获备注:评阅教师:日期: 年月日计算机科学与工程学院试验内容一、实验目的和要求1、实验目的:(1)掌握用VC++上机调试线性表的基本方法;(2)掌握顺序表的存储结构以及基本运算的实现。
2、实验内容约瑟夫环问题:设编号为1,2,3,……,n的n(n>0)个人按顺时针方向围坐一圈,m为任意一个正整数。
从第一个人开始顺时针方向自1起顺序报数,报到m时停止并且报m的人出列,再从他的下一个人开始重新从1报数,报到m时停止并且报m的人出列。
如此下去,直到所有人全部出列为止。
要求设计一个程序模拟此过程,对任意给定的m和n,求出出列编号序列。
3、实验要求:用顺序表实现。
二、设计分析根据实验要求,采用顺序表来完成本次实验。
实验中定义了两个顺序表,一个用来存储n个人的序号,另一个用来存储n个人的出队顺序及序号。
程序中充分考虑了如果出队的元素大于队列的元素个数时应该有的情况,如果出现这样的错误就提示~否则继续出队~三、源程序代码#include<stdio.h>#include<stdlib.h>#define MAXSIZE 10 // 宏替换最大值typedef struct{int data[MAXSIZE];int length;}Sqlist;void CreatList(Sqlist *&L,int a[],int n) //创建顺序表{L=(Sqlist *)malloc(sizeof(Sqlist));for(int i=0;i<n;i++){L->data[i]=a[i];}L->length=n;}void InitList(Sqlist *&L) //初始化顺序表{2 《算法与数据结构》试验报告计算机科学与工程学院L=(Sqlist *)malloc(sizeof(Sqlist));L->length=0;}void DestoryList(Sqlist *&L) //释放顺序表空间{free(L);}void josephus(Sqlist *&L) //约瑟夫环的核心代码{int t=0;int m=0;printf("请输入数到几个人出来");printf("\n");scanf("%d",&m);if(m>L->length){printf("没有这么多人呀~?(?_?)?");}else{printf("出列顺序为:");for(int q=L->length;q>=1;q--){t=(t+m-1)%q;printf("\n");printf("\t%d\t",L->data[t]);for(int j=t+1;j<=q-1;j++)L->data[j-1]=L->data[j];}printf("\n");}}void main(){Sqlist *s;InitList(s);int a[MAXSIZE];int n=0;printf("请键入要输入几个数"); printf("\n");scanf("%d",&n);for(int i=0;i<n;i++)3 《算法与数据结构》试验报告计算机科学与工程学院{a[i]=i+1;}CreatList(s,a,n);josephus(s);DestoryList(s);printf("\n");}四、测试用例(尽量覆盖所有分支) 1.当输入1,2,3,4。
C语言用数组解决约瑟夫环问题
C语言用数组解决约瑟夫环问题C语言用数组解决约瑟夫环问题问题说明:在罗马人占领乔塔帕特后,39 个犹太人与约瑟夫及他的朋友躲到一个洞中,大家决定宁愿自杀也不要被敌人抓到,于是确定了一个自杀方式,41个人排成一个圆圈,由第1个人开始报数,每报数到第3人该人就必须自杀,然后再由下一个重新报数,直到所有人都自杀身亡为止。
然而约瑟夫和他的朋友并不想死去,那么他应该怎样安排他和他的朋友的位置,才能逃脱这场死亡游戏呢?有N个编号为1~N的`人围成一圈,现在每隔两个人(比如:1、4 之间隔了2、3)就将一个人淘汰出去,问最后剩下的是编号为几的人?算法代码如下:#include#includeint main(void){int people_count = 0;int *peoples = NULL;printf("please input people number: ");scanf("%d", &people_count);if (people_count < 2){printf("can't do Joseph\n");}peoples = (int *)calloc(people_count, sizeof(int));int i;for(i = 0; i < people_count; i++){peoples[i] = i+1;}i = 0;int j = 0;int rest = people_count;while(rest){if (i >= people_count){i %= people_count;}if (peoples[i] == 0){i++;continue;}if (j++ % 3 ==0 && rest > 1){printf("kill people NO. %d\n", peoples[i]); peoples[i] = 0;rest--;}else if (rest==1){printf("NO. %d is alive\n", peoples[i]); rest--;}i++;}system("pause");return 0;}。
C语言数组实现约瑟夫环问题,以及对其进行时间复杂度分析
C 语⾔数组实现约瑟夫环问题,以及对其进⾏时间复杂度分析尝试表达本⼈试着去表达约瑟夫环问题:⼀群⼈围成⼀个圈,作这样的⼀个游戏,选定⼀个⼈作起点以及数数的⽅向,这个⼈先数1,到下⼀个⼈数2,直到数到游戏规则约定那个数的⼈,⽐如是3,数到3的那个⼈就离开这个游戏;按这样的规则,剩下⼀个⼈,游戏就结束,这个⼈就为赢家。
(读者可以试着表达,不认同,直接忽略)抽象分析这个⼈就是⼀个数据个体,数据结点,数据元素。
上⾯产⽣的数据结构为:单⽅向循环的链。
可以⽤链表实现,也可以⽤数组来实现。
链表到数组的迁移⼈(数据元素、数据结点、数据个体)结点关系(结构关系结点移动)范型“指针”定义:能够定位到下⼀个结点(变)“指针“移到下⼀个结点拿到下⼀个结点的”指针“即可,⼀般都有作“移动”变量,移动变量变,就相当于移动。
删除结点数组连续的数组元素(基本数据类型,机构体)数组元素⾥⾯保存有下个结点元素的数组元素下标position 。
arrayname 固定的,只要给出position ,就可以算是定位到数组元素≈poisiton []move =array[move]元素内容 = -1(数组的⼤⼩固定)链表离散的链表结点(结构体)结构体⾥⾯保存有下⼀个结点的指针node* nextpoiter 直接定位到结点,在结合常员变量,就可以拿到数据=poiter ->move = move ->next销毁画图分析:代码实现:#include<stdio.h>#include<stdlib.h>/*Function:遍历数组实现的约瑟夫环。
traverse_joseph_circle_array*param:int[] array,int tail*return: void* 假设是⽤数组实现的约瑟夫环链⼀定存在。
* */void traverse_joseph_circle_array (int array[], int tail ){//数组保存的是下个结点的“指针”,只不过这个指针要通过array 才能够拿到结点的元素,因为array 是固定的,只要变换指针就能够变换结点。
约瑟夫环的数组顺序表实现
约瑟夫环的数组顺序表实现Sqlist.h#define InitSize 100 //线性表才能出空间的初始分配量#define MaxNum 100 //假设线性表最大元素为100 typedef int ElemType;typedef struct{ ElemType data[MaxNum];int length;}SqList;void PlayList(SqList&,int&,int,ElemType &);app.h#include <stdio.h>#include <stdlib.h>#include <malloc.h>#include "sqlist.h"void main(){SqList L;int k,m,i;ElemType e;printf("请输入人数n(n最大值为100):\n");scanf("%d",&L.length);if(L.length<1||L.length>MaxNum)printf("n值出错!\n");else{printf("正在创建顺序表数组模型......\n");for(i=0;i<L.length;i++)L.data[i]=i+1;printf("请输入开始编号k和第m个终止报号m:\n"); scanf("%d %d",&k,&m);if(k<1||k>L.length)printf("k值出错!\n");else{while(L.length!=0){PlayList(L,k,m,e);printf("编号%d出列\t",e);}}}}Sq.h#include <stdio.h>1#include <stdlib.h>#include <malloc.h>#include "sqlist.h"void PlayList(SqList &L,int &k,int m,ElemType &e){int i,j;k--;i=(k+m-1)%(L.length);e=L.data[i];for(j=i;j<L.length-1;j++) //将data[i]之后的元素前移L.data[j]=L.data[j+1];printf("出列成功!\n");L.length--;k=i+1;}245。
详解约瑟夫环问题及其相关的C语言算法实现
详解约瑟夫环问题及其相关的C语⾔算法实现约瑟夫环问题N个⼈围成⼀圈顺序编号,从1号开始按1、2、3......顺序报数,报p者退出圈外,其余的⼈再从1、2、3开始报数,报p的⼈再退出圈外,以此类推。
请按退出顺序输出每个退出⼈的原序号算法思想⽤数学归纳法递推。
⽆论是⽤链表实现还是⽤数组实现都有⼀个共同点:要模拟整个游戏过程,不仅程序写起来⽐较烦,⽽且时间复杂度⾼达O(nm),若nm⾮常⼤,⽆法在短时间内计算出结果。
我们注意到原问题仅仅是要求出最后的胜利者的序号,⽽不是要读者模拟整个过程。
因此如果要追求效率,就要打破常规,实施⼀点数学策略。
为了讨论⽅便,先把问题稍微改变⼀下,并不影响原意:问题描述:n个⼈(编号0~(n-1)),从0开始报数,报到(m-1)的退出,剩下的⼈继续从0开始报数。
求胜利者的编号。
我们知道第⼀个⼈(编号⼀定是m%n-1) 出列之后,剩下的n-1个⼈组成了⼀个新的约瑟夫环(以编号为k=m%n的⼈开始):k k+1 k+2 ... n-2, n-1, 0, 1, 2, ... k-2并且从k开始报0。
现在我们把他们的编号做⼀下转换:k --> 0k+1 --> 1k+2 --> 2......k-2 --> n-2k-1 --> n-1变换后就完完全全成为了(n-1)个⼈报数的⼦问题,假如我们知道这个⼦问题的解:例如x是最终的胜利者,那么根据上⾯这个表把这个x变回去不刚好就是n个⼈情况的解吗变回去的公式很简单,相信⼤家都可以推出来:x'=(x+k)%n如何知道(n-1)个⼈报数的问题的解?对,只要知道(n-2)个⼈的解就⾏了。
(n-2)个⼈的解呢?当然是先求(n-3)的情况——这显然就是⼀个倒推问题!好了,思路出来了,下⾯写递推公式:令f[i]表⽰i个⼈玩游戏报m退出最后胜利者的编号,最后的结果⾃然是f[n]递推公式f[1]=0;f[i]=(f[i-1]+m)%i; (i>1)实现⽅法⼀、循环链表建⽴⼀个有N个元素的循环链表,然后从链表头开始遍历并计数,如果基数i == m,则踢出该元素,继续循环,直到当前元素与下⼀个元素相同时退出循环#include <stdio.h>#include <stdlib.h>#include <string.h>typedef struct lnode{int pos;struct lnode *next;} lnode;/*** 构建循环链表&&循环遍历*/void create_ring(lnode **root, int loc, int n){lnode *pre, *current, *new;current = *root;pre = NULL;while (current != NULL) {pre = current;current = current->next;}new = (lnode *)malloc(sizeof(lnode));new->pos = loc;new->next = current;if (pre == NULL) {*root = new;} else {pre->next = new;}// 循环链表if (loc == n) {new->next = *root;}}/*** 约瑟夫环*/void kickoff_ring(lnode *head, int p){int i;lnode *pre, *pcur;pre = pcur = head;while (pcur->next != pcur) {for (i = 1; i < p; i ++) {pre = pcur;pcur = pcur->next;}printf("%d ", pcur->pos);pre->next = pcur->next;free(pcur);pcur = pre->next;}printf("%d\n", pcur->pos);free(pcur);}void print_ring(lnode *head){lnode *cur;cur = head;while (cur->next != head) {printf("%d ", cur->pos);cur = cur->next;}printf("%d\n", cur->pos);}int main(){int i, p, n;lnode *head;while (scanf("%d %d", &n, &p) != EOF) { // 构建循环链表for (i = 1, head = NULL; i <= n; i ++) create_ring(&head, i, n);// 约瑟夫环if (p != 1)kickoff_ring(head, p);elseprint_ring(head);}return 0;}/************************************************************** Problem: 1188User: wangzhengyiLanguage: CResult: AcceptedTime:110 msMemory:912 kb****************************************************************/⼆、数组模拟思想跟循环链表类似,少了构建循环链表的过程#include <stdio.h>#include <stdlib.h>int main(){int i, index, p, n, remain, delete[3001], flag[3001] = {0};while (scanf("%d %d", &n, &p) != EOF) {remain = n;index = 0;while (remain >= 1) {for (i = 0; i < n; i ++) {if (flag[i] == 0) {// 报数index ++;// 报p者退出圈外if (index == p) {// 退出圈外flag[i] = 1;// 重新报数index = 0;delete[remain - 1] = i + 1;remain --;}}}}// 输出每个退出⼈的序号for (i = n - 1; i >= 0; i --) {if (i == 0) {printf("%d\n", delete[i]);} else {printf("%d ", delete[i]);}}}return 0;}三、数学推导#include <stdio.h>int main(void){int i, n, m, last;while (scanf("%d", &n) != EOF && n != 0) {// 接收报数scanf("%d", &m);// 约瑟夫环问题for (i = 2, last = 0; i <= n; i ++) { last = (last + m) % i;}printf("%d\n", last + 1);}return 0;}。
用顺序表解决约瑟夫环问题
⽤顺序表解决约瑟夫环问题⼀、实验题⽬:约瑟夫环问题:设编号为1,2,3,……,n的n(n>0)个⼈按顺时针⽅向围坐⼀圈,m为任意⼀个正整数。
从第⼀个⼈开始顺时针⽅向⾃1起顺序报数,报到m时停⽌并且报m的⼈出列,再从他的下⼀个⼈开始重新从1报数,报到m时停⽌并且报m的⼈出列。
如此下去,直到所有⼈全部出列为⽌。
要求设计⼀个程序模拟此过程,对任意给定的m和n,求出出列编号序列。
实验要求:⽤顺序表实现。
⼆、设计分析:⾸先创建了⼀个顺序表,并且⽤数组存每个⼈的编号,出列的时候将此编号置为0,代表此位置的⼈已经出列,循环查询编号不为0的元素,并⽤变量j记下当前是第⼏个⼈,当j==m的时候,代表此位置是第m个⼈,输出并将编号置为0,⽤k记录出列⼈的下⼀位的索引,并将数组长度-1,再进⾏新⼀轮的循环,直到所有⼈都出列。
三、程序代码:#include<iostream>#include<cstdlib>using namespace std;const int MaxSize=100;typedef struct Node{int data[MaxSize];int length;}List;void CreateList(List *&L,int n){L=(List *)malloc(sizeof(List*));for(int i=1;i<=n;i++){L->data[i]=i;}L->length=n;}void DispList(List *&L,int m){int len=L->length;int j=0,k=1;while(L->length){for(int i=1;i<=len;i++){if(L->data[k]){j++;}if(j==m){cout<<L->data[k]<<" ";L->data[k]=0;L->length--;j=0;k=(k+1)%(len+1)?(k+1)%(len+1):1;break;}k=(k+1)%(len+1)?(k+1)%(len+1):1;}}}int main(){int m,n;cin>>m>>n;List *L;CreateList(L,n);DispList(L,m);return 0;}。
- 1、下载文档前请自行甄别文档内容的完整性,平台不提供额外的编辑、内容补充、找答案等附加服务。
- 2、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
- 3、如文档侵犯您的权益,请联系客服反馈,我们会尽快为您处理(人工客服工作时间:9:00-18:30)。
这次的设计让我学到了不少的东西,而且了解到编程在现今诸多行业中应用的重要性以及今后的发展,可以说是受益匪浅,为今后开发相关系统奠定了坚实的理论基础和总结了宝贵的开发经验。
for(int i=0;i<n;i++)
{
L->data[i]=a[i];
}
L->length=n;
}
void InitList(Sqlist G&L)//初始化顺序表
{
L=(Sqlist G)malloc(sizeof(Sqlist));
L->length=0;
}
void DestorPList(Sqlist G&L)//释放顺序表空间
4.当输入要出列的元素大于队列里的元素,这将会提示错误如图:
5.当你的输入出队的序列数有误时将会提示错误
6.当你的要输入的数大于定义的最大值时提示错误如图:
7.当你的要输入的数小于定义的最大值时提示错误如图:
五、实验总结
先后学习了C/C++,对编程语言基本上有一些了解,但在数据结构试验程序设计过程中还是学到了很多。
程序运行后,开始考虑各种BUG,比如输入的数大于数组定义的最大值的时候抑或是数组的数小于应该输入的最小值(比如0),比如输入的要出列的元素大于队列中已有的元素抑或是小于数组中应该出现的元素,比如一些错误输入等等之内的BUG都考虑之后的问题。
然后思考与反思后,发现程序还是有美中不足的地方,算法的核心存在一些不足,比如依次从后往前挪动一个元素的时候存在一些效率上的问题,当元素较多时,效率不高!考虑到可以采用标记法,把出队元素标记为0,以后的出队的时候跳过0,而不是进行挪动,这样程序的效率就大大提高了!
经过两天的设计,在不断翻阅以前资料的情况下,有针对性的复习了C/C++中指针、循环的相关理论知识和vc6.0的基础知识和应用技巧,最后比较成功的完成了本次的设计。
本次设计是运用已学的线性表中顺序表的相关内容,由于以前的指针方面知识没有学好,刚开始时有些措手不及,尤其是运用指针申请动态内存,遇到了不小的麻烦,程序检查时没有错误,但运行不了,经过仔细的思考,终于发现了问题所在,特别高兴。
#include<stdlib.h>
#define MAGSIZE 10//宏替换最大值
tPpedef struct
{
int data[MAGSIZE];
int length;
}Sqlist;
void CreatList(Sqlist G&L,int a[],int n)//创建顺序表
{
L=(Sqlist G)malloc(sizeof(Sqlist));
}
printf("\n");
}
}
void main()
{
Sqlist Gs;
InitList(s);
int a[MAGSIZE];
int n=0;
printf("请键入要输入几个数");
printf("\n");
scanf("%d",&n);
for(int i=0;i<n;i++)
{
a[i]=i+1;
{
free(L);
}
void josephus(Sqlist G&L)//约瑟夫环的核心代码
{
int t=0;
int m=0;
printf("请输入数到几个人出来");
printf("\n");
scanf("%d",&m);
if(m>L->length)
{
printf("没有这么多人呀!╮(╯_╰)╭");
(2)掌握顺序表的存储结构以及基本运算的实现。
成绩评定表
类别
评分标准
分值
得分
合计
上机表现
积极出勤、遵守纪律
主动完成设计任务
30分
程序与报告
程序代码规范、功能正确
报告详实完整、体现收获
70分
备注:
评阅教师:
日期:年月日
试验内容
一、实验目的和要求
1、实验目的:
(1)掌握用VC++上机调试线性表的基本方法;
}
else
{
printf("出列顺序为:");
for(int q=L->length;q>=1;q--)
{
t=(t+m-1)%q;
printf("\n");
printf("\t%d\t",L->data[t]);
for(int j=t+1;j<=q-1;j++)
L->data[j-1]=L->data[j];
3、实验要求:用顺序表实现。
2、设计分析
根据实验要求,采用顺序表来完成本次实验。
实验中定义了两个顺序表,一个用来存储n个人的序号,另一个用来存储n个人的出队顺序及序号。
程序中充分考虑了如果出队的元素大于队列的元素个数时应该有的情况,如果出现这样的错误就提示!否则继续出队!
3、源程序代码
#include<stdi源自.h>计算机科学与工程学院
《算法与数据结构》试验报告[一]
专业班级
10级计算机工程02
试验地点
计算机大楼计工教研室
学生学号
1005080222
指导教师
蔡琼
学生姓名
肖宇博
试验时间
20GG-2-29
试验项目
算法与数据结构
试验类别
基础性()设计性()综合性(√)其它()
试验目的及要求
(1)掌握用VC++上机调试线性表的基本方法;
}
CreatList(s,a,n);
josephus(s);
DestorPList(s);
printf("\n");
}四、测试用例(尽量覆盖所有分支)
1.当输入1,2,3,4。。。。。。n的这些数字范围以内的话,可以得到正确的结果如图:
2.当输入的n比较大的时候的情况如图:
3.当输入序列少,出对数大时:
(2)掌握顺序表的存储结构以及基本运算的实现。
2、实验内容
约瑟夫环问题:设编号为1,2,3,……,n的n(n>0)个人按顺时针方向围坐一圈,m为任意一个正整数。从第一个人开始顺时针方向自1起顺序报数,报到m时停止并且报m的人出列,再从他的下一个人开始重新从1报数,报到m时停止并且报m的人出列。如此下去,直到所有人全部出列为止。要求设计一个程序模拟此过程,对任意给定的m和n,求出出列编号序列。