约瑟夫环c语言程序完整版,约瑟夫环的C语言实现

引子

据说著名犹太历史学家Josephus有过以下的故事:在罗马人占领乔塔帕特后,39 个犹太人与Josephus及他的朋友躲到一个洞中,39个犹太人决定宁愿死也不要被敌人抓到,于是决定了一个自杀方式,41个人排成一个圆圈,由第1个人开始报数,每报数到第3人该人就必须自杀,然后再由下一个重新报数,直到所有人都自杀身亡为止。然而Josephus和他的朋友并不想遵从。首先从一个人开始,越过k-2个人(因为第一个人已经被越过),并杀掉第k个人。接着,再越过k-1个人,并杀掉第k个人。这个过程沿着圆圈一直进行,直到最终只剩下一个人留下,这个人就可以继续活着。问题是,给定了和,一开始要站在什么地方才能避免被处决?Josephus要他的朋友先假装遵从,他将朋友与自己安排在第16个与第31个位置,于是逃过了这场死亡游戏。

进入正题

约瑟夫环问题,在计算机界是一个经典的循环链表问题,题意是:已知 n 个人(分别用编号 1,2,3,…,n 表示)围坐在一张圆桌周围,从编号为 k 的人开始顺时针报数,数到 m 的那个人出列;他的下一个人又从 1 开始,还是顺时针开始报数,数到 m 的那个人又出列;依次重复下去,直到圆桌上剩余一个人。

如图所示,假设此时圆周周围有 5 个人,要求从编号为 3 的人开始顺时针数数,数到 2 的那个人出列:62a834d560548c8fbbb61faf45f9c805.png

出列顺序依次为:

编号为 3 的人开始数 1,然后 4 数 2,所以 4 先出列;

4 出列后,从 5 开始数 1,1 数 2,所以 1 出列;

1 出列后,从 2 开始数 1,3 数 2,所以 3 出列;

3 出列后,从 5 开始数 1,2 数 2,所以 2 出列;

最后只剩下 5 自己,所以 5 胜出。

手敲代码实现如下

#include "stdlib.h"

#define OK 1

#define ERROR 0

typedef int ElemType;

typedef int Status;

typedef struct Node{

ElemType data;

struct Node *next;

}Node;

typedef struct Node * LinkList;

/*

1、初始化单向循环链表(带入节点总数)

*/

Status initJosehuList(LinkList *list, int count){

LinkList tempNode,lastNode = NULL;

int i = 1;

while (i <= count) {

//创建一个节点

tempNode = malloc(sizeof(Node));

if (tempNode == NULL) {

return ERROR;

}

tempNode->data = i;

if (*list == NULL) {

//首元节点插入

*list = tempNode;

tempNode->next = tempNode;

}

else {

//尾节点插入

tempNode->next = lastNode->next;

lastNode->next = tempNode;

}

//记录尾节点

lastNode = tempNode;

i++;

}

return OK;

}

/*

2、遍历链表

循环链表的遍历最好用do while语句,因为需要先做一次p = p->next,判断p->next等于首元节点的时候就是找到尾节点了

*/

void ListTraverse(LinkList list){

printf("遍历链表:");

LinkList p = list;

if (!p) {

printf("这是一个空链表");

}

else {

do {

printf("%d ",p->data);

p = p->next;

} while (p != list);

}

printf("\n");

}

int JosehuMethod(LinkList *list,int startIndex,int num){

if (*list == NULL || startIndex < 1 || num < 1) {

return 0;

}

//找到最后面的那个人,因为他是index为1时第一个数数的人的前一个人

LinkList preNode;

for (preNode = *list; preNode->next != *list; preNode = preNode->next);

//记录要出列的人

LinkList locaNode;

//第几次出列

int serialNum = 1;

//记录报到几号了

int newNum = 1;

//判断是否只留下一个人了

while ((*list)->next != *list) {

//1、先找到开始报数的人

if (startIndex > 1) {

preNode = preNode->next;

startIndex --;

continue;

}

//2、找到后,让他开始报数

if (newNum < num) {

newNum ++;

preNode = preNode->next;

}

else {

//3、找到要出列的人,将他出列

newNum = 1;

locaNode = preNode->next;

//判断是否首元节点,要特殊处理下

if (locaNode == *list) {

*list = locaNode->next;

}

preNode->next = locaNode->next;

printf("第%d个出列的人是:%d\n",serialNum,locaNode->data);

serialNum ++;

free(locaNode);

}

}

printf("最后留下的人是:%d\n",(*list)->data);

return (*list)->data;

}

int main(int argc, const char * argv[]){

//初始化

LinkList list;

int count;

printf("输入队列数量:");

scanf("%d",&count);

initJosehuList(&list, count);

//遍历数据

ListTraverse(list);

int startIndex;

int num;

printf("输入开始报数的位置:");

scanf("%d",&startIndex);

printf("输入出列的报数序号:");

scanf("%d",&num);

//执行约瑟夫方法

JosehuMethod(&list, startIndex, num);

printf("\n");

return 0;

}

复制代码

输入效果如下

41b0768d36fb892b2059ffdab9bbac5b.png

  • 1
    点赞
  • 17
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
约瑟夫环是一个经典的数学问题,也可以用C语言实现。下面是一个完整版约瑟夫环C语言程序: ```c #include <stdio.h> #include <stdlib.h> typedef struct Node { int data; struct Node* next; } Node; Node* createNode(int data) { Node* newNode = (Node*)malloc(sizeof(Node)); newNode->data = data; newNode->next = NULL; return newNode; } void appendNode(Node** head, int data) { Node* newNode = createNode(data); if (*head == NULL) { *head = newNode; (*head)->next = *head; } else { Node* temp = *head; while (temp->next != *head) { temp = temp->next; } temp->next = newNode; newNode->next = *head; } } void deleteNode(Node** head, int position) { if (*head == NULL) { return; } Node* current = *head; Node* prev = NULL; int count = 1; while (current->next != *head) { if (count == position) { if (prev == NULL) { while (current->next != *head) { current = current->next; } *head = current->next->next; } else { prev->next = current->next; } free(current); return; } prev = current; current = current->next; count++; } } void josephusCircle(int n, int k) { Node* head = NULL; for (int i = 1; i <= n; i++) { appendNode(&head, i); } Node* current = head; while (current->next != current) { for (int i = 1; i < k; i++) { current = current->next; } Node* temp = current->next; printf("%d ", temp->data); deleteNode(&head, temp->data); current = current->next; } printf("%d\n", current->data); free(current); } int main() { int n, k; printf("请输入总人数n:"); scanf("%d", &n); printf("请输入报数k:"); scanf("%d", &k); printf("约瑟夫环的出列顺序为:"); josephusCircle(n, k); return 0; } ``` 这个程序中,我们使用了循环链表来模拟约瑟夫环。首先,我们定义了一个`Node`结构体来表示链表节点,其中包含一个整数`data`和一个指向下一个节点的指针`next`。然后,我们实现了创建节点的函数`createNode`和向链表末尾添加节点的函数`appendNode`。 接下来,我们实现了删除指定位置节点的函数`deleteNode`,它会根据给定的位置删除链表中的节点。最后,我们实现约瑟夫环的函数`josephusCircle`,它会根据给定的总人数和报数规则输出约瑟夫环的出列顺序。 在`main`函数中,我们首先读取总人数`n`和报数`k`,然后调用`josephusCircle`函数来输出约瑟夫环的出列顺序。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值