如何使用递归用户定义函数模拟array_reverse()?

4

我想使用递归方法反转一个索引数组中的值。输出结果应该与 array_reverse() 相同。

我的代码:

$array = [1,2,3,4,5,6,7];

function reverseString(&$s) {
    if(count($s) < 2){
        return;
    }
    $len = count($s);
    $temp = $s[0];
    $s[0] = $s[$len - 1];
    $s[$len - 1] = $temp;
    reverseString(array_slice($s, 1, $len - 2));
}

reverseString($array);
print_r($array);

返回:

Array (
    [0] => 7
    [1] => 2
    [2] => 3
    [3] => 4
    [4] => 5
    [5] => 6
    [6] => 1 )

array_slice()是用于切割数组的函数,你对吗?

为什么我的递归交换技术没有影响到内部元素呢?


5
array_reverse() - Zeljka
应该是 array_slice(...),而不是 $array_slice(...)。它是一个函数,不是一个变量。 - arkascha
不太清楚你在这里想要问什么。但是 $array_slice 应该从一开始就是 array_slice,你不想在这里使用“可变函数”。 - 04FS
PHP 真的不是为此进行优化的。 在 PHP 中考虑如何以更多的函数式编程风格编写代码可能很有趣,但请不要将此代码用于任何人将使用的地方。 - apokryfos
2个回答

5

字符串和数组是两个独立的事物。我稍微优化了你的算法:

<?php
$array = [1,2,3,4,5,6,7];

function reverseSequence(&$s) {
    $len = count($s);
    if($len < 2){
        return;
    }

    $rest = array_slice($s, 1, $len - 2);
    reverseSequence($rest);
    $s = array_merge([$s[$len - 1]], $rest, [$s[0]]);
}

reverseSequence($array);
print_r($array);

输出显然是:

Array
(
    [0] => 7
    [1] => 6
    [2] => 5
    [3] => 4
    [4] => 3
    [5] => 2
    [6] => 1
)

1
如果您开启了错误报告,您将看到三个这样的提示:
注意:只有变量应该通过引用传递...
这是因为您正在将array_slice()的输出作为引用参数传递;要解决此问题,您必须在传递之前将`array_slice()`的输出声明为变量。
事实上,您看到三个提示实际上表明您的递归技术正在按预期遍历并执行工作,但结果元素交换未应用于$s上的先前调用 - 换句话说,所有后续递归修改都会丢失。(演示

@arkascha在我之前大约一个小时提供了有关您脚本的必要修复,但我可能会稍微不同地编写它。

代码:(演示)

function swapOutermost(&$a) {
    $size = count($a);
    if ($size > 1) {
        $innerElements = array_slice($a, 1, -1);
        swapOutermost($innerElements);
        $a = array_merge(
            [$a[$size - 1]],  // last is put first
            $innerElements,   // recursed reference in the middle
            [$a[0]]           // first is put last
        );
    }
}
  • count()每次递归调用只执行一次 -- arkascha已经修复了这个问题
  • 没有写return
  • array_slice()的第三个参数为-1$len - 2有相同的效果。

这里是一种递归技术,它只使用迭代的count()调用--没有切片或合并,因为它每次都传递整个原始输入数组。只有目标索引在递归过程中发生变化。我使用对称数组解构PHP7.1及更高版本可用的工具)根据索引自增进行交换。

代码:(演示

function swapOutermost(&$a, $i = 0) {
    $last = count($a) - 1 - $i;
    if ($i < $last) {
        [$a[$i], $a[$last]] = [$a[$last], $a[$i]];
        swapOutermost($a, ++$i);
    }
}

swapOutermost($array);

当然,由于计数不会改变,将其传递一次并重复使用会更有效率。

function swapOutermost(&$a, $count, $i = 0) {
    $last = $count - 1 - $i;
    if ($i < $last) {
        [$a[$i], $a[$last]] = [$a[$last], $a[$i]];
        swapOutermost($a, $count, ++$i);
    }
}

swapOutermost($array, count($array));

现在,您的原始代码片段使用引用修改,但是您在问题要求中没有明确要求这一点 - 只要使用递归即可。如果您可能会考虑使用递归函数来返回变量(例如,因为您希望能够将此调用嵌套在另一个函数中),那么这里有一种通过每个递归级别传递越来越短的数组的方法(与您的原始方法相同):
代码:(演示
function recursiveArrayReverse($a) {
    $size = count($a);
    if ($size < 2) {
        return $a;
    }
    return array_merge(
        [$a[$size - 1]],
        recursiveArrayReverse(
            array_slice($a, 1, -1)
        ),
        [$a[0]]
    );
}

$array = [1, 2, 3, 4, 5, 6, 7];
$array = recursiveArrayReverse($array);

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接