一、课程设计目的与任务《数据结构》课程设计是为训练学生的数据组织能力和提高程序设计能力而设置的增强实践能力的课程。目的:学习数据结构课程,旨在使学生学会分析研究数据对象的特性,学会数据的组织方法,以

一、课程设计目的与任务

《数据结构》课程设计是为训练学生的数据组织能力和提高程序设计能力而设置的增强实践能力的课程。目的:学习数据结构课程,旨在使学生学会分析研究数据对象的特性,学会数据的组织方法,以便选择合适的数据的逻辑结构和存储结构以及相应操作,把现实世界中的问题转换为计算机内部的表示和处理,这就是一个良好的程序设计技能训练的过程。提高学生的程序设计能力、掌握基本知识、基本技能,提高算法设计质量与程序设计素质的培养就是本门课程的课程设计的目的。

任务:根据题目要求,完成算法设计与程序实现,并按规定写出课程设计报告。

二、课程设计的内容与基本要求

设计题目:约瑟夫生死游戏

〔问题描述〕:约瑟夫生死游戏的大意是:30个旅客同乘一条船,因为严重超载,加上风高浪大,危险万分;因此船长告诉乘客,只有将全船一半的旅客投入海中,其余人才能幸免遇难。无奈,大家只得同意这种办法,并议定30个人围成一圈,由第一个人开始,依次报数,数到第9人,便把他投入大海中,然后从他的下一个人数起,数到第9人,再将他投入大海,如此循环,直到剩下15个乘客为止。问哪些位置是将被扔下大海的位置。

〔基本要求〕本游戏的数学建模如下:假设n个旅客排成一个环形,依次顺序编号1,2,…,n。从某个指定的第j号开始,沿环计数,每数到第m个人就让其出列,且从下一个人开始重新计数,继续进行下去。这个过程一直进行到剩下k个旅客为止。

本游戏要求用户输入的内容包括n,m,j,k的值.

本游戏要求输出的内容是包括

1. 离开旅客的序号;

2. 剩余旅客的序号;

〔提示〕根据上面的模型及输入输出参数分析,可以采用循环链表来进行算法实现。

具体要完成的任务是:

   A. 编制完成上述问题的C语言程序、进行程序调试并能得出正确的运行结果。

   B. 写出规范的课程设计报告书;

三、学时分配进度安排

序号

设计内容

所用时间

1

选题及调研

1天

2

功能及算法分析,编写程序

3天

3

调试程序,运行系统

3天

4

程序完成及撰写报告

2天

5

答辩

1天

合    计

2周

四、课程设计考核及评分标准

1.设计报告要求

课程设计报告要求逻辑清晰、层次分明、书写整洁。报告书应包括设计题目、设计思想、系统结构、数据结构说明及模块算法说明、使用说明书、测试结果分析,附录(程序清单)。设计报告须每人一份,独立完成。

2.评分标准

课程设计考核将综合考虑学生的系统设计方案、运行结果、课程设计报告书的质量、态度、考勤、答辩情况等各因素。具体评分标准如下: 

评分标准

分值

(1)设计方案正确,具有可行性、创新性;

20分

(2)系统开发效果较好;

20分

(3)课程设计报告书写规范、质量高;

30分

(4)课程设计答辩时,回答问题正确;

20分

(5)态度认真、刻苦钻研、遵守纪律;

10分

总分

100分

   注:成绩等级:优(90分—100分)、良(80分—89分)、中(70分—79分)、及格(60分—69分)、60分以下为不及格。

五、指导时间

周次

星期一

星期二

星期三

星期四

星期五

第16周

第3-4节

第3-4节

第1-2节

           

周次

星期一

星期二

星期三

星期四

星期五

第17周

第1-4节

第3-4节

第3-4节

第3-4节

第1-4节

                           

目  录

1 设计题目....................................................................... 1

2 设计思想....................................................................... 1

3 系统结构....................................................................... 1

4 数据结构说明和模块算法说明.................................... 1

5 使用说明书................................................................... 2

6 运行结果....................................................................... 2

7 测试过程及结果分析.................................................... 2

8 附录:源程序清单....................................................... 2

课程设计成绩评定表....................................................... 3

1.设计题目

约瑟夫问题

2.设计思想

结构分析:由于需要不断删除元素,顺序表删除元素时间开销过大,而且顺序访问到最后会出现越界问题,但设置循环链表可避免此问题,且链表删除元素时间复杂度为O(1),因此结构上选择链表

核心功能设计思路:核心功能即删除元素的功能,由题可知删除元素个数往往是过大的,所以利用递归调用删除函数来实现

实现思路:

1.设置链表

2.初始化链表

3.用户输入游戏总人数,再输入从第几人开始游戏,每隔几人使其出列,直至所剩多少人,每次数据要进行逻辑判断,以防出现逻辑错误

4.然后通过尾插法创建链表,创建链表时需要将链表设置成循环链表

5.将链表当前所指位置调整为从第几个人开始的位置,以方便删除函数的设计

6.调用删除函数,每次删除一个元素,所剩元素的总数大于要求的所剩元素数量时,不断删除时不断打印所删除的元素,便不断递归调用自身

7.删除完元素后,此时所剩元素的总数便为输入时的数量,执行打印函数,遍历现在的链表

3.系统结构

执行程序

输入数据

数据非法,return

创建链表

数据合法,初始化

判断数据合法性

判断空间是否分配成功

空间不足,return

将链表所指向的位置调整为正确位置

执行删除函数

打印链表

程序结束

不断打印删除

链表元素数量>k

递归调用

4.数据结构说明和模块算法说明

4.1链表结构:

一个数据域,保存的是当前结点的编号,即本人编号,一个指针域,指向下一个人的结点,通过typedef添加了替换名LinkList

typedef struct LNode{

    ElemType data;//数据域

    struct LNode *next;//指针域

} LinkList;

4.2初始化单链表:

一个参数,即链表,将链表初始化,即L->next为NULL,空间不足时return,即分配失败,初始化结束时输出initList successfully

int InitList(LinkList *L){

    // L=(LinkList *)malloc(sizeof(LinkList));

    if (L==NULL) return 0;//分配失败

    L->next=NULL;//空表,类似于顺序表n=0

    printf("initList successfully\n");

}

4.3尾插法创建链表:

尾插法创建链表,每次都是在链表末端插入元素,该函数有两个参数,一是链表,二是创建多少个元素,创建多少个元素的数值如果低于0则会认为是非法操作,return,用的是while循环,条件是i<=k,i初值为1,同时设置该链表为循环链表,创建结束后打印Created successfully

int FootCreateList(LinkList *L,ElemType k){

    //非法操作或创建失败

    if(k<0) return 0;

    LinkList *temp,*LCopy;

    LCopy=L;

    int i=1;

    while(i<=k){

        temp=(LinkList *)malloc(sizeof(LinkList));

        if(temp==NULL) return 0;

        temp->data=i;

        L->next=temp;

        L=L->next;//链表位置始终保持在最后

        i++;

    }

    L->next=LCopy->next;//尾结点连接头结点后第一个元素结点

    printf("Created successfully\n");

}

4.4打印操作:

该函数两个参数,一是链表,二是该链表长度,会使用一个链表的副本temp来不断遍历,通过for循环来遍历,每次都将打印temp->data,再使其指向下一结点temp=temp->next,打印结束后输出print successfully

void PrintList(LinkList *L,ElemType k){

    LinkList *temp=L;

    temp=temp->next;//从头结点指向首结点

    for (int i = 0; i < k; ++i)

    {

        printf("%d\n",temp->data);

        temp=temp->next;

    }

    printf("print successfully\n");

}

4.5删除操作:

该函数有四个参数,链表,每隔几人删除一个,直至总人数所剩多少人,链表长度(即总人数),通过for循环遍历到将要删除的元素的前一个元素,此时跳出for循环,输出将被删除的元素L->next->data,修改当前元素指向的下一个元素为下下个元素,L->next=L->next->next,此时便删除掉了当前元素

