C语言 | 数据结构—约瑟夫环问题

简介: 目录首先什么是约瑟夫环约瑟夫环实现方式一、创建结构体变量二、初始化链表三、构建循环链表四、删除链表 五、完整代码及注释讲解首先什么是约瑟夫环约瑟夫环是循环链表中的一个经典问题;题目描述:n 个人围成一圈,从第一个人开始报数,数到 m 的人出列,再由下一个人重新从 1 开始报数,数到 m 的人再出圈,依次类推,直到所有的人都出圈;假设10个人围成一圈,依次编号1到10,按从小到大顺序报数,报到3的人出局,流程示意图如下约瑟夫环实现方式我个人倾向于循环链表;一、创建结构体变量typedef struct Node{ int data; //数据域 st

目录

首先什么是约瑟夫环

约瑟夫环实现方式

一、创建结构体变量

二、初始化链表

三、构建循环链表

四、删除链表

五、完整代码及注释讲解


首先什么是约瑟夫环

约瑟夫环循环链表中的一个经典问题;题目描述:n 个人围成一圈,从第一个人开始报数,数到 m 的人出列,再由下一个人重新从 1 开始报数,数到 m 的人再出圈,依次类推,直到所有的人都出圈;

假设10个人围成一圈,依次编号1到10,按从小到大顺序报数,报到3的人出局,流程示意图如下

约瑟夫环实现方式

我个人倾向于循环链表

一、创建结构体变量

typedefstructNode{
intdata;  //数据域structNode*next;  //指针域}Node;

二、初始化链表

Node*Create(){
Node*head;
head= (Node*)malloc(sizeof(Node));
if (head==NULL) {
exit(1);
     }
head->next=NULL;
returnhead;
}

三、构建循环链表

创建一个临时结点tail,将头结点head赋予tail,插入新结点p,让tailnext指向pp的next指向head的下一个结点即结点p;同时让tail移到p的位置,为下个结点插入做准备;这样一个循环链表就初步完成了;

代码块

Node*Push(Node*head,Node*tail,int1){
p->data=i;
tail->next=p;
p->next=head->next;
tail=p;
returnhead;
}

四、删除链表

voidPrint(Node*head){
Node*q=head;
q->next=p->next;
printf("%d ", p->data);
free(p);
p=q->next;
}

五、完整代码及注释讲解

#include<stdio.h>#include<stdlib.h>typedefstructNode{
intdata;
structNode*next;
}Node;
//创建结构体变量Node*Create(){
Node*head;
head= (Node*)malloc(sizeof(Node));
if (head==NULL) {
exit(1);
     }
head->next=NULL;
returnhead;
}
intmain()
{
intn, m,i;
Node*tail, *p, *q;
Node*head=Create();
scanf("%d %d", &n, &m);  //输入n个人围一圈及报数m的人出局//判断如果插入的数据为0或者以报数0为出局,则结束操作if (n==0||m==0) {
return0;
     }
else {
tail=head;  //开始没有数据,故尾结点tail与头结点重合for ( i=0; i<n; i++) {
p= (Node*)malloc(sizeof(Node));  //插入新结点需,先申请动态内存if (p==NULL) {        //判断动态内存是否申请成功printf("申请失败!");
exit(1);
             }
p->data=i+1; //以下4步为插入新结点及数据的操作,具体分析请看上面构建循环链表tail->next=p;
p->next=head->next;
tail=p;
         }
     }
p=head->next;  //插入完数据后,将最后一个结点的临时结点移到第一个数据处q=tail;   //然后临时结点到尾结点处i=1;
while (p!=q) {      //首尾结点是否重合,重合则表示只剩一个数据,结束循环if (i==m) {     //对报数m的人进行出局操作q->next=p->next;  //以下四步为删除操作printf("%d ", p->data);
free(p);     //一定记得将删除链表处的内存释放,以免内存内存泄漏p=q->next;
i=1;     //删除后,重新从1开始报数         }
else {   //没有报数到m,则p,q结点都往后移一位q=p;  //先q移到p的位置p=q->next;  //然后p移到q的下一个位置i++;
         }
     }
printf("%d", p->data);  //打印最后一位出局的人的号数return0;
}


