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

问题描述 投票:4回答:2

我想使用递归来反转索引数组中的值。输出应与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 arrays recursion slice reverse
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()的输出作为参考参数;要解决此问题,您必须在将数组_slice()的输出声明为变量之前将其传递。

您看到三个通知的事实实际上表明您的递归技术已经遍历了预期的范围并完成了工作,但是结果元素交换未应用于$s上的先前调用-IOW所有随后的递归修改将丢失。 (Demo


@ 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作为array_slice()的第三个参数与您的$len - 2具有相同的效果。

这里是一种递归技术,它仅使用迭代的count()调用-无需切片或合并,因为它每次都传递整个原始输入数组。递归期间仅目标索引会更改。我正在使用Symmetric Array Destructuringa tool available from PHP7.1 and up)基于索引增量进行交换。

代码:(Demo

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

现在,您的原始代码段通过引用进行了修改,但是您在问题要求中并未明确要求这样做-仅必须使用递归。如果您可以使用一个递归函数来代替返回变量(因为,例如,您希望将此调用嵌套在另一个函数中),那么这是一种在递归的每个级别传递一个越来越短的数组的方法(因为您原来的做过):

代码:(Demo

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);
© www.soinside.com 2019 - 2024. All rights reserved.