改进方向:未将当前元素下一结点的空间释放,可能会造成空间的浪费,可以添加释放结点语句

ElemType DeleteElemList(LinkList *L,int m,int k,int *n){

    int i=1;

    //从j位往后数m-1位,将要删除元素的前一位

    for (; i <= m-1; ++i)

    {  

        L=L->next;

    }

    // printf("所删元素为:%d \n",L->next->data);//输出目标元素

    L->next=L->next->next;//跳过目标元素

    (*n)=(*n)-1;//长度减1

    //未达到k人时不断递归调用

    if (k<(*n)) DeleteElemList( L, m, k , n);

   

}

4.6主函数:

创建链表,并为其分配空间,再输入游戏总人数,从第几人开始游戏,每隔几个人使其出列,最终剩下多少人,其中设置了数值上的逻辑判断,避免出现逻辑上的错误,首先初始化链表,当输入总人数时便开始判断该人数数量是否有问题,有问题则return,没问题则创建长度为总人数数量的链表,链表数值为升序序列,其次输入从第几个人开始游戏,输入后判断是否符合逻辑,再者输入每隔几人使其出列,输入判断是否负荷逻辑,最后输入游戏剩余人数,同样判断是否符合逻辑,逻辑判断结束后,调整链表所指位置为刚开始指定从第几个人开始的位置,调用删除函数,参数为,该链表,每个几个人使其出列再减一,直至所剩多少人,链表长度(即总人数)

int main()

{

    //n人,从j开始计数,第m个人使其出列,直至所剩k人

    int n,m,j,k;

    LinkList *L;//声明一个指向单链表的带头指针L

    L=(LinkList *)malloc(sizeof(LinkList));

    InitList(L);

    //插入n元素,即n人

    printf("输入n人\n");

    scanf("%d",&n);

    if (n<1){

        printf("非法输入");

        return 0;

    }

    //为链表创建n结点

    FootCreateList(L,n);

    //打印

    // PrintList(L,n);

    printf("从j开始计数\n");

    scanf("%d",&j);

    if (j>n){

        printf("非法输入");

        return 0;

    }

    printf("第m个人使其出列\n");

    scanf("%d",&m);

    if (m>=n){

        printf("非法输入");

        return 0;

    }

    printf("直至所剩k人\n");

    scanf("%d",&k);

    if (k>=n){

        printf("非法输入");

        return 0;

    }

    //调整正确位置到j位

    for (int i = 0; i < j; ++i)

    {  

        L=L->next;//此时temp指到目标位置

    }

    //开始操作

    DeleteElemList(L,m-1,k,&n);

    // printf("最后的n为%d\n",n);

    printf("所剩元素为\n");

    PrintList(L,n);

    return 0;

}

5.使用说明书

游戏步骤:

第一步:输入总人数

第二步:输入从第几个人开始计数

第三步:输入每隔几个人使其出列

第四步:输入直到总人数达到多少人时游戏结束

第五步:等待结果

游戏规则:

1.游戏总人数不允许低于一人

2.从第几个人开始计数,这个人的序号不能超过总人数

3. 每隔几个人使其出列,所隔人数不能超过或等于总人数

4.所剩总人数不能大于等于游戏开始时总人数

6.运行结果

题目所示数据结果(n=30,j=1,m=9,k=15)

结果分析:

输入30,即总人数30,创建长度为30的循环链表,输入1,即从第一个人开始计数,输入9,即从第一个人开始,第九人出列,输入15,即直至所剩15人游戏结束,之后将链表所指位置指向开始计数的那个人的位置,再调用删除函数,所剩人数超过要求的人便不断递归调用删除函数,每一次所删元素如下列所示

第一次所删元素为:9

第二次所删元素为:17

第三次所删元素为:25

第四次所删元素为:3

第五次所删元素为:12

第六次所删元素为:21

第七次所删元素为:30

第八次所删元素为:10

第九次所删元素为:20

