Traverse (2n+1)(2n+1) Array from centre out in diamond pattern?

萝らか妹 提交于 2019-12-25 10:05:11

问题


1How would I traverse an array from the centre outwards, visiting each cell only once?

I can do it with a breadthfirst traversal by finding unvisited neighbours, but how could I do it with some kind of edit-distance traversal? I've been trying to figure it out on paper, but can't wrap my head around it.

eg, in an array

[
[5 6 8 9 0]
[1 2 4 5 6]
[5 4 0 2 1]
[1 2 3 4 5]
[1 2 3 4 5]]

starting from the zero in the centre, we would visit the 4 at [1][2] then the 2 at [2][3] then the 3 at [3][2] then the 4 at [2][1] then the 8 at [0][2]and then the 5 at the [1][3] etc etc

I've tried this, which gets close, but misses some.

def traversalOrder(n): #n is size of array (always square)

    n = n/2
    t = []
    for k in range(1,n+1):
        t += [(i,j) for i in range(n-k,n+k+1) for j in range(n-k,n+k+1) if (i,j) not in t and (i-j == k or j-i == k)  ]

回答1:


I have an open source library pixelscan that does this sort of spatial pattern traversal on a grid. The library provides various scan functions and coordinate transformations. For example,

x0, y0, r1, r2 = 0, 0, 0, 2
for x, y in ringscan(x0, y0, r1, r2, metric=manhattan):
    print x, y

where

x0     = Circle x center
y0     = Circle y center
r1     = Initial radius
r2     = Final radius
metric = Distance metric

produces the following points in a diamond:

(0,0) (0,1) (1,0) (0,-1) (-1,0) (0,2) (1,1) (2,0) (1,-1) (0,-2) (-1,-1) (-2,0) (-1,1)

You can apply a translation to start at any center point you want.




回答2:


It seems that you could use some sort of priority queue to sort the elements based on an edit distance, like you suggested. While my edit distance doesn't give you the EXACT order you are looking for, it might be a starting point. I used heapq.

import heapq

grid = [
[5, 6, 8, 9, 0],
[1, 2, 4, 5, 6],
[5, 4, 0, 2, 1],
[1, 2, 3, 4, 5],
[1, 2, 3, 4, 5]]

rows = len(grid)
cols = len(grid[0])

heap_list = []

for row in xrange(rows):
    for col in xrange(cols):
        edit_distance = abs(row - rows/2) + abs(col - cols/2)
        #heappush(heap, (priority, object))
        heapq.heappush(heap_list, (edit_distance, grid[row][col]))

for i in xrange(len(heap_list)):
    print heapq.heappop(heap_list)

# prints (distance, value)
# (0, 0)
# (1, 2)
# (1, 3)
# (1, 4)
# (1, 4)
# (2, 1)
# etc...



回答3:


I think the easiest way to do this is with three nested loops. The outer most loop is over the expanding radiuses of your diamonds. The next loop is the four sides of a given diamond, described by a starting point and a vector the move along. The innermost loop is over the points along that side.

def traversal(n):
    h = n//2
    yield h, h   # center tile doesn't get handled the by the loops, so yield it first
    for r in range(1, n):
        for x0, y0, dx, dy in [(h, h-r, 1, 1),
                               (h+r, h, -1, 1),
                               (h, h+r, -1, -1),
                               (h-r, h, 1, -1)]:
            for i in range(r):
                x = x0 + dx*i
                y = y0 + dy*i
                if 0 <= x < n and 0 <= y < n:
                    yield x, y

If n is always odd, you can improve the performance of the inner loop a bit by limiting i rather than computing all the points and doing bounds tests to skip the ones that are outside your grid. Switching range(r) to range(max(0, r-h), max(r, h+1)) and getting rid of the if before the yield should do it. I'll leave the version above however, since its logic is much more clear.



来源:https://stackoverflow.com/questions/23840829/traverse-2n12n1-array-from-centre-out-in-diamond-pattern

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!