当前位置:文档之家› 约瑟夫问题算法及数据结构课程设计报告

约瑟夫问题算法及数据结构课程设计报告

线性表的操作及其应用一、问题描述线性表、队列是一种常用的数据结构,有顺序和链式两种存储结构,在实际中应用十分广泛,而链表又分为单链表和循环链表,队列又分为链式队列和循环队列。

这些数据结构都可用来解决约瑟夫环问题。

约瑟夫环问题是算法设计中的一个经典问题,是顺序编号的一组n个人围坐一圈,从第1个人按一定方向顺序报数,在报到m时该人出列,然后按相同方法继续报数,直到所有人出列。

设计算法求约瑟夫环中人员的出列顺序。

二、基本要求1、选择合适的存储结构,建立线性表;2、利用顺序存储结构求解约瑟夫环问题;3、利用单链表和循环链表分别求解约瑟夫环问题;4、利用队列求解约瑟夫环问题。

三、测试数据约瑟夫环的测试数据为7,报数为1至3。

四、算法思想由于用到四种不同的存储结构,它们的算法思想依次是:1、首先建立一个顺序表模拟整个约瑟夫环,手动输入顺序表长(即参加约瑟夫循环的人数)和循环的次数和表元素。

用已经输出总人数和顺序表长作比较,作为外层循环条件。

并对每一个输出后的元素重新赋值以为标记。

对于每次循环,首先检查顺序表此次是不是我们设立的标记,如果不是则循环次数加1,当达到要求的循环次数时就将循环次数设置为0,输出该元素到屏幕并将总输出元素加1。

每次外循环我们都会移到表的下一个位置,作为新的判断条件,每次报到表尾的时候,我们都将重新设置到表尾,作为下次循环的表元素。

2、首先采用链式循环链表建立整个约瑟夫环,手动输入第一次的循环次数和每个人所持下一个循环次数。

设立判断指针指向表头,并将该指针是否为空作为外层循环条件。

做一个内层循环,将判断指针移动到循环要输出的数,并设立一个前指针指向该指针的前一个位置,输出该元素后,将循环次数重新赋值成该元素。

接着判断前指针和判断指针比较,如果相等说明整个表已经输出完毕,否则将删除该位置的元素。

3、用链式队列建立循环约瑟夫环,手动输入人数,第一次的循环次数和每个人所持下一个循环次数。

并将每一个元素依次入队列,根据第一次循环次数,建立一个for循环,每一次循环都出队列,如果达到要求的循环次数就输出,否则进队列,这样这个数字就出现在队尾。

第一个数输出后,以队列的非空作为循环条件,判断方式如上。

4、用循环队列建立约瑟夫环,将1-7个元素依次进入循环队列,以队列的长度作为与已输出的元素作为判断条件,对每一个输出后的元素重新赋值以为标记。

对于每次循环,首先检查该该位置的元素是不是我们设立的标记-1,如果不是则循环次数加1,将队首指针移到队列的下一个元素,结束此次循环,当达到要求的循环次数时就将重新循环次数设置为0,输出该元素到屏幕并将总输出元素加1。