第十次所删元素为:1

第十一次所删元素为:13

第十二次所删元素为:24

第十三次所删元素为:6

第十四次所删元素为:19

第十五次所删元素为:4

7.测试过程及结果分析

非法数据测试(n=2,j=2,m=2)

边界数据测试(n=2,j=1,m=1,k=2)

极限数据测试(计算量过大,并未立即得出结果)

8.附录:源程序清单

#include <stdio.h>

#include <string.h>

#include <stdlib.h>

typedef int ElemType;

typedef struct LNode{

    ElemType data;//数据域

    struct LNode *next;//指针域

} LinkList;

//初始化单链表

int InitList(LinkList *L){

    // L=(LinkList *)malloc(sizeof(LinkList));

    if (L==NULL) return 0;//分配失败

    L->next=NULL;//空表,类似于顺序表n=0

    printf("initList successfully\n");

}

//头插法创建链表

int HeadCreateList(LinkList *L,ElemType k){

    if(k<1) return 0;

    LinkList *temp;

    if (temp==NULL) return 0;//分配失败

    int i=1;

    while(i<=k){

        temp=(LinkList *)malloc(sizeof(LinkList));

        temp->data=i;//交替指向添加元素

        temp->next=L->next;//链表循环赋值

        L->next=temp;

        i++;

    }

    printf("Created successfully\n");

}

//尾插法创建链表

int FootCreateList(LinkList *L,ElemType k){

    //非法操作或创建失败

    if(k<0) return 0;

    LinkList *temp,*LCopy;

    LCopy=L;

    int i=1;

    while(i<=k){

        temp=(LinkList *)malloc(sizeof(LinkList));

        if(temp==NULL) return 0;

        temp->data=i;

        L->next=temp;

        L=L->next;//链表位置始终保持在最后

        i++;

    }

    L->next=LCopy->next;//尾结点连接头结点后第一个元素结点

    printf("Created successfully\n");

}

//打印操作

void PrintList(LinkList *L,ElemType k){

    LinkList *temp=L;

    temp=temp->next;//从头结点指向首结点

    for (int i = 0; i < k; ++i)

    {

        printf("%d\n",temp->data);

        temp=temp->next;

    }

    printf("print successfully\n");

}

//递归调用,每隔m个删除一个,直至所剩k人

ElemType DeleteElemList(LinkList *L,int m,int k,int *n){

    int i=1;

    //从j位往后数m-1位,将要删除元素的前一位

    for (; i <= m-1; ++i)

    {  

        L=L->next;

    }

    // printf("所删元素为:%d \n",L->next->data);//输出目标元素

    L->next=L->next->next;//跳过目标元素

    (*n)=(*n)-1;//长度减1

    //未达到k人时不断递归调用

    if (k<(*n)) DeleteElemList( L, m, k , n);

   

}

int main()

{

    //n人,从j开始计数,第m个人使其出列,直至所剩k人

    int n,m,j,k;

    LinkList *L;//声明一个指向单链表的带头指针L

    L=(LinkList *)malloc(sizeof(LinkList));

    InitList(L);

    //插入n元素,即n人

    printf("输入n人\n");

    scanf("%d",&n);

    if (n<1){

        printf("非法输入");

        return 0;

    }

    //为链表创建n结点

    FootCreateList(L,n);

    //打印

    // PrintList(L,n);

    printf("从j开始计数\n");

    scanf("%d",&j);

    if (j>n){

        printf("非法输入");

        return 0;

    }

    printf("第m个人使其出列\n");

    scanf("%d",&m);

    if (m>=n){

        printf("非法输入");

        return 0;

    }

    printf("直至所剩k人\n");

    scanf("%d",&k);

    if (k>=n){

        printf("非法输入");

        return 0;

    }

    //调整正确位置到j位

    for (int i = 0; i < j; ++i)

    {  

        L=L->next;//此时temp指到目标位置

    }

    //开始操作

    DeleteElemList(L,m-1,k,&n);

    // printf("最后的n为%d\n",n);

    printf("所剩元素为\n");

    PrintList(L,n);

    return 0;

}

