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

How to simulate array_reverse() using a recursive user-defined function?

提问人:user8133761 提问时间:2/7/2020 最后编辑:mickmackusauser8133761 更新时间:2/8/2020 访问量:161

问:

我想使用递归反转索引数组中的值。输出应与 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()是数组部分的链接,对吗?

为什么内部元素不受我的递归交换技术的影响?

PHP 数组递 切片 反转

评论

5赞 Zeljka 2/7/2020
array_reverse()
0赞 arkascha 2/7/2020
它应该是 ,而不是 。它是一个函数,而不是一个变量。array_slice(...)$array_slice(...)
0赞 04FS 2/7/2020
不太清楚你在这里想问什么。但可能应该首先,您不想在这里使用“变量函数”。$array_slicearray_slice
0赞 apokryfos 2/7/2020
PHP确实没有为此进行优化。考虑如何在PHP中以更实用的编程风格进行编码可能会很有趣,但请不要用人们将使用的任何代码编写此代码。

答:

5赞 arkascha 2/7/2020 #1

字符串和数组是两个独立的东西。我稍微清理了一下你的算法:

<?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赞 mickmackusa 2/7/2020 #2

如果您打开了错误报告,您将看到以下三个通知:

注意:只有变量应该通过引用传递...

这是因为您将输出作为引用的参数传递;要解决此问题,您必须在传入之前将 'array_slice() 的输出声明为变量。array_slice()

您看到三个通知的事实实际上表明您的递归技术正在按预期遍历并执行工作,但生成的元素交换未应用于之前的调用 -- IOW 所有后续递归修改都将丢失。(演示$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
  • -1因为 的第 3 个参数与 .array_slice()$len - 2

这是一种递归技术,它只使用迭代调用——没有切片或合并,因为它每次都传递整个原始输入数组。在递归过程中,只有目标索引会更改。我正在使用对称数组解构PHP7.1 及更高版本提供的工具)基于索引增量进行交换。count()

代码:(演示)

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);