算法与数据结构——Josephus Problem(约瑟夫问题)

约瑟夫问题

维基百科,自由的百科全书

跳到导航 跳到搜索

约瑟夫问题(有时也称为约瑟夫斯置换),是一个出现在计算机科学数学中的问题。在计算机编程的算法中,类似问题又称为约瑟夫环

人们站在一个等待被处决的圈子里。 计数从圆圈中的指定点开始,并沿指定方向围绕圆圈进行。 在跳过指定数量的人之后,执行下一个人。 对剩下的人重复该过程,从下一个人开始,朝同一方向跳过相同数量的人,直到只剩下一个人,并被释放。

问题即,给定人数、起点、方向和要跳过的数字,选择初始圆圈中的位置以避免被处决。

我的代码实现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);
}

猜你喜欢

转载自blog.csdn.net/qq_41420747/article/details/82631943