一、课程设计目的与任务

《数据结构》课程设计是为训练学生的数据组织能力和提高程序设计能力而设置的增强实践能力的课程。目的:学习数据结构课程,旨在使学生学会分析研究数据对象的特性,学会数据的组织方法,以便选择合适的数据的逻辑结构和存储结构以及相应操作,把现实世界中的问题转换为计算机内部的表示和处理,这就是一个良好的程序设计技能训练的过程。提高学生的程序设计能力、掌握基本知识、基本技能,提高算法设计质量与程序设计素质的培养就是本门课程的课程设计的目的。

任务:根据题目要求,完成算法设计与程序实现,并按规定写出课程设计报告。

二、课程设计的内容与基本要求

设计题目:约瑟夫生死游戏

〔问题描述〕:约瑟夫生死游戏的大意是:30个旅客同乘一条船,因为严重超载,加上风高浪大,危险万分;因此船长告诉乘客,只有将全船一半的旅客投入海中,其余人才能幸免遇难。无奈,大家只得同意这种办法,并议定30个人围成一圈,由第一个人开始,依次报数,数到第9人,便把他投入大海中,然后从他的下一个人数起,数到第9人,再将他投入大海,如此循环,直到剩下15个乘客为止。问哪些位置是将被扔下大海的位置。

〔基本要求〕本游戏的数学建模如下:假设n个旅客排成一个环形,依次顺序编号1,2,…,n。从某个指定的第j号开始,沿环计数,每数到第m个人就让其出列,且从下一个人开始重新计数,继续进行下去。这个过程一直进行到剩下k个旅客为止。

本游戏要求用户输入的内容包括n,m,j,k的值.

本游戏要求输出的内容是包括

1. 离开旅客的序号;

2. 剩余旅客的序号;

〔提示〕根据上面的模型及输入输出参数分析,可以采用循环链表来进行算法实现。

具体要完成的任务是:

   A. 编制完成上述问题的C语言程序、进行程序调试并能得出正确的运行结果。

   B. 写出规范的课程设计报告书;

三、学时分配进度安排

序号

设计内容

所用时间

1

选题及调研

1天

2

功能及算法分析,编写程序

3天

3

调试程序,运行系统

3天

4

程序完成及撰写报告

2天

5

答辩

1天

合    计

2周

四、课程设计考核及评分标准

1.设计报告要求

课程设计报告要求逻辑清晰、层次分明、书写整洁。报告书应包括设计题目、设计思想、系统结构、数据结构说明及模块算法说明、使用说明书、测试结果分析,附录(程序清单)。设计报告须每人一份,独立完成。

2.评分标准

课程设计考核将综合考虑学生的系统设计方案、运行结果、课程设计报告书的质量、态度、考勤、答辩情况等各因素。具体评分标准如下: 

评分标准

分值

(1)设计方案正确,具有可行性、创新性;

20分

(2)系统开发效果较好;

20分

(3)课程设计报告书写规范、质量高;

30分

(4)课程设计答辩时,回答问题正确;

20分

(5)态度认真、刻苦钻研、遵守纪律;

10分

总分

100分

   注:成绩等级:优(90分—100分)、良(80分—89分)、中(70分—79分)、及格(60分—69分)、60分以下为不及格。

五、指导时间

周次

星期一

星期二

星期三

星期四

星期五

第16周

第3-4节

第3-4节

第1-2节

           

周次

星期一

星期二

星期三

星期四

星期五

第17周

第1-4节

第3-4节

第3-4节

第3-4节

第1-4节

                           

目  录

1 设计题目....................................................................... 1

2 设计思想....................................................................... 1

3 系统结构....................................................................... 1

4 数据结构说明和模块算法说明.................................... 1

5 使用说明书................................................................... 2

6 运行结果....................................................................... 2

7 测试过程及结果分析.................................................... 2

8 附录:源程序清单....................................................... 2

课程设计成绩评定表....................................................... 3

