算法 -- 约瑟夫问题

假设有N个人,决定选出一个领导人,方法如下:

所有人排成一个圆圈, 按顺序数数,每隔第M个人出局,此时,他两边的人靠拢,重新排成一个圆圈,找出哪个人将会是最后一个留下的。 (比如N = 9 , M = 5 . 出局顺序为 5 1 7 4 3 6 9 2   剩下 8)

 

链表节点结构体

typedef struct node_S
{
    int                 value;
    struct node_S       *next;
} node_T, *link;

 

一、创建链表

link create_link(node_T *head)
{
    int i;
    node_T *p, *q;

    p = head;
    for (i = 2; i < N + 1; i++)
    {
        q = (link)malloc(sizeof(node_T));

        // 赋值 1 2 .. N
        q->value = i;
        p->next = q;
        p = q;

        // 循环
        q->next = head;
    }
    return head;
}

二、释放节点

void free_node(node_T *node)
{
    //printf("node: %p\n", node);

    free(node);
    node->next = NULL;
    node = NULL;
}

三、执行约瑟夫逻辑流程

node_T *do_josephus(node_T *head)
{
    int i;
    link q;
    link p = head;

    /* 当thd 至少为 2 的情况下 */

    //while (p->next)                                     // 此处错误, 最终 p->next = p; 即 p->next != NULL
    //while (p->next != p)                                // 判定条件为不指向自己, thd >= 2; 最后一位 p->next = p; 
    //while (p->next != p && p->next == NULL)               // 兼容 thd = 1; 因为最后一位 p->next = head  而此时head = NULL;
    while (p->next != p)
    {
        if (thd == 1)
        {
            if (p->next != head)                // 检查是否指向最后一位  p->next = head; 即便 head = NULL; p->next == NULL is not
            {
                q = p;
                p = p->next;
            }
            else
            {
                break;
            }
        }
        else
        {
            for (i = 1; i < thd - 1; i++)              // 指向出局者前一个
            {
                p = p->next;                           // if thd = 3,  p point 2;
            }
            q = p->next;

            p->next = q->next;
            p = p->next;
        }

        printf("%d ", q->value);
        free_node(q);
    }

    printf("%d ", p->value);
    printf("\n");
    return p;
}

四、测试打印 链表数据

void test_print(node_T *head)
{
    int i;
    link p = head;

    for (i = 1; i < N + 1; i++)
    {
        printf("%d ", p->value);
        p = p->next;
    }
    printf("\n");
}

五、主函数

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


typedef struct node_S
{
    int                 value;
    struct node_S       *next;
} node_T, *link;

int thd, N;

int main(int argc, const char *argv[])
{

    int i;
    node_T *last;
    node_T *head, *p, *q;

    if (argc != 3)
    {
        printf("Usage: a.out <total> <thd>\n");
        return -1;
    }

    N = atoi(argv[1]);
    thd = atoi(argv[2]);

    // 创建头节点
    head = (link)malloc(sizeof(node_T));
    head->value = 1;
    head->next = NULL;

    // 创建循环链表
    create_link(head);

    // 测试打印
    test_print(head);

    // 执行
    last = do_josephus(head);

    return 0;
}

 

附: 标准程序 (算法:C语描述 )

  • 由于创建链表采用 最后创建的元素为起点, 因此不用单独处理 N = 1 的情况
#include <stdio.h>
#include <stdlib.h>

typedef struct node *link;

struct node
{
    int     item;
    link    next;
};

int N , M;

void test_print(link head)
{
    int i;
    link p = head;

    for (i = 1; i < N + 1; i++)
    {   
        printf("%d ", p->item);
        p = p->next;
    }   
    printf("\n");
}

int main(int argc, const char *argv[])
{
    int i;
    
    if (argc != 3){ 
        printf("Usage: a.out <N> <M>\n");
        return -1; 
    }   
    N = atoi(argv[1]);
    M = atoi(argv[2]);

    // 创建头节点
    link t = malloc(sizeof *t), x = t;
    t->item = 1;
    t->next = t;

    // 创建链表
    for (i = 2; i <= N; i++)
    {   
        x = (x->next = malloc(sizeof *x));
        x->item = i;
        x->next = t;                // 此时x指向末尾元素 x->next = t;(头)
    }   
    // 测试打印
    test_print(t); 

    // 执行约瑟夫
    while (x != x->next)
    {   
        for (i = 1; i < M; i++)
            x = x->next;
        x->next = x->next->next;    // 从末尾开始,因此不用单独 处理 N为1的情况
        N--;
    }   

    printf("%d\n", x->item);

    return 0;
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值