From ancient puzzles to modern miracles: the magical Joseph ring (C language)

foreword

Joseph's ring is an ancient and interesting problem, which involves a life-and-death contest between people, and has aroused people's long-term thinking and exploration. This problem can be solved in different ways, each with its own unique advantages and disadvantages.

Using an array to implement a Joseph ring can simply and intuitively represent the order of personnel, but is affected by the static limitation of the array size and the low operational efficiency of data copying. However, using a singly linked list implementation can dynamically adjust the size of the Joseph ring at runtime, and delete nodes through pointer updates, thereby improving efficiency.

In addition, it is more efficient to solve the Joseph ring problem through mathematical formulas. There is no need to build and traverse data structures, and the number of the last survivor can be obtained through simple mathematical calculations. This approach works well for larger problems and is extremely efficient.

Each implementation has its unique advantages, and choosing the right one depends on actual needs. Either way, solving the Joseph ring problem requires mathematical thinking and programming skills, while stimulating interest and exploration in mathematics and algorithms.

Historical Background of the Ring of Joseph

The Josephus problem is an ancient mathematical problem named after the ancient Jewish historian Flavius ​​Josephus. According to legend, Josephus was a Jewish military general who was trapped during a Jewish fortress under siege by the Romans.

According to the traditional Josephus account, he and 39 of his countrymen were trapped in a cave. As the last man standing, they decided that they would rather commit suicide than become captives of the Romans. So they decided to stand in a circle, count from one person, kill that person every time they counted to a specified number, and then start counting from the next person. This goes on until there is only one person left and he will be the only survivor.

At the heart of this problem is deciding which position is the last survivor. Josephs offers a solution based on his own recollection and experience. According to his description, he stood in the seventh position, that is to say, when he counted to the seventh person in the circle, he would be the last survivor.

Array method to solve

When using C language to realize the Joseph ring, you can use the array to represent the sequence of personnel, and simulate the killing process through loops and conditional statements. Here is a detailed explanation:

#include <stdio.h>

#define MAX_SIZE 100

// 约瑟夫环函数
int josephus(int n, int k)
{
    
    
    int circle[MAX_SIZE]; // 用数组表示约瑟夫环
    int i, index, count;

    // 初始化约瑟夫环
    for (i = 0; i < n; ++i)
    {
    
    
        circle[i] = i + 1;
    }

    index = 0; // 从第一个人开始
    count = 0; // 计数器

    // 开始杀人循环,直到只剩下一个人
    while (n > 1)
    {
    
    
        count++;

        // 数到第k个人就杀掉他
        if (count == k)
        {
    
    
            // 打印被杀的人的编号
            printf("杀死第 %d 个人\n", circle[index]);

            // 将被杀的人从约瑟夫环中移除
            for (i = index; i < n - 1; ++i)
            {
    
    
                circle[i] = circle[i + 1];
            }

            count = 0; // 重置计数器
            n--; // 约瑟夫环的人数减一
        }

        index++; // 移向下一个人

        // 当到达约瑟夫环的末尾时,回到开始位置
        if (index == n)
        {
    
    
            index = 0;
        }
    }

    // 返回最后幸存者的编号
    return circle[0];
}

int main()
{
    
    
    int n, k;
    int survivor;

    printf("请输入约瑟夫环的人数n:");
    scanf("%d", &n);

    printf("请输入每次数的数字k:");
    scanf("%d", &k);

    survivor = josephus(n, k);
    printf("最后幸存者的编号是:%d\n", survivor);

    return 0;
}

In this code, we first declare an array circleto represent the Joseph ring, whose size MAX_SIZEis Then, we use a loop to initialize the people in Joseph's ring, ranking them sequentially from 1 to n.

Next, we use indexand countvariables to simulate the killing process. indexIndicates the position of the currently counted person and countthe number of people who have already been counted.

In the kill loop, we first increment the counter countand then check if we reached the kth person. If the kth person is counted, we print out the number of the person who was killed and remove him from the Joseph ring.

After removing the person, we need to move the person behind to fill the vacancy and decrease the number of people in the Joseph ring by one.

Finally, when there is only one person left, the loop ends and we return the number of the last survivor.

In the main function, we receive the number n of the Joseph ring input by the user and the number k of each count, and call josephusthe function to calculate the number of the last survivor and print it out.

C language singly linked list solution

When using C language to realize the Joseph ring, you can also use the singly linked list to represent the sequence of personnel, and simulate the process of killing people through loops and conditional statements. Here is a detailed explanation:

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

// 定义单链表节点结构
typedef struct Node
{
    
    
    int data;
    struct Node *next;
} Node;

// 创建一个单链表节点
Node *createNode(int data)
{
    
    
    Node *newNode = (Node *)malloc(sizeof(Node));
    newNode->data = data;
    newNode->next = NULL;
    return newNode;
}

// 创建约瑟夫环
Node *createJosephusCircle(int n)
{
    
    
    Node *head = createNode(1);
    Node *prev = head;
    int i;
    for (i = 2; i <= n; ++i)
    {
    
    
        Node *newNode = createNode(i);
        prev->next = newNode;
        prev = newNode;
    }
    prev->next = head; // 将末尾节点指向头节点形成循环
    return head;
}

// 模拟杀人过程
int josephus(int n, int k)
{
    
    
    Node *head = createJosephusCircle(n);
    Node *current = head;
    Node *prev = NULL;
    int count = 0;

    while (head->next != head)
    {
    
    
        count++;
        if (count == k)
        {
    
    
            printf("杀死第 %d 个人\n", current->data);
            prev->next = current->next;
            free(current);
            current = prev->next;
            count = 0;
        }
        else
        {
    
    
            prev = current;
            current = current->next;
        }
    }

    int survivor = head->data;
    free(head);
    return survivor;
}