1.设计题目

约瑟夫问题

2.设计思想

结构分析:由于需要不断删除元素,顺序表删除元素时间开销过大,而且顺序访问到最后会出现越界问题,但设置循环链表可避免此问题,且链表删除元素时间复杂度为O(1),因此结构上选择链表

核心功能设计思路:核心功能即删除元素的功能,由题可知删除元素个数往往是过大的,所以利用递归调用删除函数来实现

实现思路:

1.设置链表

2.初始化链表

3.用户输入游戏总人数,再输入从第几人开始游戏,每隔几人使其出列,直至所剩多少人,每次数据要进行逻辑判断,以防出现逻辑错误

4.然后通过尾插法创建链表,创建链表时需要将链表设置成循环链表

5.将链表当前所指位置调整为从第几个人开始的位置,以方便删除函数的设计

6.调用删除函数,每次删除一个元素,所剩元素的总数大于要求的所剩元素数量时,不断删除时不断打印所删除的元素,便不断递归调用自身

7.删除完元素后,此时所剩元素的总数便为输入时的数量,执行打印函数,遍历现在的链表

3.系统结构

执行程序

输入数据

数据非法,return

创建链表

数据合法,初始化

判断数据合法性

判断空间是否分配成功

空间不足,return

将链表所指向的位置调整为正确位置

执行删除函数

打印链表

程序结束

不断打印删除

链表元素数量>k

递归调用

4.数据结构说明和模块算法说明

4.1链表结构:

一个数据域,保存的是当前结点的编号,即本人编号,一个指针域,指向下一个人的结点,通过typedef添加了替换名LinkList

typedef struct LNode{

    ElemType data;//数据域

    struct LNode *next;//指针域

} LinkList;

4.2初始化单链表:

一个参数,即链表,将链表初始化,即L->next为NULL,空间不足时return,即分配失败,初始化结束时输出initList successfully

int InitList(LinkList *L){

    // L=(LinkList *)malloc(sizeof(LinkList));

    if (L==NULL) return 0;//分配失败

    L->next=NULL;//空表,类似于顺序表n=0

    printf("initList successfully\n");

}

4.3尾插法创建链表:

尾插法创建链表,每次都是在链表末端插入元素,该函数有两个参数,一是链表,二是创建多少个元素,创建多少个元素的数值如果低于0则会认为是非法操作,return,用的是while循环,条件是i<=k,i初值为1,同时设置该链表为循环链表,创建结束后打印Created successfully

int FootCreateList(LinkList *L,ElemType k){

    //非法操作或创建失败

    if(k<0) return 0;

    LinkList *temp,*LCopy;

    LCopy=L;

    int i=1;

    while(i<=k){

        temp=(LinkList *)malloc(sizeof(LinkList));

        if(temp==NULL) return 0;

        temp->data=i;

        L->next=temp;

        L=L->next;//链表位置始终保持在最后

        i++;

    }

    L->next=LCopy->next;//尾结点连接头结点后第一个元素结点

    printf("Created successfully\n");

}

4.4打印操作:

该函数两个参数,一是链表,二是该链表长度,会使用一个链表的副本temp来不断遍历,通过for循环来遍历,每次都将打印temp->data,再使其指向下一结点temp=temp->next,打印结束后输出print successfully

void PrintList(LinkList *L,ElemType k){

    LinkList *temp=L;

    temp=temp->next;//从头结点指向首结点

    for (int i = 0; i < k; ++i)

    {

        printf("%d\n",temp->data);

        temp=temp->next;

    }

    printf("print successfully\n");

}

4.5删除操作:

该函数有四个参数,链表,每隔几人删除一个,直至总人数所剩多少人,链表长度(即总人数),通过for循环遍历到将要删除的元素的前一个元素,此时跳出for循环,输出将被删除的元素L->next->data,修改当前元素指向的下一个元素为下下个元素,L->next=L->next->next,此时便删除掉了当前元素

改进方向:未将当前元素下一结点的空间释放,可能会造成空间的浪费,可以添加释放结点语句

