约瑟夫问题
维基百科,自由的百科全书
约瑟夫问题(有时也称为约瑟夫斯置换),是一个出现在计算机科学和数学中的问题。在计算机编程的算法中,类似问题又称为约瑟夫环。
人们站在一个等待被处决的圈子里。 计数从圆圈中的指定点开始,并沿指定方向围绕圆圈进行。 在跳过指定数量的人之后,执行下一个人。 对剩下的人重复该过程,从下一个人开始,朝同一方向跳过相同数量的人,直到只剩下一个人,并被释放。
问题即,给定人数、起点、方向和要跳过的数字,选择初始圆圈中的位置以避免被处决。
我的代码实现C++
测试通过,环境codeblocks
#include <iostream>
#include <stdio.h>
#include <stdlib.h>
using namespace std;
typedef struct Node
{
int value;
struct Node* next;
} Node, *ListNode; //定义数据节点 和 指针
ListNode createList(int total)
{/*创建链表*/
int index = 1;
Node* pre, * curr;
ListNode L = new Node; //第一个节点
L->next = NULL;
L->value = index; // 赋值为1
pre = L;
while(--total > 0) // 创建后续n-1个节点
{
curr = new Node;
curr->value = ++index;
pre->next = curr;
pre = curr;
}
curr->next = L; // 首尾相接,使链表成为循环的
return L;
}
void run (int total, int tag)
{/* run函数来进行节点的删除 */
ListNode L = createList(total); // 创建链表
ListNode node = L;
Node* pre = NULL; // 后继节点
int index = 1;
if(tag == 1)
{
while (L->next!=NULL) {
L = L->next;
}
printf("最后一个节点为:%d\n",L->value);
return ;
}
while(node && node->next)
{
if(index == tag)
{// 删除节点操作
printf("删除节点:%d\n",node->value );
pre->next = node->next;
node->next = NULL;
node = pre->next;
}
else
{// tag!=1的前提下,刚进入循环 或者 刚执行完删除节点操作时 执行此else
pre = node; // pre前移
node = node->next; // node前移
index++; // 计数器自增
}
}
}
int main()
{
run(6,3); // run(节点数,要删除的标记数)
return 0;
}
wiki代码实现C++
我自己加了注释,测试通过
#include <iostream>
#include <stdio.h>
#include <stdlib.h>
using namespace std;
typedef struct LinkNode
{
int value;
struct LinkNode* next;
} LinkNode, *LinkNodePtr;
LinkNodePtr createCycle(int total)
{
int index = 1;
LinkNodePtr head = NULL, curr = NULL, prev = NULL;
head = (LinkNodePtr)malloc(sizeof(LinkNode));
head->value = index;
prev = head;
while (--total > 0)
{
curr = (LinkNodePtr) malloc(sizeof(LinkNode));
curr->value = ++index;
prev->next = curr;
prev = curr;
}
curr->next = head; // 循环链表
return head;
}
void run(int total, int tag)
{
LinkNodePtr node = createCycle(total); // 创建
LinkNodePtr prev = NULL;
int start = 1; // 说实话这个start有点鸡肋
int index = start;
while (node && node->next)
{
if (index == tag) // 当前计数器的数字等于给定的删除标记数的时候删除节点
{
printf("节点 %d 已被删除\n", node->value);
if (tag == start) // 当删除标记数为1时会循环此if语句,否则不会执行此语句
{
prev = node->next;
node->next = NULL;
node = prev;
}
else
{
prev->next = node->next;
node->next = NULL;
node = prev->next;
}
index = start; // 计数器置回start值
}
else // 计数器继续前进
{
prev = node;
node = node->next;
index++;
}
}
}
int main()
{
run(6, 3); // run(节点数,要删除的标记数)
return 0;
}
wiki代码实现python
未测试
# -*- coding: utf-8 -*-
class Node(object):
def __init__(self, value):
self.value = value
self.next = None
def create_linkList(n):
head = Node(1)
pre = head
for i in range(2, n+1):
newNode = Node(i)
pre.next= newNode
pre = newNode
pre.next = head
return head
n = 5 #总的个数
m = 2 #数的数目
if m == 1: #如果是1的话,特殊处理,直接输出
print (n)
else:
head = create_linkList(n)
pre = None
cur = head
while cur.next != cur: #终止条件是节点的下一个节点指向本身
for i in range(m-1):
pre = cur
cur = cur.next
print (cur.value)
pre.next = cur.next
cur.next = None
cur = pre.next
print (cur.value)
代码实现C
测试通过
#include <stdio.h>
void jose(int n,int m)
{
int mon[n]; /*存放n个猴子的编号*/
int i,d,count;
for (i=0;i<n;i++) /*设置猴子的编号*/
mon[i]=i+1;
printf("出队前:"); /*输出出列前的编号*/
for (i=0;i<n;i++)
printf("%d ",mon[i]);
printf("\n");
printf("出队后:");
count=0; /*记录退出圈外的猴子个数*/
i=-1; /*从0号位置的猴子开始计数*/
while (count<n)
{
d=0;
while (d<m) /*累计数m个猴子*/
{
i=(i+1)%n;
if (mon[i]!=0)
d++;
}
printf("%d ",mon[i]); /*猴子出列*/
mon[i]=0;
count++; /*出列数增1*/
}
printf("\n");
}
int main()
{
int m,n;
printf("输入猴子个数n,m:");
scanf("%d%d",&n,&m);
jose(n,m);
scanf("%d",&n);
}