简体   繁体   English

以螺旋顺序打印二维数组值

[英]Print 2D array values in spiral sequence

I want to print an array in spiral order.我想以螺旋顺序打印一个数组。 For arrays with sizes 3x3, 4x4, ...etc.对于大小为 3x3、4x4 等的数组。 my code works correctly, but for 3x5, 4x6 or 5x8 sizes the output is wrong, returning only the first iteration.我的代码工作正常,但对于 3x5、4x6 或 5x8 尺寸,输出错误,仅返回第一次迭代。

This is my simple code:这是我的简单代码:

private function _spiral($rows, $cols, array $array) {
    $offset = 0;
    while($offset < ($rows - 1)){
        for($col = $offset; $col <= $cols - 1; $col++){
            print($array[$offset][$col] . ' ');
        }
        $offset++;
        $cols--;
        for($row = $offset; $row < $rows; $row++){
            print($array[$row][$cols] . ' '); 
        }
        $rows--;
        for($col = $cols - 1; $col >= $offset; $col--){
            print($array[$rows][$col] . ' ');
        }
        for($row = $rows; $row >= $offset; $row--){
            print($array[$row][$offset - 1] . ' ');
        }
    } 
 }

Example with 3 rows and 4 columns: 3 行 4 列示例:

$array = array(
    array(00,01,02,03),
    array(10,11,12,13),
    array(20,21,22,23)
)

Expected result for this array is 0 1 2 3 13 23 22 21 20 10 11 12 , but the output of my function stops after 10.这个数组的预期结果是0 1 2 3 13 23 22 21 20 10 11 12 ,但我的函数的输出在 10 后停止。

For 4 rows and 4 columns:对于 4 行 4 列:

$array = array(
    array(00,01,02,03),
    array(10,11,12,13),
    array(20,21,22,23),
    array(30,31,32,33)
)

...it should return 0 1 2 3 13 23 33 32 31 30 20 10 11 12 22 21 , and that is what my code returns. ...它应该返回0 1 2 3 13 23 33 32 31 30 20 10 11 12 22 21 ,这就是我的代码返回的内容。

But I want both cases to work with my code.但我希望这两种情况都适用于我的代码。 How can I correct the code to also produce the correct output for the first, and other cases?如何更正代码以在第一种和其他情况下也产生正确的输出?

There are a few problems with your code:您的代码存在一些问题:

  • it does not treat the four directions of traversal in the same way.它不会以相同的方式处理四个遍历方向。 You have four loops for these four directions, but in some you have <= as loop-end condition in others < , in some the condition is on something minus 1, in others not.这四个方向有四个循环,但在某些情况下,您将<=作为循环结束条件,在其他情况下< ,在某些情况下,条件是负 1,而在其他情况下则不是。

  • it has no provision for when all elements have been printed by the first or second inner loop, and thus the remaining loops will in some cases print already printed elements.它没有规定何时所有元素都被第一个或第二个内循环打印,因此在某些情况下,剩余的循环将打印已经打印的元素。

  • the outer loop condition does not check whether there are still columns that need traversal.外循环条件不检查是否还有需要遍历的列。 It is not enough to test for such rows only.仅测试此类行是不够的。

Although you could try to fix your code, I think it is better to start from scratch, taking into account that the solution should be symmetric for all four directions.尽管您可以尝试修复您的代码,但我认为最好从头开始,考虑到解决方案对于所有四个方向都应该是对称的。 This is an important intuitive reaction to develop: spot symmetries.这是一个重要的发展直觉反应:点对称。 This will lead to less code and fewer bugs.这将导致更少的代码和更少的错误。

You want to traverse a dimension (row or column) in your array until you reach the border of the array or an element you already printed.您想遍历数组中的一个维度(行或列),直到到达数组的边界或已打印的元素。 Then you want to turn 90° to the right and repeat exactly the same logic over and over again.然后你想向右转 90° 并一遍又一遍地重复完全相同的逻辑。 So if your code looks different for these different directions, something is not right.因此,如果您的代码在这些不同的方向上看起来不同,那么就有问题了。

I will share two implementations.我将分享两个实现。 Both will use the concept of the "current" cell, and let it move around in spiral motion.两者都将使用“当前”单元的概念,并让它以螺旋运动的方式移动。

The first solution treats going back or forward along a row with the same code, and similarly it has one piece of code for traversing a column forward or backward.第一个解决方案使用相同的代码处理沿行的后退或前进,类似地,它有一段代码用于向前或向后遍历列。 So this solution has two inner loops, one for traversing along a row, and another for traversing along a column.所以这个解决方案有两个内部循环,一个用于沿行遍历,另一个用于沿列遍历。 The direction in which a row or column is traversed is kept in the $direction variable, which flips between 1 and -1 at each execution of the outer loop:在其中一行或一列被遍历被保持在所述方向$direction可变的,其中,1之间翻转和-1在外部循环的每个执行:

function _spiral(array $array) {
    // No need to have the number of rows and columns passed as arguments:
    // We can get that information from the array:
    $rows = count($array);
    $cols = count($array[0]);
    // Set "current" cell to be outside array: it moves into it in first inner loop
    $row = 0;
    $col = -1;
    $direction = 1; // Can be 1 for forward and -1 for backward
    while ($rows > 0 and $cols > 0) {
        // Print cells along one row
        for ($step = 0; $step < $cols; $step++) {
            $col += $direction;
            print $array[$row][$col] . ' ';
        }
        // As we have printed a row, we have fewer rows left to print from:
        $rows--;
        // Print cells along one column
        for ($step = 0; $step < $rows; $step++) {
            $row += $direction;
            print $array[$row][$col] . ' ';
        }
        // As we have printed a column, we have fewer columns left to print from:
        $cols--;
        // Now flip the direction between forward and backward
        $direction = -$direction;
    }
}

Note the perfect symmetry between the first inner loop and the second inner loop.请注意第一个内环和第二个内环之间的完美对称。

In a second solution, this use of symmetry is taken one step further, in order to replace the two inner loops with only one.在第二种解决方案中,这种对称性的使用更进一步,以便仅用一个来替换两个内环。 For that to happen we must abandon the use of separate variables for rows and columns, and use the concept of a size related to a dimension:为此,我们必须放弃对行和列使用单独的变量,并使用与维度相关的大小概念:

function _spiral(array $array) {
    // This version of the function aims to treat rows and columns in the same way,
    // They are just another dimension, but all the logic is exactly the same:
    // $size[] has the number of rows in $size[0] and number of columns in $size[1]
    $size = Array(count($array), count($array[0]));
    // $current[] has the current row in $current[0] and current column in $current[1]
    $current = Array(0, -1);
    // $direction[] has the current row-traversal direction in $direction[0] 
    //    and column-traveral direction in $direction[1]
    $direction = Array(1, 1);
    $dimension = 0; // Which dimension to traverse along, can be 0 for row, 1 for column
    while ($size[$dimension] > 0)   {
        // Switch dimension (row to column, column to row), to traverse along
        $dimension = 1 - $dimension;
        // Print one line along that dimension, in its current direction
        for ($step = 0; $step < $size[$dimension]; $step++) {
            $current[$dimension] += $direction[$dimension];
            print $array[$current[0]][$current[1]] . ' ';
        }
        // As we have printed a line, we have fewer left to print from:
        $size[1 - $dimension]--;
        // Now flip the direction between forward and backward for this dimension:
        $direction[$dimension] = -$direction[$dimension];
    }
}

An extended version一个扩展版本

Upon request more than one year later: here is a version that allows one to choose the corner to start from, and whether to do it counter-clockwise instead of clockwise.一年多后应要求:这是一个版本,允许您选择从哪个角落开始,以及是否逆时针而不是顺时针。 This function will not print the result, but return a 1D array, with the spiral sequence.这个函数不会打印结果,而是返回一个一维数组,带有螺旋序列。 This way you can decide yourself what to do with the result: print it, or ... whatever.通过这种方式,您可以自己决定如何处理结果:打印它,或者……无论如何。

function spiral(array $array, $startRight = false, $startBottom = false, 
                              $counterClockWise = false) {
    // This version allows to select which corner to start from, and in which direction.
    //   $size[] has the number of rows in $size[0] and number of columns in $size[1]
    $size = [count($array), count($array[0])];
    // $direction[] has the current row-traversal direction in $direction[0] 
    //    and column-traversal direction in $direction[1]
    $direction = [$startBottom ? -1 : 1, $startRight ? -1 : 1];
    // Which dimension to traverse along: false means row, true means column.
    //   Every one of the optional arguments will flip the first dimension to use:
    $dimension = ($startBottom xor $startRight xor $counterClockWise);
    // $current[] has the current row in $current[0] and current column in $current[1]
    $current = [$startBottom * (count($array)-1), $startRight * (count($array[0])-1)];
    // Go back one step, outside of the grid
    $current[!$dimension] -= $direction[!$dimension];
    while ($size[$dimension] > 0)   {
        // Switch dimension (row to column, column to row), to traverse along
        $dimension = !$dimension;
        // Print one line along that dimension, in its current direction
        for ($step = 0; $step < $size[$dimension]; $step++) {
            $current[$dimension] += $direction[$dimension];
            $result[] = $array[$current[0]][$current[1]]; // store in new array
        }
        // As we have printed a line, we have fewer left to print from:
        $size[!$dimension]--;
        // Now flip the direction between forward and backward for this dimension:
        $direction[$dimension] = -$direction[$dimension];
    }
    return $result; // Return the resulting spiral as a 1D array
}

See it run on eval.in查看它在eval.in 上运行

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM