用循环链表实现Josephus问题

  Josephus问题:设有n个人围坐在一个圆桌周围,现从第s个人开始报数,数到第m的人出列,然后从出列的下一个人重新开始报数,数到第m的人又出列。如此反复直到所有的人全部出列为止。

  思路:构建一个没有头结点的循环链表,实现自己的删除函数,数到第几个结点就把这个结点从链表中删除,然后重新数。

  难点在于写删除函数。

  代码如下:

 

#include <stdio.h>
#include <stdlib.h>

typedef struct student * PNode;

typedef struct student{
    int data;
    PNode next;
}Node;

PNode create(int n)
{
    PNode head=(PNode)malloc(sizeof(Node));
    PNode p;
    int data=0;
    p=head;
    printf("请输入结点的值\n");
    scanf("%d",&data);
    p->data=data;
    while(--n)
    {
        p->next=(PNode)malloc(sizeof(Node));
        p=p->next;
        printf("请继续输入结点的值\n");
        scanf("%d",&data);
        p->data=data;
    }
    p->next=head;
    return head;
}
void print(PNode link)
{
    PNode head,p;
    if(link==NULL) return;
    head=link;
    p=link;
    while(p->next!=head)
    {
        printf("%d ",p->data);
        p=p->next;
    }
    printf("%d\n",p->data);
}

PNode del(PNode link,int num)
{
    PNode head=link;
    PNode p=link;
    PNode temp;
    if(link==NULL)
    {
    //       printf("链表为空");
        return NULL;
    }
    //      printf("要删除结点的值为%d\n",num);
    //删除头结点
    if(p->data==num)
    {
        if(p->next==head)   //只剩下一个结点的情况
        {
    //            printf("链表删除完毕。\n");
            free(link);
            return NULL;
        }
        while(p->next!=head)
            p=p->next;
        temp=p->next;
        p->next=p->next->next;
        head=p->next;
        free(temp);
        return head;
    }
    //删除非头结点
    while(p->next->data!=num && p->next!=head)
    {
        p=p->next;
    }
    if(p->next==head)
    {
   //        printf("没有找到这样的结点。\n");
        return head;
    }
    temp=p->next;
    p->next=p->next->next;
    free(temp);
    return head;
}

void Josepus(PNode link,int n,int k,int m)
{
    if(link==NULL)
    {
        printf("链表为空\n");
        return;
    }
    printf("打印出列的顺序:");
    PNode p=link;
    int r=k+m-2;  //r为链表要移动的次数,根据图示来进行r大小的确认
    while(r--)
    {
        p=p->next;
    }
    printf("%d ",p->data);
    p=del(p,p->data);
    while(p!=NULL)
    {
        r=m-1;
        while(r--)
        {
            p=p->next;
        }
        printf("%d ",p->data);
        p=del(p,p->data);
    }
    printf("\n");
}

int main(void)
{
        int n,num;
        int s,m;
        printf("请输入要创建多少个结点\n");
        scanf("%d",&n);
        PNode link=create(n);
        printf("打印初始链表\n");
        print(link);
        printf("请输入要从第几个人开始报数\n");
        scanf("%d",&s);
        printf("请输入要报多少个人\n");
        scanf("%d",&m);
        Josepus(link,n,s,m);/*      测试删除函数用地
         while(1)
    {
        printf("请输入要删除的结点的值\n");
        scanf("%d",&num);
        link=del(link,num);
        if(link==NULL)
            break;
        printf("打印删除后的链表\n");
        print(link);
    }
*/
    return 0;
}
时间: 2024-10-28 11:02:28

用循环链表实现Josephus问题的相关文章

Josephus排列

思考与分析: 对于m为常数,可以用循环链表,用head,tail标志头尾指针使其易于表示循环结构.循环输出后删除结点n次,每次外层循环时,内层都固定循环m次.所以运行时间为O(mn)=O(n). 对于m为非常数.可以用顺序统计树,用size属性记录每个结点在当前树中所在的位置.经过一个取余过程,每次都能正确找到并输出删除每个结点,在经过n次循环,每次循环都要找到一个结点输出并删除它,所以每次循环都要花费O(lgn)时间.总的运行时间是O(nlgn). 代码如下: m为常数时: #include

