数据结构课程设计题目1.目的数据结构是研究数据元素之间的逻辑关系的一门课程,以及数据元素及其关系在计算机中的存储表示和对这些数据所施加的运算。
该课程设计的目的是通过课程设计的综合训练,培养分析和编程等实际动手能力,系统掌握数据结构这门课程的主要内容。
2.内容本次课程设计的内容是用单循环链表模拟约瑟夫环问题,循环链表是一种首尾相接链表,其特点是无须增加存储容量,仅对表的链接方式稍作改变,使表处理更加灵活,约瑟夫环问题就是用单循环链表处理的一个实际应用。
通过这个设计实例,了解单链表和单循环链表的相同与不同之处,进一步加深对链表结构类型及链表操作的理解。
约瑟夫环问题的描述是:设编号为1,2,…,n的n个人按顺时针方向围坐一圈,每个人持有一正整数密码。
开始时选择一个正整数作为报数上限m,从第一个人开始顺时针方向自1起顺序报数,报到m时停止报数,报m的人出圈,将他的密码作为新的m值,从他在顺时针方向上的下一个人起重新从1报数。
如此下去,直到所有人都出圈为止。
令n最大值为100。
要求设计一个程序模拟此过程,求出出圈的编号序列。
3.设计:1)对设计内容进行分析2)逻辑设计1、循环链表抽象数据类型定义typedef struct LNode//定义单循环链表中节点的结构 { int num;//编号 int pwd;//passwordstruct LNode *next;//指向下一结点的指针}LNode;2、本程序包含一下几个模块 (1)构造结点模块LNode *createNode(int m_num,int m_pwd) {图2 约瑟夫环原理演示图LNode *p;p=(LNode *)malloc(sizeof(LNode));//生成一个结点p->num=m_num;//把实参赋给相应的数据域p->pwd=m_pwd;p->next=NULL;//指针域为空return p;}(2)创建链表模块void createList(LNode *ppHead,int n)(3)出队处理模块void jose(LNode *ppHead,int m_pwd)(4)约瑟夫环说明输出模块void instruction()(5)菜单模块void menu()(6)主函数模块int main()函数的调用关系图如下:3)具体设计流程:1.主函数图4 主函数数据流程图根据流程图,主函数程序如下:int main(){int n,m,x;LNode *ppHead=NULL;menu();for(;;){printf("\n请选择要执行的操作:");scanf("%d",&x);system("cls");switch(x){case 1:printf("************************************************************* ***\n");printf("约瑟夫环:\n");printf(" 编号为1,2,3,4…,n的n个人按顺时针方向围坐一圈,每人持有一个密\n");printf("码(正整数).一开始任选一个正整数作为报数的上限值m,从第一个人开始\n");printf("按顺时针方向自1开始顺序报数,报到m时停止.报m的人出列,将他的密码\n");printf("m作为新的m值,从他在顺时针方向上的下一人开始重新从1报数,如此下去,\n");printf("直到所有人全部出列为止.编程打印出列顺序.\n");printf("************************************************************* ***\n");main();break;case 2:printf("\n请输入总人数n:");scanf("%d",&n);printf("请输入开始上限数m:");scanf("%d",&m);createList(&ppHead,n);printf("\n");printf("出队顺序:\n");jose(ppHead,m);printf("\n约瑟夫环游戏结束!\n");main();break;case 0:exit(0);default:system("cls");printf("\n您选择的操作有误,请重新选择...\n\n\n");main();}}return 0;}2.链表的创建图5 创建链表函数的数据流程图/*创建单向循环链表ppHead,人数个数为n,并输入每个人的密码值,若建立失败则生成头结点,让cur指向他,若建立成功则插入结点P,cur指向的数据元素为p,后续为"空"的节点,再把P插入循环链表ppHead中*/根据流程图,创建链表函数程序如下:void createList(LNode **ppHead,int n){int i,m_pwd;LNode *p,*cur;//cur:浮标指针for(i=1;i<=n;i++){printf("输入第%d个人的密码:",i);scanf("%d",&m_pwd);//输入持有密码p=createNode(i,m_pwd);//调用构造结点函数if(*ppHead==NULL)//如果头结点为空{*ppHead=cur=p;//生成头结点,让cur指向他cur->next=*ppHead;//cur的指针域指向自身}else//如果不为空,则插入结点{p->next = cur->next;cur->next = p;cur= p;//cur指向新插入结点}}printf("完成创建!\n"); //提示链表创建完成}3.出队处理图6 出队函数的数据流程图/*p指向要删除节点的前一个节点,ppHead指向要删除的节点,使p=ppHead,ppHead再指向要删除节点的下一个节点,使p和ppHead链接,输出p指向节点的编号和密码值,释放ppHead,如此循环,直至把所有节点都打印和删除为止!*/根据流程图,出队函数程序如下:void jose(LNode *ppHead,int m_pwd){int i,j;LNode *p,*p_del;//定义指针变量for(i=1;p!=ppHead;i++){for(j=1;j<m_pwd;++j){p=ppHead;//p赋值为ppHead,p指向要删除结点的前一个结点ppHead=ppHead->next;//ppHead指向下一个元素}p->next = ppHead->next;//p结点与头结点链接i=ppHead->pwd;//i赋值为ppHead->pwdj=ppHead->num;//j赋值为ppHead->num,j为要删除的密码值printf("第%d个人出列,密码:%d\n",j,i);m_pwd=ppHead->pwd;//m_pwd赋值为ppHead->pwdfree(ppHead);//释放头结点ppHead=p->next;//ppHead重新赋值给p->next,即释放前的ppHead->pwd指针//删除报数结点}i=ppHead->pwd;//i赋值为ppHead->pwdj=ppHead->num;//j赋值为ppHead->numprintf("最后一个出列是%d号,密码是:%d\n",j,i);free(ppHead);//释放头结点}4. 约瑟夫环说明模块void instruction(){printf("***********************************************************************\n");printf("** 约瑟夫(Joseph)环: **\n");printf("** 编号为1,2,…,n的n个人按顺时针方向围坐一圈,每人持有一个密码 **\n");printf("** (正整数)。
一开始任选一个正整数作为报数上限值m,从第一个人开始按顺 **\n");printf("** 时针方向自1开始顺序报数,报到m时停止报数。
报m的人出列,将他的密码 **\n");printf("** m作为新的m值,从他在顺时针方向上的下一个人开始重新从1报数,如此下 **\n");printf("** 去,直至所有人全部出列为止。
试设计一个程序求出出列顺序。
**\n");printf("***********************************************************************\n");}5. 菜单模块void menu(){printf("**************************约瑟夫环*****************************\n");printf(" \n");printf(" [1]约瑟夫环问题的阐述\n");printf(" [2]按要求求解约瑟夫环\n");printf(" [0]退出\n");printf("************************** 欢迎使用!****************************\n");}4.实现:程序语言:#include <stdio.h>//输入输出函数头文件#include <stdlib.h>//字符串转短整形函数的头文件//typedef struct LNode//定义单循环链表中节点的结构{int num;//编号int pwd;//密码struct LNode *next;//指向下一结点的指针}LNode;/*构造结点*/LNode *createNode(int m_num,int m_pwd){LNode *p;p=(LNode *)malloc(sizeof(LNode));//生成一个结点p->num=m_num;//把实参赋给相应的数据域p->pwd=m_pwd;p->next=NULL;//指针域为空return p;}/**创建循环链表**/void createList(LNode **ppHead,int n){int i,m_pwd;LNode *p,*cur;//cur:浮标指针for(i=1;i<=n;i++){printf("输入第%d个人的密码:",i);scanf("%d",&m_pwd);//输入持有密码p=createNode(i,m_pwd);//调用构造结点函数if(*ppHead==NULL)//如果头结点为空{*ppHead=cur=p;//生成头结点,让cur指向他cur->next=*ppHead;//cur的指针域指向自身}else//如果不为空,则插入结点{p->next = cur->next;cur->next = p;cur = p;//cur指向新插入结点}}printf("完成创建!\n"); //提示链表创建完成}/*出队处理*/void jose(LNode *ppHead,int m_pwd){/*p指向要删除节点的前一个节点,ppHead指向要删除的节点,使p=ppHead, ppHead再指向要删除节点的下一个节点,使p和ppHead链接,输出p指向节点的编号和密码值,释放ppHead,如此循环,直至把所有节点都打印和删除为止!*/int i,j;LNode *p,*p_del;//定义指针变量for(i=1;p!=ppHead;i++){for(j=1;j<m_pwd;++j){p=ppHead;//p赋值为ppHead,p指向要删除结点的前一个结点ppHead=ppHead->next;//ppHead指向下一个元素}p->next = ppHead->next;//p结点与头结点链接i=ppHead->pwd;//i赋值为ppHead->pwdj=ppHead->num;//j赋值为ppHead->num,j为要删除的密码值printf("第%d个人出列,密码:%d\n",j,i);m_pwd=ppHead->pwd;//m_pwd赋值为ppHead->pwdfree(ppHead);//释放头结点ppHead=p->next;//ppHead重新赋值给p->next,即释放前的ppHead->pwd指针//删除报数结点}i=ppHead->pwd;//i赋值为ppHead->pwdj=ppHead->num;//j赋值为ppHead->numprintf("最后一个出列是%d号,密码是:%d\n",j,i);free(ppHead);//释放头结点}void instruction(){printf("***********************************************************************\n");printf("** 约瑟夫(Joseph)环: **\n");printf("** 编号为1,2,…,n的n个人按顺时针方向围坐一圈,每人持有一个密码 **\n");printf("** (正整数)。