五、模块划分1、void InitQueue(SqQueue *Q)初始化循环队列2、void DestroyQueue(SqQueue *Q)销毁循环队列3、void ClearQueue(SqQueue *Q)清空循环队列4、int QueueEmpty(SqQueue Q)判断空队列5、int QueueLength(SqQueue Q)求循环队列长度6、void GetHead(SqQueue Q, ElemType *e)取队头元素7、int EnQueue(SqQueue *Q, ElemType e)入队列8、int DeQueue(SqQueue *Q, ElemType *e)出队列9、void QueueTraverse(SqQueue Q)遍历循环队列并输出元素10、void InitQueue(LQueue *Q)初始化队列11、void DestroyQueue(LQueue *Q)销毁队列12、void ClearQueue(LQueue *Q)清空队列13、int QueueEmpty(LQueue Q)判断空队列14、int QueueLength(LQueue Q)求队列长度15、ElemType GetHead(LQueue Q, ElemType *e)取队头元素16、void EnQueue(LQueue *Q, ElemType e)入队列17、void DeQueue(LQueue *Q, ElemType *e)出队列18、void QueueTraverse(LQueue Q)遍历队列并输出元素19、void joseffer(int n)约瑟夫环20、int CreateList(LinkList &L,int n)建立顺序链表21、void josephus_clist(LinkList &L,int m)顺序链表解决约瑟夫环22、void InitList(SqList *L)初始化链表23、void ysf1()链表解决约瑟夫环24、void ysf2()循环链表解决约瑟夫环25、void ysf3(){链式队列解决约瑟夫环问题26、void ysf4()循环队列解决约瑟夫环问题27、void menu()菜单28、int main()主函数六、数据结构//(ADT)typedef int ElemType;/* 定义顺序表类型*/typedef struct{ ElemType *elem;int length;} SqList;/* 定义循环链表类型*/typedef struct LNode{ int num;int code;struct LNode *next;} *LinkList;/* 定义循环队列类型*/typedef struct{ ElemType *base;int front;int rear;} SqQueue;/* 定义链式队列类型*/typedef struct QNode{ ElemType data;struct QNode *next;} QNode,*QueuePtr;typedef struct{ QueuePtr front;QueuePtr rear;} LQueue;七、源程序#include "stdlib.h"#include "stdio.h"#define N 100typedef int ElemType;/* 定义顺序表类型*/typedef struct{ ElemType *elem;int length;} SqList;/* 定义循环链表类型*/typedef struct LNode{ int num;int code;struct LNode *next;} *LinkList;/* 定义循环队列类型*/typedef struct{ ElemType *base;int front;int rear;} SqQueue;/* 定义链式队列类型*/typedef struct QNode{ ElemType data;Struct QNode *next;} QNode,*QueuePtr;typedef struct{ QueuePtr front;QueuePtr rear;} LQueue;/* 初始化循环队列*/void InitQueue(SqQueue *Q){ Q->base=(ElemType*)malloc(N*sizeof(ElemType));Q->front=Q->rear=0; }/* 销毁循环队列*/void DestroyQueue(SqQueue *Q){ free(Q->base); }/* 清空循环队列*/void ClearQueue(SqQueue *Q){ Q->front=Q->rear=0; }/* 判断空队列*/int QueueEmpty(SqQueue Q){ if (Q.front==Q.rear)return 1;elsereturn 0; }/* 求循环队列长度*/int QueueLength(SqQueue Q){ return (Q.rear+N-Q.front)%N; }/* 取队头元素*/void GetHead(SqQueue Q, ElemType *e){ if (Q.front!=Q.rear)*e=Q.base[Q.front];}/* 入队列*/int EnQueue(SqQueue *Q, ElemType e){ if ((Q->rear+1)%N==Q->front)return 0;Q->base[Q->rear]=e;Q->rear=(Q->rear+1)%N;return 1; }/* 出队列*/int DeQueue(SqQueue *Q, ElemType *e){ if (Q->front==Q->rear)return 0;*e=Q->base[Q->front];Q->front=(Q->front+1)%N;return 1; }/* 遍历循环队列并输出元素*/void QueueTraverse(SqQueue Q){ int i;printf("\nQueue: ");if (Q.rear<Q.front) Q.rear=Q.rear+N;for(i=Q.front; i<Q.rear; i++)printf("%d\t",Q.base[i%N]);}/* 初始化队列*/void InitQueue(LQueue *Q){ Q->front=Q->rear=(QueuePtr)malloc(N*sizeof(QNode));if(!(Q->front)) exit(0);Q->front->next=NULL;}/* 销毁队列*/void DestroyQueue(LQueue *Q){ while(Q->front){ Q->rear=Q->front->next;free(Q->front);Q->front=Q->rear;}}/* 清空队列*/void ClearQueue(LQueue *Q){ QueuePtr p;p=Q->front->next;while(p){ Q->front->next=p->next;free(p);Q->rear=Q->front;}}/* 判断空队列*/int QueueEmpty(LQueue Q){ if (Q.front==Q.rear)return 1;elsereturn 0; }/* 求队列长度*/int QueueLength(LQueue Q){ QueuePtr p; int n=0;p=Q.front;while(p!=Q.rear){ n++;p=p->next;}return n;}/* 取队头元素*/ElemType GetHead(LQueue Q, ElemType *e){ if (Q.front!=Q.rear)return Q.front->next->data;else return 0;}/* 入队列*/void EnQueue(LQueue *Q, ElemType e) { QueuePtr p;p=(QueuePtr)malloc(N*sizeof(QNode));if(!p) exit(0);p->data=e;p->next=NULL;Q->rear->next=p;Q->rear=p;}/* 出队列*/void DeQueue(LQueue *Q, ElemType *e) { QueuePtr p;if(Q->front!=Q->rear){ p=Q->front->next;*e=p->data;Q->front->next=p->next;if(Q->rear==p)Q->rear=Q->front;free(p);}}/* 遍历队列并输出元素*/void QueueTraverse(LQueue Q){ QueuePtr p;printf("\nQueue:");p=Q.front->next;while(p){ printf("%d\t",p->data);p=p->next;}}/*约瑟夫环*/void joseffer(int n){ LQueue Q;int i;ElemType x;InitQueue(&Q);for(i=1;i<=n;i++)EnQueue(&Q,i);while(!QueueEmpty(Q)){ for(i=1;i<=3;i++){ DeQueue(&Q,&x);if(i!=3) EnQueue(&Q,x);else printf("%4d",x);}}}/*建立顺序链表*/int CreateList(LinkList &L,int n){ LNode *p,*q;printf("Input %d number:\n",n);L=q=(LinkList)malloc(sizeof(LNode));if(L==NULL || q==NULL)return 0;for(int i=1;i<=n;i++){ p=(LinkList)malloc(sizeof(LNode));scanf("%d",&p->code);p->num=i;if(i==1)L=p;elseq->next=p;q=p;}p->next=L;L=p;return 1;}/*顺序链表解决约瑟夫环*/void josephus_clist(LinkList &L,int m){ int e=m,k;LinkList p,pre,tp;p=L;while(p!=NULL){ for(int j=0;j<e;j++){ pre=p;p=p->next;}e=p->code;k=p->num;printf("The output number is %d\n",e);if(pre!=p){ tp=p;pre->next=p->next;p=p->next;p=pre;free(tp);}else{ free(pre);p=NULL;}}}/*初始化链表*/void InitList(SqList *L){ L->elem=(ElemType*)malloc(N*sizeof(ElemType));L->length=0; }/*链表解决约瑟夫环*/void ysf1(){ SqList L;int m,i,d,k;InitList(&L);printf("元素个数和报到第几出");scanf("%d%d",&L.length,&d);printf("输入元素");for(i=0;i<L.length;i++)scanf("%d",&L.elem[i]);m=0;k=0;i=0;while(m<L.length){if(L.elem[i]!=N)k++;if(k==d){ printf("%3d",L.elem[i]);L.elem[i]=N;k=0;m++;}i++;if(i==L.length) i=0;}}/*循环链表解决约瑟夫环*/void ysf2(){ int m,n;LinkList jos_clist;printf("Input the beginging number:\n");scanf("%d",&m);printf("Input n people:\n");scanf("%d",&n);CreateList(jos_clist,n);josephus_clist(jos_clist,m);}/*链式队列解决约瑟夫环问题*/void ysf3(){ LQueue Q;int i; ElemType x; int n;printf("number:n=");scanf("%d",&n);InitQueue(&Q);for(i=1;i<=n;i++)EnQueue(&Q,i);printf("len:%d\n",QueueLength(Q));while(!QueueEmpty(Q)){ DeQueue(&Q,&x);printf("%d\t",x);}QueueTraverse(Q);joseffer(n);}/*循环队列解决约瑟夫环问题*/void ysf4(){ SqQueue Q; int i,m,k,j;k=0;m=0;InitQueue(&Q);for(i=1; i<=7; i++)EnQueue(&Q,i);j=QueueLength(Q);printf("len=%d",j);QueueTraverse(Q);printf("\nJoseffer:\t");while(m<=QueueLength(Q)){ if(Q.base[Q.front]!=-1){k++;}if(k==3){ printf("%d\t",Q.base[Q.front]);Q.base[Q.front]=-1;k=0;m++;}Q.front=(Q.front+1)%j;}}/*菜单*/void menu(){ int choice;do{printf("\n====================================");printf("\n 主菜单");printf("\n 1.顺序表实现约瑟夫环问题");printf("\n 2.循环链表表实现约瑟夫环问题");printf("\n 3.链式队列实现约瑟夫环问题");printf("\n 4.循环队列实现约瑟夫环问题");printf("\n 5.退出程序");printf("\n====================================");printf("\n 请输入您的选择(1,2,3,4,5) choice=");scanf("%d",&choice);switch(choice){ case 1:ysf1();break;case 2:ysf2();break;case 3:ysf3();break;case 4:ysf4();break;case 5:exit(0);}} while(choice<=5);}/*主函数*/int main(){ menu();System("pause");return 0;}八、测试情况程序的测试结果如下:1、顺序表实现约瑟夫环问题测试结果正确。

相关主题