约瑟夫环问题(Josephus)

[问题描述] 用户输入M,N值,从1至N开始顺序循环数数,每数到M输出该数值,直至全部输出.写出C程序.(约瑟夫环问题 Josephus) [解题思路] 构建一个循环链表,每个结点的编号为1,2,......,n.每次从当前位置向前移动m-1步,然后删除这个结点. [C程序代码] #include <stdio.h> #include <stdlib.h> typedef struct node { int num; struct node *next; }node; node *

约瑟夫问题(循环链表的应用)

问题描述: 据说著名犹太历史学家 Josephus有过以下的故事:在罗马人占领乔塔帕特后,39 个犹太人与Josephus及他的朋友躲到一个洞中,39个犹太人决定宁愿死也不要被敌人抓到,于是决定了一个自杀方式,41个人排成一个圆圈,由第1个人开始报数,每报数到第3人该人就必须自杀,然后再由下一个重新报数,直到所有人都自杀身亡为止.然而Josephus 和他的朋友并不想遵从.首先从一个人开始,越过k-2个人(因为第一个人已经被越过),并杀掉第k个人.接着,再越过k-1个人,并杀掉第k个人.这个过程

习题3.10 约瑟夫环 josephus问题

/* assume a header */ /* 双向循环链表 */ struct Node; typedef struct Node * PtrToNode; typedef PtrToNode List; typedef PtrToNode position; struct Node{ PtrToNode Previous; PtrToNode Next; int Ele; }; /* 删除双向循环链表中的元素例程 */ Position Delete( Position p ) { Pos

C++ 用循环链表解决约瑟夫环问题

约瑟夫环问题 已知 n 个人(n>=1)围坐一圆桌周围,从 1 开始顺序编号,从序号为 1 的人开始报数,顺时针数到 m 的那个人出列.下一个人又从 1 开始报数,数到m 的那个人又出列.依此规则重复下去,直到所有人全部出列.请问最后一个出列的人的初始编号. 要求 输入人数 n,所报数 m,输出最后一个人的初始编号. 解决思路 首先因为是圆桌问题,使用链表解决的话需要构建循环链表. 接着是出列问题,这里我的设计思路是将指向链表的指针移动到需要出列的人的位置,然后根据正常的链表删除进行操作即可.

Java循环链表实现约瑟夫环(搬运)

1 public class Josephus { 2 static class Node{ 3 int val; 4 Node next; 5 Node(int v){ 6 val=v; 7 } 8 }//成员类,代表节点,类似于数据结构中的结构体 9 public static void main(String[] args) { 10 int N=9;//这个表示总人数 11 int M=5;//数到几的人出列 12 Node t=new Node(1);//头节点单列出来,方便形成循环链

Josephus问题的不同实现方法与总结

1 /************************************************************************/ 2 /* Josephus问题--数组实现 */ 3 /************************************************************************/ 4 #include <stdio.h> 5 #include <malloc.h> 6 7 int Josephus(int

Josephus环类问题,java实现

写出一个双向的循环链表,弄一个计数器,我定义的是到三的时候,自动删除当前节点,很简单. package Com; import java.util.Scanner; /* * 约瑟夫环问题,有n个人组成的圈,数到3的那个人出列,下个人继续从一开始 */ public class Josephus { public static void main(String[] args) { Scanner s = new Scanner(System.in); int n = Integer.parseI

Josephus

利用循环链表模拟约瑟夫问题,把自杀的人的顺序排列出来 代码如下: 1 #include<stdio.h> 2 #include<stdlib.h> 3 4 typedef int status; 5 6 typedef struct node 7 { 8 status data; 9 struct node *next; 10 }LinkList; 11 12 LinkList *create(int n) 13 { 14 LinkList *head,*p1,*p2; 15 in