【问题标题】:Circular array and elimination in C, how to return the last "living" element index?C中的循环数组和消除,如何返回最后一个“活”元素索引?
【发布时间】:2021-02-27 23:39:53
【问题描述】:

我正在尝试编写一个代码来模拟拥有一把剑的固定大小的人的circle。与当前index 最接近的“活人”将被淘汰,剑将传给下一个活人(在被杀死的人之后),依此类推。

我希望它没有链表。

示例: 3人一组: arr[0] = 1, arr[1] = 1, arr[2] = 1

第一回合:

  • arr[0] KILLS arr[1] and the sword gets PASSED to arr[2]

第一回合后的元素值:

arr[0] = 1, arr[1] = 0, arr[2] = 1

第二回合:

  • arr[2] KILLS arr[0] and stays the last player

第二回合后的元素值:

arr[0] = 0, arr[1] = 0, arr[2] = 1

  • arr[2]'s index gets returned by the main function。

我想到的是:

  • 数组
  • 将所有元素的值设置为1
  • 每次循环检查if (1 == arr[i])
  • 设置一个标志来决定是杀死还是将剑传给这个家伙。
  • 返回当前索引,表明这是最后一个活着的玩家的索引。

例如,假设我们的小组中有 5 个人: [1] [1] [1] [1] [1]

第一轮:

give_sword = 0

i = 0 不输入第一个if,因为give_sword 不是1。 它进入第二个if,并使用函数findClosestLivingPerson 找到最近的活人,并获取他的索引并将他的值设置为0(== 杀死最近的活人)。 它将give_sword 设置为1。

减少players_counter 并检查是否只剩下一名玩家。如果不是,则继续循环。

这是我的代码:

#include <stdio.h>

int findClosestLivingPerson(int arr[], int index, int group_size);


int main (int argc, char *argv[])
{
    
    int group_size = 0, players_counter = 0;
    int i = 0, give_sword = 0;
    int arr[100] = {0};
    
    printf("Enter group size: \n");
    scanf("%d",&group_size);
    
    for (i = 0; i < group_size; i++)
    {
         arr[i] = 1;
    }
   
    players_counter = group_size;
    
        for (i = 0; i < group_size; (i+1) % group_size)
        {
            if (1 == arr[i])
            {
                if(1 == give_sword) /* should give sword, not to kill */
                {
                    give_sword = 0;
                }
                else /* should be killed */
                {
                    arr[findClosestLivingPerson(arr,i, group_size)] = 0;
                    give_sword = 1;
                    --players_counter;
                    if (players_counter == 1)
                    { 
                        break;
                    }
                }
            }
        }
    printf("Winner is %d ",i);
    return 0;
}

int findClosestLivingPerson(int arr[], int index, int group_size)
{
    for (; index < group_size; (index+1) % group_size)
    {
        if (arr[index] == 1)
        return index;
    }
    return 0;
}

编译器说:

在函数'main'中:last_man.c:23:43:警告:没有声明 效果 [-Wunused-value] 23 |对于 (i = 0; i

last_man.c:在函数“findClosestLivingPerson”中:last_man.c:49:42: 警告:声明无效 [-Wunused-value] 49 |为了 (; 索引

(index+1) % group_size 意味着在这个数组中循环。

【问题讨论】:

  • 以后,准备一个minimal reproducible example 来发布您的问题。这意味着 完整 源代码可以被编译以产生所示的错误消息。您的错误消息指示第 23 行,但问题出在第 2 行,因此我们知道您省略了一些代码。您应该省略代码——您应该将程序的总代码减少到重现问题所需的代码。去掉所有不相关的函数,留下必要的#include语句(但去掉不必要的语句),然后编译缩减的代码并从中发布消息,所以行号匹配。
  • 最后一段:Stack Overflow 是针对特定问题,而不是提示和建议,也不是针对每个帖子的多个不同问题。
  • @EricPostpischil 是的,很抱歉,我刚刚添加了完整的代码。我在这里的主要目的是找出我为什么返回错误值的错误。
  • @NoobCoder 在代码中发现了一个大错误并在答案中提供。在一个好的答案之后更改您的代码会引起反对票。建议恢复您的帖子。

标签: arrays c function circular-reference josephus


【解决方案1】:

正如编译器所说,(i+1) % group_size 无效。它计算 i 和 1 之和的余数。之后,它对结果没有任何作用。

for 语句的第三部分只是一个被计算的表达式。它不会自动更新循环索引或做任何其他事情。如果你想让它更新i,你必须写一个作业,比如i = (i+1) % group_size。

【讨论】:

    【解决方案2】:

    我想你误解了for 循环的工作原理。

    格式应该是这样的:

    for( initialization, condition, iteration )
    

    示例:

    for( int i = 0; i < size; i = i + 1 )
    

    (i + 1) % group_size 不是迭代(它没有将结果分配给 i ),您真正想要做的是

    i = ( i + 1 ) % group_size;
    

    同样适用于第二个警告。

    【讨论】:

    • 谢谢!这不是我提出这个问题的主要原因。我刚刚修复并添加了完整的代码。
    【解决方案3】:

    我会建议一种不同的方法。让我们以一种能产生漂亮代码的方式来做这件事。

    struct actor {
        int label;
        struct actor *next;
    };
    

    通过这个结构,我们可以创建一个不错的链表并循环它:

    int n = 5;
    int i;
    
    struct actor *actors = calloc(n, sizeof *actors);
    for (i = 0; i < n - 1; i++) {
        actors[i].label = i;
        actors[i].next = &actors[i+1];
    }
    actors[i].label = i;
    actors[i].next = &actors[0];
    

    好的,现在我们可以分配第一个杀手了:

    struct actor *k = actors;
    

    我们还需要一个kill函数:

    struct actor *kill(struct actor *a)
    {
        if (a->next != a) {
            printf("%d kills %d\n", a->label, a->next->label);
            a->next = a->next->next;
        } else {
            printf("%d is last man standing\n", a->label);
            a->next = NULL;
        }
        return a->next;
    }
    

    这是做什么的:它从循环链表中删除下一个人(因为那是被杀死的那个人)。下一个人的查找时间始终相同。

    一切准备就绪,我们就可以开始狂欢了:

    while (k) {
        k = kill(k);
    }
    

    无论如何,这不是完美的代码,但它是一个很好的例子,说明如果你在设置上付出一点努力,可以让算法变得异常简单。

    【讨论】:

    • 非常感谢您的努力,但我还不知道链表,我需要用老式的“丑陋”方式编写它(循环,许多函数..)
    • 我不知道为什么,但它给了我错误的值和输出(我的代码)。对于 100 人,它给了我7 作为输出。虽然应该是 73。
    猜你喜欢
    • 2019-11-13
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-12-25
    • 1970-01-01
    • 2020-01-07
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多