相关文章
|
8天前
|
C语言
【数据结构】栈和队列(c语言实现)(附源码)
本文介绍了栈和队列两种数据结构。栈是一种只能在一端进行插入和删除操作的线性表,遵循“先进后出”原则;队列则在一端插入、另一端删除,遵循“先进先出”原则。文章详细讲解了栈和队列的结构定义、方法声明及实现,并提供了完整的代码示例。栈和队列在实际应用中非常广泛,如二叉树的层序遍历和快速排序的非递归实现等。
75 9
|
7天前
|
存储 搜索推荐 算法
【数据结构】树型结构详解 + 堆的实现(c语言)(附源码)
本文介绍了树和二叉树的基本概念及结构,重点讲解了堆这一重要的数据结构。堆是一种特殊的完全二叉树,常用于实现优先队列和高效的排序算法(如堆排序)。文章详细描述了堆的性质、存储方式及其实现方法,包括插入、删除和取堆顶数据等操作的具体实现。通过这些内容,读者可以全面了解堆的原理和应用。
48 16
|
7天前
|
C语言
【数据结构】二叉树(c语言)(附源码)
本文介绍了如何使用链式结构实现二叉树的基本功能,包括前序、中序、后序和层序遍历,统计节点个数和树的高度,查找节点,判断是否为完全二叉树,以及销毁二叉树。通过手动创建一棵二叉树,详细讲解了每个功能的实现方法和代码示例,帮助读者深入理解递归和数据结构的应用。
41 8
|
10天前
|
存储 C语言
【数据结构】手把手教你单链表(c语言)(附源码)
本文介绍了单链表的基本概念、结构定义及其实现方法。单链表是一种内存地址不连续但逻辑顺序连续的数据结构,每个节点包含数据域和指针域。文章详细讲解了单链表的常见操作,如头插、尾插、头删、尾删、查找、指定位置插入和删除等,并提供了完整的C语言代码示例。通过学习单链表,可以更好地理解数据结构的底层逻辑,提高编程能力。
37 4
|
11天前
|
存储 C语言
【数据结构】顺序表(c语言实现)(附源码)
本文介绍了线性表和顺序表的基本概念及其实现。线性表是一种有限序列,常见的线性表有顺序表、链表、栈、队列等。顺序表是一种基于连续内存地址存储数据的数据结构,其底层逻辑是数组。文章详细讲解了静态顺序表和动态顺序表的区别,并重点介绍了动态顺序表的实现,包括初始化、销毁、打印、增删查改等操作。最后,文章总结了顺序表的时间复杂度和局限性,并预告了后续关于链表的内容。
38 3
|
12天前
|
存储 算法 C语言
C语言数据结构(2)
【10月更文挑战第21天】
|
10天前
|
C语言
【数据结构】双向带头循环链表(c语言)(附源码)
本文介绍了双向带头循环链表的概念和实现。双向带头循环链表具有三个关键点:双向、带头和循环。与单链表相比,它的头插、尾插、头删、尾删等操作的时间复杂度均为O(1),提高了运行效率。文章详细讲解了链表的结构定义、方法声明和实现,包括创建新节点、初始化、打印、判断是否为空、插入和删除节点等操作。最后提供了完整的代码示例。
28 0
|
29天前
|
C语言 C++
C语言 之 内存函数
C语言 之 内存函数
32 3
|
20天前
|
存储 缓存 C语言
【c语言】简单的算术操作符、输入输出函数
本文介绍了C语言中的算术操作符、赋值操作符、单目操作符以及输入输出函数 `printf` 和 `scanf` 的基本用法。算术操作符包括加、减、乘、除和求余,其中除法和求余运算有特殊规则。赋值操作符用于给变量赋值,并支持复合赋值。单目操作符包括自增自减、正负号和强制类型转换。输入输出函数 `printf` 和 `scanf` 用于格式化输入和输出,支持多种占位符和格式控制。通过示例代码详细解释了这些操作符和函数的使用方法。
33 10
|
13天前
|
存储 算法 程序员
C语言:库函数
C语言的库函数是预定义的函数,用于执行常见的编程任务,如输入输出、字符串处理、数学运算等。使用库函数可以简化编程工作,提高开发效率。C标准库提供了丰富的函数,满足各种需求。
下一篇
无影云桌面