从中间到最外层访问数组(不是向量)元素的最简单方法是什么?

What is the simplest way to access array (not vector) element from middle to outermost?

我想做一个游戏,怪物从左到右水平排列,怪物的顺序有其他逻辑意义(例如:出现顺序),但我想玩一些从中间开始的效果怪物

数组,例如,对于奇数大小的数组:

int[] a=new int[]{1,2,3,4,5};

存取顺序为3,2,4,1,5(或3,4,2,5,1

对于偶数大小的数组:

int[] a=new int[]{1,2,3,4,5,6};

存取顺序为3,4,2,5,1,6或(4,3,5,2,6,1)

如果它在 c++ 中类似于 vector 的形式,它将是:

std::vector<int> a;
a.push_back(1);
a.push_back(2);
a.push_back(3);
a.push_back(4);
a.push_back(5);

while(a.size()>0){
    printf("%d\n",a[a.size()/2]);
    a.erase(a.begin()+a.size()/2);
}

输出是

3
4
2
5
1

但是我想要一个适合在数组中使用的算法,它的元素位置不能改变,

我试过类似的方法:

int a[]={1,2,3,4,5};
for(int i=a.size()/2;i>=0 && i<a.size();i=XXXX){
    printf("%d\n",a[i]);
}

which XXXX是update语句,我还是不知道应该是什么。

其实我不知道我的for循环中的init值和condition语句是否正确。我什至不知道是否可以通过一个循环完成。

好的,我知道我可以有一个临时向量然后复制索引来做到这一点,但我也想知道它是否可以在没有任何临时向量或数组的情况下在单个 for 循环中完成。

谁能帮忙(或者有其他简单的算法可以做到吗?)?

从最内层到最外层列出元素的算法是交替取出数组中的最后一个和第一个条目(pop 和 shift),直到没有留下任何元素,然后反转你已经取出的列表.这自然适用于奇数和偶数长度的数组。

例如,

1,2,3,4,5,6
1,2,3,4,5       6
2,3,4,5         6,1
2,3,4           6,1,5
3,4             6,1,5,2
3               6,1,5,2,4
                6,1,5,2,4,3
                3,4,2,5,1,6  // Reversed list from above

1,2,3,4,5
1,2,3,4         5
2,3,4           5,1
2,3             5,1,4
3               5,1,4,2
                5,1,4,2,3
                3,2,4,1,5  // Reversed list from above

您可以使用上述算法创建一个索引映射数组,您可以使用该数组按您请求的顺序访问您的主数组。例如:

// Start with an array of indices 
// from 0..arr.length-1
0,1,2,3,4
0,1,2,3         4
1,2,3           4,0
1,2             4,0,3
2               4,0,3,1
                4,0,3,1,2
                2,1,3,0,4  // Reversed list from above

那么你就有了一个映射数组

int[] arr = new int[]{1,2,3,4,5};
int[] map = new int[]{2,1,3,0,4};

你可以用它来访问你的主数组,例如

arr[map[0]]; // returns 3

编辑: 添加了 Java 实施和 demo.

public static int[] creatIndexMap(int length) {

    // Create a deque so elements can be removed from both ends
    Deque<Integer> tmp = new LinkedList<Integer>();
    for(int i = 0; i < length; i++) {
        tmp.add(i);
    }

    // In alternation remove the last and first entries of tmp
    // and add them in reverse order to the map array
    int[] map = new int[length];
    int index = length-1;
    while (!tmp.isEmpty()) {
        // Remove last element
        map[index--] = (int) tmp.removeLast();

        // Remove first element
        if(!tmp.isEmpty()) {
            map[index--] = (int) tmp.removeFirst();
        }
    }
    return map;
}

演示: IDEOne

这是对已编辑问题的回答,该问题与语言无关,需要一个函数来按规定顺序显示元素。

首先,选择一个 "middle" 索引。

var i = Math.floor((a.length-1)/2);

然后左右交替逐渐向外移动,直到遇到数组的任一边缘。

为方便起见,从一个变量 d = 0 开始,它将是与中间元素的距离。这个 d 将在每次迭代时像这样更新

d += -(2*d) + (d > 0 ? 0 : 1);

使用以下更新模式:

0, 1, -1, 2, -2, ...

如果数组 [1,2,3,4,5] 中的中间索引为 2,则应用 a[i + d] 将导致

3, 4, 2, 5, 1

希望这就是您要找的。


这是一个 JavaScript 实现:

var a = [1,2,3,4,5,7,8];

var i = Math.floor((a.length-1)/2);
for (var d = 0; i+d >= 0 && i+d < a.length;) {

  // Print out the value
  console.log(a[i + d]);

  // Outward-moving logic
  d += -(2*d) + (d > 0 ? 0 : 1);
}

或者如果你想像你在问题中尝试过的那样在 for 循环中全部使用,你可以这样做:

var a = [1,2,3,4,5,7,8];

var i = Math.floor((a.length-1)/2);
for (var d = 0; i+d >= 0 && i+d < a.length; d += -(2*d) + (d > 0 ? 0 : 1)) {
  console.log( a[i + d] ); // print the value
}

[1,2,3,4,5] 的结果(奇数数组):

3 4 2 5 1

[1,2,3,4,5,6,7,8] 的结果(偶数长度数组):

4 5 3 6 2 7 1 8

演示: JSBin