ElemType DeleteElemList(LinkList *L,int m,int k,int *n){

    int i=1;

    //从j位往后数m-1位,将要删除元素的前一位

    for (; i <= m-1; ++i)

    {  

        L=L->next;

    }

    // printf("所删元素为:%d \n",L->next->data);//输出目标元素

    L->next=L->next->next;//跳过目标元素

    (*n)=(*n)-1;//长度减1

    //未达到k人时不断递归调用

    if (k<(*n)) DeleteElemList( L, m, k , n);

   

}

4.6主函数:

创建链表,并为其分配空间,再输入游戏总人数,从第几人开始游戏,每隔几个人使其出列,最终剩下多少人,其中设置了数值上的逻辑判断,避免出现逻辑上的错误,首先初始化链表,当输入总人数时便开始判断该人数数量是否有问题,有问题则return,没问题则创建长度为总人数数量的链表,链表数值为升序序列,其次输入从第几个人开始游戏,输入后判断是否符合逻辑,再者输入每隔几人使其出列,输入判断是否负荷逻辑,最后输入游戏剩余人数,同样判断是否符合逻辑,逻辑判断结束后,调整链表所指位置为刚开始指定从第几个人开始的位置,调用删除函数,参数为,该链表,每个几个人使其出列再减一,直至所剩多少人,链表长度(即总人数)

int main()

{

    //n人,从j开始计数,第m个人使其出列,直至所剩k人

    int n,m,j,k;

    LinkList *L;//声明一个指向单链表的带头指针L

    L=(LinkList *)malloc(sizeof(LinkList));

    InitList(L);

    //插入n元素,即n人

    printf("输入n人\n");

    scanf("%d",&n);

    if (n<1){

        printf("非法输入");

        return 0;

    }

    //为链表创建n结点

    FootCreateList(L,n);

    //打印

    // PrintList(L,n);

    printf("从j开始计数\n");

    scanf("%d",&j);

    if (j>n){

        printf("非法输入");

        return 0;

    }

    printf("第m个人使其出列\n");

    scanf("%d",&m);

    if (m>=n){

        printf("非法输入");

        return 0;

    }

    printf("直至所剩k人\n");

    scanf("%d",&k);

    if (k>=n){

        printf("非法输入");

        return 0;

    }

    //调整正确位置到j位

    for (int i = 0; i < j; ++i)

    {  

        L=L->next;//此时temp指到目标位置

    }

    //开始操作

    DeleteElemList(L,m-1,k,&n);

    // printf("最后的n为%d\n",n);

    printf("所剩元素为\n");

    PrintList(L,n);

    return 0;

}

5.使用说明书

游戏步骤:

第一步:输入总人数

第二步:输入从第几个人开始计数

第三步:输入每隔几个人使其出列

第四步:输入直到总人数达到多少人时游戏结束

第五步:等待结果

游戏规则:

1.游戏总人数不允许低于一人

2.从第几个人开始计数,这个人的序号不能超过总人数

3. 每隔几个人使其出列,所隔人数不能超过或等于总人数

4.所剩总人数不能大于等于游戏开始时总人数

6.运行结果

题目所示数据结果(n=30,j=1,m=9,k=15)

结果分析:

输入30,即总人数30,创建长度为30的循环链表,输入1,即从第一个人开始计数,输入9,即从第一个人开始,第九人出列,输入15,即直至所剩15人游戏结束,之后将链表所指位置指向开始计数的那个人的位置,再调用删除函数,所剩人数超过要求的人便不断递归调用删除函数,每一次所删元素如下列所示

第一次所删元素为:9

第二次所删元素为:17

第三次所删元素为:25

第四次所删元素为:3

第五次所删元素为:12

第六次所删元素为:21

第七次所删元素为:30

第八次所删元素为:10

第九次所删元素为:20

第十次所删元素为:1

第十一次所删元素为:13

第十二次所删元素为:24

第十三次所删元素为:6

第十四次所删元素为:19

