zoukankan      html  css  js  c++  java
  • 约瑟夫环

    Title: 约瑟夫环问题
    Date: 2017-03-10 22:38:52
    Category: 数据结构
    Tags: 链表
    Slug: yuesefuhuan
    Author: lart
    Illustration: 数据结构.jpg

    问题:

    约瑟夫环问题:

    问题描述:设有编号为1,2,3……n的n个人顺时针方向围坐一圈,每人有一密码(正整数)。开始时给出一报数上限m,从编号为1的人开始报数,报m的人出列;以后将出列者的密码作为新的m,从顺时针方向紧挨着他的下一个人开始报数……直至所有人出列。试编算法,求出出列顺序。
    

    要求:

    1. 用不带头结点的单向循环链表实现
    2. 从键盘输入n,m
    3. 各人的密码由计算机随机产生(1~10的正整数,也可以自己指定)
    

    测试数据:

    假设m的初值为6;n=7。7个人的密码依次是:3,1,7,2,4,8,4 则出列的顺序为: 6,1,4,7,2,3,5

    1.0 版本

    # include <stdio.h>
    # define NUM 7 //人的总个数
    
    int main()
    {
        int members[1 + NUM] = { 0, 3, 8, 1, 22, 4, 9, 15 };//间隔多少个人
        //将各个成员的存在状态用一个仅有0和1的int数组表述
        //1存在;0退出
        int bool[1 + NUM];//存在状态数组
        int *p = bool;//循环指针
        int i_1;//循环指数
        for (i_1 = 1; i_1 <= NUM; i_1++)//初始化
            *(p + i_1) = 1;
    
        //给定第一步进数
        int init_step = 5;
    
        //先将特殊的第一个处理掉,后面的有规律
        int i_2;//循环指数
        if (init_step % NUM != 0)//有余数
        {
            *(p + init_step % NUM) = 0;
            i_2 = init_step % NUM;
        }
        else//无余数
        {
            *(p + NUM) = 0;
            i_2 = NUM;
        }
        printf("退出:%d 
    ", i_2);
    
        //处理后面的数据
        int j = 0;      //j统计经过的未退出的人数,至上一个退出人的数据后,归零
        int count = 1;  //统计退出的人数
        int death;      //退出者的序号
        death = i_2;
        for (;; ++i_2)
        {
            if (*(p + i_2) == 1)//此人还活着
            {
                j++;
    
                if (j == members[death])
                {
                    *(p + i_2) = 0;
                    death = i_2;
                    j = 0;
                    count++;
                    printf("退出:%d 
    ", i_2);
    
                }
    
                if (count == NUM)
                {
                    printf("最后退出:%d 
    ", i_2);
                    break;
                }
            }
    
            if (i_2 == NUM)
                i_2 = 0;
        }
    
        return 0;
    }
    

    2.0 版本

    //使用循环链表来解决约瑟夫环问题
    //需要对链表实现的功能:
    //1. 初始化链表节点值
    //2. 删掉对应元素
    //3. 返回对应值和序号
    
    #include <stdio.h>
    #include <stdlib.h>
    
    #define NUM 7
    #define TRUE 1
    #define FALSE 0
    #define OK 1
    #define ERROR 0
    #define INFEASIBLE -1
    #define OVERFLOW -2
    
    typedef int Status;
    
    typedef struct LinkNode{
        int number;// 序号
        int data;// 对应的步进
        struct LinkNode* next;// 指向下一个节点的指针
    }LinkNode, *LinkList;// 指向结构体的指针
    
    int members[NUM] = { 3, 8, 1, 22, 4, 9, 15 };
    
    // 设立尾指针的单循环链表
    Status ListInit_CL(LinkList &L)
    {
        LinkList l = (LinkList)malloc(sizeof(struct LinkNode));
        if (!l)
            exit(OVERFLOW);
    
        L = l;// L就当作首,方便最后传出时,L没有变化
    
        int index;
        for (index = 0; index < NUM-1; index++)// 循环赋值
        {
            l->data = members[index];
            l->number = index + 1;
    
            LinkList q = (LinkList)malloc(sizeof(struct LinkNode));// 临时存储
            if (!q) // 分配失败
                return OVERFLOW;
    
            l->next = q;
            l = q;// 移位,当在最后一次的循环中,l所在是空的
            q = NULL;
            free(q);
        }
    
        l->data = members[index];
        l->number = index + 1;
        l->next = L;
    
        return OK;
    }
    
    // 删除第i个元素,并由number,data返回其序号和值
    Status ListDelete_CL(LinkList &L, int i, int &number, int &data)
    {
        LinkList q;
    
        int j;
        for (j = 0; j < i - 1; j++)// 移动i-1次,寻找后面第i-1个结点
            L = L->next;
    
        q = L->next;// q指向待删除结点
        L->next = q->next;// L->next指向被删除节点的下一个,后面的计数就是从L现在往后第i个了
    
        //返回被删除节点序号与值
        data = q->data;
        number = q->number;
        free(q);// 释放待删除结点
        return OK;
    }
    
    int main()
    {
        LinkList L = NULL;// 头指针,指向类似的结构体的指针
        if (!ListInit_CL(L))
            return ERROR;
    
        int i, get_data, get_number, given_num;
        printf("请输入你想要的数字:
    ");
        scanf("%d", &given_num);
    
        ListDelete_CL(L, given_num-1, get_number, get_data);// 删除第一个人对应的下一个人
        printf("第%d位被剔除,他的信息是%d
    ", get_number, get_data);
    
        int index;
        for (index = 0; index < NUM - 2; index++)// 只删除n-2个,除了前面删除的一个,最后剩下的就是没有删除的。
        {
            ListDelete_CL(L, get_data, get_number, get_data);
            printf("第%d位被剔除,他的信息是%d
    ", get_number, get_data);
        }
        printf("第%d位被剩下
    ", L->number);
        return OK;
    }
    

    3.0 版本

    //使用循环链表来解决约瑟夫环问题
    //需要对链表实现的功能:
    //1. 初始化链表节点值
    //2. 删掉对应元素
    //3. 返回对应值和序号
    
    #include <stdio.h>
    #include <stdlib.h>
    #include <time.h>
    
    #define TRUE 1
    #define FALSE 0
    #define OK 1
    #define ERROR 0
    #define INFEASIBLE -1
    #define OVERFLOW -2
    
    typedef int Status;
    
    typedef struct LinkNode{
        int number;// 序号
        struct LinkNode* next;// 指向下一个节点的指针
    }LinkNode, *LinkList;// 指向结构体的指针
    
    // 设立尾指针的单循环链表
    Status ListInit_CL(LinkList &L, int given_people)
    {
        LinkList l = (LinkList)malloc(sizeof(struct LinkNode));
        if (!l)
            exit(OVERFLOW);
    
        L = l;// L就当作首,方便最后传出时,L没有变化
    
        int index;
        for (index = 0; index < given_people-1; index++)// 循环赋值
        {
            l->number = index + 1;
    
            LinkList q = (LinkList)malloc(sizeof(struct LinkNode));// 临时存储
            if (!q) // 分配失败
                return OVERFLOW;
    
            l->next = q;
            l = q;// 移位,当在最后一次的循环中,l所在是空的
            q = NULL;
            free(q);
        }
    
        l->number = index + 1;
        l->next = L;
    
        return OK;
    }
    
    // 删除第i个元素,并由number返回其序号
    Status ListDelete_CL(LinkList &L, int i, int &number)
    {
        LinkList q;
    
        int j;
        for (j = 0; j < i - 1; j++)// 移动i-1次,寻找后面第i-1个结点
            L = L->next;
    
        q = L->next;// q指向待删除结点
        L->next = q->next;// L->next指向被删除节点的下一个,后面的计数就是从L现在往后第i个了
    
        //返回被删除节点序号
        number = q->number;
        free(q);// 释放待删除结点
    
        return OK;
    }
    
    int main()
    {
        int i, get_number, given_people, given_maxnum;
        printf("请输入人数n,报数上限m
    ");
        scanf("%d %d", &given_people, &given_maxnum);
        if (given_people <= 0 || given_maxnum <= 0)
            return ERROR;
    
        LinkList L = NULL;
        if (!ListInit_CL(L, given_people))
            return ERROR;
    
        srand((unsigned)time(NULL));
        int rand_number;
        ListDelete_CL(L, rand_number = rand() % given_maxnum + 1 - 1, get_number);
        printf("第%d位被剔除,对应的随机数是%d
    ", get_number, rand_number + 1);
    
        int index;
        for (index = 0; index < given_people - 2; index++)// 只删除n-2个,除了前面删除的一个,最后剩下的就是没有删除的。
        {
            ListDelete_CL(L, rand_number = rand() % given_maxnum + 1, get_number);
            printf("第%d位被剔除,对应的随机数是%d
    ", get_number, rand_number);
        }
        printf("第%d位被剩下
    ", L->number);
    
        return OK;
    }
    
  • 相关阅读:
    Kafka Kerberos客户端访问
    Kafka Kerberos服务端配置
    Centos安装Kafka
    aaaaaaaaaaaa
    Kafka队列消息和发布订阅消息
    RabbitMQ概念
    RabbitMQ使用
    windows下安装Erlang
    RabbitMQ简介
    Flume简介
  • 原文地址:https://www.cnblogs.com/lart/p/6553732.html
Copyright © 2011-2022 走看看