循环链表与约瑟夫问题

循环链表经常与约瑟夫问题涉及在一起,在解决约瑟夫问题之前,如果了解了循环链表(这里当然是指单向的了,不要想复杂了),那么约瑟夫问题就比较好解决了。

1,循环链表的建立,打印。

这里为了简单,只是开辟了5个空间,然后将其打印。

#include <stdio.h>
#include <stdlib.h>
typedef struct Link {
    int k;
    struct Link *next;
}Link, *LinkPoint;

LinkPoint create()  //建立循环链表
{
    LinkPoint head,p1,p2;
    int i, n=0;
    for(i=0; i<5; i++)
    {
       p1 = (LinkPoint)malloc(sizeof(Link));
       if(n == 0)
       {
           p2 = head = p1;
           p1->k = i+1;
           p1->next = NULL;
           n = 1;
       }
       else
       {
           p1->k = i+1;
           p1->next = NULL;
           p2->next = p1;
           p2 = p1;
       }
    }
    p2->next = head;
    return head;
}

void print(LinkPoint head)  //打印出来
{
    LinkPoint p;
    p = head;
    if(head != NULL)
    {
        do{
            printf("uuu %d\n",p->k);
            p = p->next;
        }while(p->next != head);
        printf("uuu %d\n",p->k);
    }
}

int main()
{
    LinkPoint list;
    list = create();
    print(list);

    return 0;
}


一个简单的循环链表完成了,下面就一个简单的题目来进入约瑟夫问题吧。

2,13个人围成一圈,从第1个人开始顺序报号1、2、3。凡报导3者退出圈子。找出最后留在圈子中的人原来的序号。

#include <stdio.h>
#include <stdlib.h>
typedef struct Link {
    int k;
    struct Link *next;
}Link, *LinkPoint;

LinkPoint create(int num)  //建立循环链表
{
    LinkPoint head,p1,p2;
    int i, n=0;
    for(i=0; i<num; i++)
    {
       p1 = (LinkPoint)malloc(sizeof(Link));
       if(n == 0)
       {
           p2 = head = p1;
           p1->k = i+1;
           p1->next = NULL;
           n = 1;
       }
       else
       {
           p1->k = i+1;
           p1->next = NULL;
           p2->next = p1;
           p2 = p1;
       }
    }
    p2->next = head;
    return head;
}

void print(LinkPoint head)  //打印出来
{
    LinkPoint p;
    p = head;
    if(head != NULL)
    {
        do{
            printf("uuu %d\n",p->k);
            p = p->next;
        }while(p->next != head);
        printf("uuu %d\n",p->k);
    }
}

int playGame(LinkPoint head)
{
    LinkPoint p1,p2;
    int i = 1;
    int num = 13;
    p1 = p2 = head;
    while(num != 1)
    {
        p1 = p1->next;
        i++;
        if(i == 3)
        {
            p2 = p2->next;
            p2->next = p1->next;
            free(p1);  //p1指向的内存释放掉,但p1指针还没有消失
              p1 = p2->next;
            p2 = p1;
            i = 1;
            num--;
        }
    }
    return p1->k;

}

int main()
{
    LinkPoint list;
    int last;

    list = create(13);
    print(list);

    last = playGame(list);
    printf("last num is %d\n",last);

    return 0;
}
假如从第几个人开始是未知的,可以从第2个人开始数,从第3个人开始数,又比如说总共有几个人来参与这个游戏,都是未知,由我们来确定的话,只需要修改函数的参数就够了,整体框架不用再改变。如:
#include <stdio.h>
#include <stdlib.h>
typedef struct Link {
    int k;
    struct Link *next;
}Link, *LinkPoint;

LinkPoint create(int num)  //建立循环链表
{
    LinkPoint head,p1,p2;
    int i, n=0;
    for(i=0; i<num; i++)
    {
       p1 = (LinkPoint)malloc(sizeof(Link));
       if(n == 0)
       {
           p2 = head = p1;
           p1->k = i+1;
           p1->next = NULL;
           n = 1;
       }
       else
       {
           p1->k = i+1;
           p1->next = NULL;
           p2->next = p1;
           p2 = p1;
       }
    }
    p2->next = head;
    return head;
}

int playGame(LinkPoint head, int start, int total)
{
    LinkPoint p1,p2,r;
    int i = 1;
    //int num = 13;
    start -= 1;
    //p1 = p2 = head;
    r = head;
    while(start--)
        r = r->next;
    p1 = p2 = r;
    while(total != 1)
    {
        p1 = p1->next;
        i++;
        if(i == 3)
        {
            p2 = p2->next;
            p2->next = p1->next;
            free(p1);  //p1指向的内存释放掉,但p1指针还没有消失
            p1 = p2->next;
            p2 = p1;
            i = 1;
            total--;
        }
    }
    return p1->k;

}

int main()
{
    LinkPoint list;
    int last;

    list = create(13);

    last = playGame(list,2,13);
    printf("last num is %d\n",last);

    return 0;
}
当然可以根据自己再次修改,可以添加输入,这样就不用每次修改参数还要重新编译。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值