【问题标题】:Go through the array back and forth来回遍历数组
【发布时间】:2019-04-03 10:39:22
【问题描述】:

我们有一个长度为 3 的数组和一些计数序列:0,1,2,3,4,... 到无穷大。在该输入序列中,我们需要生成将在数组中来回遍历的序列,例如:0,1,2,1,0,1,2,1,0,... 等等 length=3

我认为这个任务在许多编程书籍中是一个非常常见的任务,但我无法找到标准解决方案,所以我创建了自己的解决方案。有没有其他更有效和优雅的解决方案,因为我不喜欢我的解决方案???

#define LENGTH 5
int main()
{
   char arr[LENGTH] = {'a','b','c','d','e'};
   int i;
   int base=0;
   for(i=0;i<100;i++){ 
        if(i%(LENGTH-1)==0){ 
            if(base==0) base=LENGTH-1;
            else base =0;
        }
    int j = abs(base-i%(LENGTH-1)); 
    printf("%c ",arr[j]); 
   }
}

Java 代码(为了您的方便):

public static void traverse(){
        char arr[] = {'a','b','c','d','e'};
        int base=0;
        for(int i=0;i<100;i++){ 
            if(i%(arr.length-1)==0){ 
            if(base==0) base=arr.length-1;
            else base =0;
            }
        int j = Math.abs(base-i%(arr.length-1)); 
        System.out.println(arr[j]+" ");
        }
    }

【问题讨论】:

  • 请不要标记无关的语言。
  • 删除了 Java 标记,因为该问题与 Java 无关
  • 项目正在使用 Java。我使用 C 进行调整。语言与此类问题无关。
  • “语言与此类问题无关” — 如果语言与您的问题无关,则不要标记它们。
  • 您的问题是“无限”。你的程序永远不会终止。

标签: java c arrays algorithm mod


【解决方案1】:

可能是这样的:

#define LENGTH 5
int main()
{
    char arr[LENGTH] = { 'a','b','c','d','e' };
    int current = 0;
    int direction = 1;
    for (int i = 0; i < 100; i++) 
    {       
        printf("%c ", arr[current]);
        if (current == 0)
            direction = 1;
        else if (current == LENGTH - 1)
            direction = -1;
        current += direction;
    }
}

【讨论】:

  • 太棒了!谢谢你。更清洁的解决方案。我认为没有更好的存在! :)
  • 不能使用这个解决方案。有时计数序列是这样的:0、1、2、3、3、3、4、4。循环内 arr-index 的独立递增将产生与输入不对应的结果(当前 += 方向)。基本上在您的解决方案中 i-var 设置循环的持续时间,但不设置其输入数据。
  • @oleg_phorostyna 如果我理解正确,您的 i 可能会重复值,然后应该产生重复的输出?在这种情况下,您要么需要从i 计算索引(根据我的回答),要么检测i 的重复值而不是在这种情况下提前current
  • @oleg 我不确定我是否理解这个问题。如果您不想重复输出序列中的重复元素,则对输入序列进行预处理(使其不包含重复元素)。您可以尝试在生成输出时即时处理此问题。但是,你只需要做一次,为什么还要做几次呢?
  • @Nico Schertler 预处理是一个可行的技巧。输入 - 是不可预测的复杂动作序列的结果(for 循环是一种抽象)
【解决方案2】:

此方案仅从i 计算arr 的索引,从而避免需要保持任何状态(例如当前方向)。因此,它有点复杂,但也适用于i 的非连续值。

char arr[] = { '0', '1', '2', '3', '4' };
const int LENGTH = sizeof arr / sizeof(*arr); // not necessary for char
assert(LENGTH > 1); // doesn't work for fewer than 2 elements

const int CYCLE = LENGTH - 1;
for (int i = 0; i < 100; ++i) { 
    printf("%c ", arr[ (i / CYCLE) & 1 ? CYCLE - i % CYCLE : i % CYCLE ]);
}
printf("\n");

解释:i / CYCLE 是通过数组的循环数,&amp; 1 检查该数字的最低有效位以确定方向(位为 1 的奇数循环向后,偶数循环 - 从0 – 前进)。 i % CYCLE 是转发循环,但由于CYCLE = LENGTH - 1,它没有到达数组的最后一个索引。 CYCLE - i % CYCLE 是向后循环,从CYCLE - 0 开始,这是向前时最后没有到达的索引,到1 结束,这样就避免了再次向前时索引0 的重复。

换句话说,向前和向后循环都省略了一个索引以避免在改变方向时重复,因此CYCLE = LENGTH - 1,这也意味着LENGTH必须至少为2以避免被零除。

【讨论】:

  • 这也是可行的解决方案,但不是很清楚。))
  • @oleg_phorostyna 我在答案中添加了简要说明。
  • 看起来差不多是我的解决方案,但仍然更好更简洁。(i / CYCLE) & 1 - 这是一个很棒的条件!我会坚持这个模式。我只是好奇-这是来回遍历数组的最佳方式吗?而且我有一个网站的想法,其中包含一些以独立于语言的风格描述的常用算法,并对每个步骤进行了广泛的解释。网络上有这样的吗?
  • @oleg_phorostyna 好吧,维基百科有对常用算法的解释,当然还有许多教科书提供伪代码实现(例如,Cormen 等人的《算法简介》)。
  • @oleg_phorostyna 至于x &amp; 1,比较常用的方式是x % 2,非负数也是一样,我只是碰巧用的是按位的。许多人可能认为% 2 更具可读性,特别是如果您添加此处隐含的!= 0(在C 中)。
猜你喜欢
  • 1970-01-01
  • 2020-11-08
  • 2016-01-31
相关资源
最近更新 更多