Looping in a spiral

前端 未结 30 2830
独厮守ぢ
独厮守ぢ 2020-11-22 15:07

A friend was in need of an algorithm that would let him loop through the elements of an NxM matrix (N and M are odd). I came up with a solution, but I wanted to see if my fe

30条回答
  •  北荒
    北荒 (楼主)
    2020-11-22 15:18

    Here's a solution in Python 3 for printing consecutive integers in a spiral clockwise and counterclockwise.

    import math
    
    def sp(n): # spiral clockwise
        a=[[0 for x in range(n)] for y in range(n)]
        last=1
        for k in range(n//2+1):
          for j in range(k,n-k):
              a[k][j]=last
              last+=1
          for i in range(k+1,n-k):
              a[i][j]=last
              last+=1
          for j in range(n-k-2,k-1,-1):
              a[i][j]=last
              last+=1
          for i in range(n-k-2,k,-1):
              a[i][j]=last
              last+=1
    
        s=int(math.log(n*n,10))+2 # compute size of cell for printing
        form="{:"+str(s)+"}"
        for i in range(n):
            for j in range(n):
                print(form.format(a[i][j]),end="")
            print("")
    
    sp(3)
    # 1 2 3
    # 8 9 4
    # 7 6 5
    
    sp(4)
    #  1  2  3  4
    # 12 13 14  5
    # 11 16 15  6
    # 10  9  8  7
    
    def sp_cc(n): # counterclockwise
        a=[[0 for x in range(n)] for y in range(n)]
        last=1
        for k in range(n//2+1):
          for j in range(n-k-1,k-1,-1):
              a[n-k-1][j]=last
              last+=1
          for i in range(n-k-2,k-1,-1):
              a[i][j]=last
              last+=1
          for j in range(k+1,n-k):
              a[i][j]=last
              last+=1
          for i in range(k+1,n-k-1):
              a[i][j]=last
              last+=1
    
        s=int(math.log(n*n,10))+2 # compute size of cell for printing
        form="{:"+str(s)+"}"
        for i in range(n):
            for j in range(n):
                print(form.format(a[i][j]),end="")
            print("")
    
    sp_cc(5)
    #  9 10 11 12 13
    #  8 21 22 23 14
    #  7 20 25 24 15
    #  6 19 18 17 16
    #  5  4  3  2  1
    

    Explanation

    A spiral is made of concentric squares, for instance a 5x5 square with clockwise rotation looks like this:

     5x5        3x3      1x1
    
    >>>>>
    ^   v       >>>
    ^   v   +   ^ v   +   >
    ^   v       <<<
    <<<

    (>>>>> means "go 5 times right" or increase column index 5 times, v means down or increase row index, etc.)

    All squares are the same up to their size, I looped over the concentric squares.

    For each square the code has four loops (one for each side), in each loop we increase or decrease the columns or row index. If i is the row index and j the column index then a 5x5 square can be constructed by: - incrementing j from 0 to 4 (5 times) - incrementing i from 1 to 4 (4 times) - decrementing j from 3 to 0 (4 times) - decrementing i from 3 to 1 (3 times)

    For the next squares (3x3 and 1x1) we do the same but shift the initial and final indices appropriately. I used an index k for each concentric square, there are n//2 + 1 concentric squares.

    Finally, some math for pretty-printing.

    To print the indexes:

    def spi_cc(n): # counter-clockwise
        a=[[0 for x in range(n)] for y in range(n)]
        ind=[]
        last=n*n
        for k in range(n//2+1):
          for j in range(n-k-1,k-1,-1):
              ind.append((n-k-1,j))
          for i in range(n-k-2,k-1,-1):
              ind.append((i,j))
          for j in range(k+1,n-k):
              ind.append((i,j))
          for i in range(k+1,n-k-1):
              ind.append((i,j))
    
        print(ind)
    
    spi_cc(5)
    

提交回复
热议问题