第十五次所删元素为:4

7.测试过程及结果分析

非法数据测试(n=2,j=2,m=2)

边界数据测试(n=2,j=1,m=1,k=2)

极限数据测试(计算量过大,并未立即得出结果)

8.附录:源程序清单

#include <stdio.h>

#include <string.h>

#include <stdlib.h>

typedef int ElemType;

typedef struct LNode{

    ElemType data;//数据域

    struct LNode *next;//指针域

} LinkList;

//初始化单链表

int InitList(LinkList *L){

    // L=(LinkList *)malloc(sizeof(LinkList));

    if (L==NULL) return 0;//分配失败

    L->next=NULL;//空表,类似于顺序表n=0

    printf("initList successfully\n");

}

//头插法创建链表

int HeadCreateList(LinkList *L,ElemType k){

    if(k<1) return 0;

    LinkList *temp;

    if (temp==NULL) return 0;//分配失败

    int i=1;

    while(i<=k){

        temp=(LinkList *)malloc(sizeof(LinkList));

        temp->data=i;//交替指向添加元素

        temp->next=L->next;//链表循环赋值

        L->next=temp;

        i++;

    }

    printf("Created successfully\n");

}

//尾插法创建链表

int FootCreateList(LinkList *L,ElemType k){

    //非法操作或创建失败

    if(k<0) return 0;

    LinkList *temp,*LCopy;

    LCopy=L;

    int i=1;

    while(i<=k){

        temp=(LinkList *)malloc(sizeof(LinkList));

        if(temp==NULL) return 0;

        temp->data=i;

        L->next=temp;

        L=L->next;//链表位置始终保持在最后

        i++;

    }

    L->next=LCopy->next;//尾结点连接头结点后第一个元素结点

    printf("Created successfully\n");

}

//打印操作

void PrintList(LinkList *L,ElemType k){

    LinkList *temp=L;

    temp=temp->next;//从头结点指向首结点

    for (int i = 0; i < k; ++i)

    {

        printf("%d\n",temp->data);

        temp=temp->next;

    }

    printf("print successfully\n");

}

//递归调用,每隔m个删除一个,直至所剩k人

ElemType DeleteElemList(LinkList *L,int m,int k,int *n){

    int i=1;

    //从j位往后数m-1位,将要删除元素的前一位

    for (; i <= m-1; ++i)

    {  

        L=L->next;

    }

    // printf("所删元素为:%d \n",L->next->data);//输出目标元素

    L->next=L->next->next;//跳过目标元素

    (*n)=(*n)-1;//长度减1

    //未达到k人时不断递归调用

    if (k<(*n)) DeleteElemList( L, m, k , n);

   

}

int main()

{

    //n人,从j开始计数,第m个人使其出列,直至所剩k人

    int n,m,j,k;

    LinkList *L;//声明一个指向单链表的带头指针L

    L=(LinkList *)malloc(sizeof(LinkList));

    InitList(L);

    //插入n元素,即n人

    printf("输入n人\n");

    scanf("%d",&n);

    if (n<1){

        printf("非法输入");

        return 0;

    }

    //为链表创建n结点

    FootCreateList(L,n);

    //打印

    // PrintList(L,n);

    printf("从j开始计数\n");

    scanf("%d",&j);

    if (j>n){

        printf("非法输入");

        return 0;

    }

    printf("第m个人使其出列\n");

    scanf("%d",&m);

    if (m>=n){

        printf("非法输入");

        return 0;

    }

    printf("直至所剩k人\n");

    scanf("%d",&k);

    if (k>=n){

        printf("非法输入");

        return 0;

    }

    //调整正确位置到j位

    for (int i = 0; i < j; ++i)

    {  

        L=L->next;//此时temp指到目标位置

    }

    //开始操作

    DeleteElemList(L,m-1,k,&n);

    // printf("最后的n为%d\n",n);

    printf("所剩元素为\n");

    PrintList(L,n);

    return 0;

}

  • 26
    点赞
  • 16
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

用数据说话用数据决策

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值