int main()
{
    
    
    int n, k;
    int survivor;

    printf("请输入约瑟夫环的人数n:");
    scanf("%d", &n);

    printf("请输入每次数的数字k:");
    scanf("%d", &k);

    survivor = josephus(n, k);
    printf("最后幸存者的编号是:%d\n", survivor);

    return 0;
}

In this code, we first define a single linked list node structure Node, which contains a datafield to store the personnel number, and a nextpointer to the next node.

Next, we define a createNodefunction to create a new singly linked list node and return a pointer to that node.

Then, we wrote a createJosephusCirclefunction to create Joseph rings. We create nodes sequentially from 1 to n and nextconnect them using pointers. Finally, we nextpoint the pointer of the end node to the head node, forming a loop.

Next, we wrote josephusfunctions to simulate the killing process. We use currentpointers to track the current number of people, and use prevpointers to record the previous node so that the linked list can be updated when killing people. We use counta variable to count and when the kth person is counted, we print out the number of the person who was killed and remove it from the linked list.

Finally, we take the number of the head node as the last survivor, and free the memory.

In the main function, we receive the number n of the Joseph ring input by the user and the number k of each count, and call josephusthe function to calculate the number of the last survivor and print it out.

This is the detailed explanation of the C language code to implement the Joseph ring using a singly linked list.

Mathematical formula (recursive method)

Use a mathematical formula to calculate the number of the last survivor of Joseph's ring, which can be done recursively or iteratively. Here is a detailed explanation using the iterative approach:

#include <stdio.h>

int josephus(int n, int k)
{
    
    
    int survivor = 0;
    int i;

    // 从n=1的情况开始递推计算
    for (i = 2; i <= n; ++i)
    {
    
    
        survivor = (survivor + k) % i;
    }

    // 因为编号从1开始,所以加1得到幸存者的编号
    survivor += 1;

    return survivor;
}

int main()
{
    
    
    int n, k;
    int survivor;

    printf("请输入约瑟夫环的人数n:");
    scanf("%d", &n);

    printf("请输入每次数的数字k:");
    scanf("%d", &k);

    survivor = josephus(n, k);
    printf("最后幸存者的编号是:%d\n", survivor);

    return 0;
}

In this code, we define a josephusfunction to represent the number of people in the Joseph ring and the number of each count with parameters n and k.

By iterating, we start from n=2 and calculate the number of the next person after each person is killed. We use a variable survivorto keep track of the number of survivors during the calculation, initial value is 0.

In each round of iterations, we will survivoradd k, and then take modulo the total number of people i to get the number of the next person to be killed. In this way, we find the next person to be killed in turn until only the last person remains.

Finally, we'll survivoradd 1 to match the personnel numbering scheme of Joseph's ring, and return the number of the last survivor.

In the main function, we receive the number n of the Joseph ring input by the user and the number k of each count, and call josephusthe function to calculate the number of the last survivor and print it out.

This is the detailed explanation of the C language code to implement the Joseph ring using mathematical formulas.

Summarize the advantages and disadvantages of these three methods and the optimization scheme

The following summarizes the advantages and disadvantages of the three implementations of the Joseph ring, as well as possible optimization solutions:

1. Array implementation:
Advantages:

  • Simple and intuitive, easy to understand and implement.
  • The storage and access speeds are fast, and no pointer operations are required due to the direct use of array indexes.

shortcoming:

  • The size of the array is static and needs to be determined at compile time, which limits the size of the Joseph ring.
  • When a person is deleted, the following person needs to be moved forward, which involves a large number of copy operations of data, and the efficiency is low.

Optimizable solution

  • Use a dynamic array or a dynamically linked list so that Joseph rings can be resized as needed at runtime.

2. Singly linked list implementation:
advantages:

  • Dynamic memory allocation, the size of the Joseph ring can be dynamically adjusted at runtime.
  • The operation of deleting a node only needs to update the pointer, which is more efficient.

shortcoming:

  • The node access needs to be realized by traversing the linked list, which is less efficient than the random access of the array.
  • Linked list nodes require additional memory space to store pointer information.

Optimizable solution

  • Using a doubly linked list can improve the access efficiency of nodes.

3. Realization of mathematical formulas:
Advantages:

  • There is no need to build and traverse the data structure of the Joseph ring, and the calculation is directly based on mathematical formulas, which is very efficient.
  • It is not limited by the size of the Joseph ring and is suitable for very large problems.

shortcoming:

  • Only the number of the last survivor can be obtained, but the order of the people who were killed cannot be obtained.
  • For some special k values, periodic laws may arise.

Optimizable solution

  • The calculation process of the mathematical formula cannot be improved through simple optimization, because it is already the optimal solution.

In general, choosing the right implementation depends on the situation. If the size of the Joseph ring is small and the requirement is to obtain a complete killing order, you can choose an array or a singly linked list to implement. If the size of the Joseph ring is large or only the number of the last survivor needs to be obtained, the mathematical formula is the optimal solution . In addition, according to specific requirements, optimization schemes can also be combined to improve the efficiency and flexibility of implementation.

The charm of the Joseph ring problem is that it combines mathematics, logic and programming, so that people not only exercise their thinking ability in the process of solving the problem, but also experience the charm of mathematics and computer science. This problem is both a mind-training opportunity and an amazing journey into mathematics and algorithms. Whether in academic research or in daily life, the Joseph ring problem can bring us fun and inspiration.

Guess you like

Origin blog.csdn.net/m0_75215937/article/details/131965513
Recommended