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;
}

 程序猿必读

posted on 2015-04-11 16:25  龙种人  阅读(769)  评论(0编辑  收藏  举报