约瑟夫环(改进2.0)

具体改进内容:

  • 第一个输入为一的bug *

给定密码序列的约瑟夫环

//使用循环链表来解决约瑟夫环问题
//需要对链表实现的功能:
//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->next = 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->next;

    return OK;
}

// 删除第i个元素,并由number,data返回其序号和自身的密码
Status ListDelete_CL(LinkList &L, int i, int &number, int &data)
{
    LinkList q;
    int j;

    if (i > 1)
    {
        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个了
    }
    else if (i == 1)
    {
        q = L->next;//q指向第一个有效位
        L = L->next;//L从第一个有效位移动。
        for (j = 0;; j++)// 移动到最后面,使最后指向第二个有效位,并移动过去
        {
            L = L->next;
            if (L->next == q)
            {
                L->next = q->next;
                break;
            }
        }
    }
    else
    {
        return ERROR;
    }

    //返回被删除节点序号与值
    data = q->data;
    number = q->number;

    free(q);
    return OK;
}


//将原本的第一个节点,置空,用来放置最初始的密码,从第二个节点开始为个人赋值
//***这样实现所有人都可以用相同的规律排除。***
//这样会不会使得密码为1的?不会。因为是用一个与原本第一个一样的节点,等价于原本的第一个人的报数。
//***重点在让指针循环是指向L->next***
int main()
{
    // 让L单独做一个人,后面跟的才是最终循环的人。真正的数据从L->next开始。让他和第一个人数据相同。
    LinkList L = (LinkList)malloc(sizeof(struct LinkNode));
    if (!ListInit_CL(L))
        return ERROR;

    int get_data;
    printf("请输入你想要的密码:\n");
    scanf("%d", &get_data);

    int index, get_number = 0;
    for (index = 0; index < NUM - 1; index++)// 只删除n-2个,除了前面删除的一个,最后剩下的就是没有删除的。
    {
        ListDelete_CL(L, get_data, get_number, get_data);
        printf("第%d位被剔除,上一位的密码是%d\n", get_number, get_data);
    }
    printf("第%d位被剩下\n", L->number);
    return OK;
}

随机生成密码的约瑟夫环

//使用循环链表来解决约瑟夫环问题
//需要对链表实现的功能:
//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->next = 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->next;

    return OK;
}

// 删除第i个元素,并由number返回其序号
Status ListDelete_CL(LinkList &L, int i, int &number)
{
    LinkList q;
    int j;

    if (i > 1)
    {
        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个了
    }
    else if (i == 1)
    {
        q = L->next;//q指向第一个有效位
        L = L->next;//L从第一个有效位移动。
        for (j = 0;; j++)// 移动到最后面,使最后指向第二个有效位,并移动过去
        {
            L = L->next;
            if (L->next == q)
            {
                L->next = q->next;
                break;
            }
        }
    }
    else
    {
        return ERROR;
    }

    //返回被删除节点序号
    number = q->number;

    free(q);
    return OK;
}

//将原本的第一个节点,置空,用来放置最初始的密码,从第二个节点开始为个人赋值
//***这样实现所有人都可以用相同的规律排除。***
//这样会不会使得密码为1的?不会。因为是用一个与原本第一个一样的节点,等价于原本的第一个人的报数。
//***重点在让指针循环是指向L->next***
int main()
{
    int i, get_number, given_people, given_maxnum;
    printf("请输入人数n,随机密码上限m\n");
    scanf("%d %d", &given_people, &given_maxnum);
    if (given_people <= 0 || given_maxnum <= 0)
        return ERROR;

    LinkList L = (LinkList)malloc(sizeof(struct LinkNode));
    if (!ListInit_CL(L, given_people))
        return ERROR;

    srand((unsigned)time(NULL));
    int rand_number;
    int index;

    for (index = 0; index < given_people - 1; index++)// 只删除n-1个,最后剩下的就是没有删除的。
    {
        ListDelete_CL(L, rand_number = (rand() % given_maxnum) + 1, get_number);
        printf("第%d位被剔除,上一位的随机密码是%d\n", get_number, rand_number);
    }

    printf("第%d位被剩下\n", L->number);

    return OK;
}
    原文作者:约瑟夫环问题
    原文地址: https://www.cnblogs.com/lart/p/6617638.html
    本文转自网络文章,转载此文章仅为分享知识,如有侵权,请联系博主进行删除。
点赞