递归字符串反转函数

Posted

技术标签:

【中文标题】递归字符串反转函数【英文标题】:recursive string reverse function 【发布时间】:2011-03-26 08:53:38 【问题描述】:

出于好奇,编写了一个,但在那里的 XOR 有点问题。这个函数的重点是不使用迭代器,这就是为什么它是一个递归函数。这不是作业,只是好奇。

    private static char[] ReverseNL(char[] arr, int index)
    
        var len = arr.Length;
        if (index > 0)
            arr[len - index] ^= arr[index - 1];
        return index-- < 1 ? arr : ReverseNL(arr, index);
    

我的字符串的第一部分似乎卡住了

“嘿,堆栈!”变成“I♫→A ←E↨reht yeh”

总是词组的前半部分变得混乱......

更新..

我想这里真的不需要 XOR.. 所以使用了基本赋值,也摆脱了 return。

    private static void ReverseNL(char[] arr, int index) 
        var len = arr.Length;
        if (index > 0 && index > len / 2) 
            var c = arr[len - index];
            arr[len - index] = arr[index - 1];
            arr[index - 1] = c;
            index--;
            ReverseNL(arr, index);
        
    

【问题讨论】:

@NullUserException - 显然已经足够大,可以在问题中引用南方公园的一首歌曲(是否合适是另一个问题)。 我建议您将字符串更改为更标准的短语,例如:“The quick brown fox jumps over the lazy dog” 我认为您想要执行交换,并且您正在尝试执行 XOR 交换(由于算法错误而失败)。只需使用简单的交换;对于那些不完全理解它是如何工作的人来说,异或交换肯定会导致混乱。 或者是回文,比如“aibohphobia”? 你知道异或运算符的作用吗?看起来你认为它会交换你的字符,这就是它的作用: 10110110 XOR 00011100 变为: 10101010 因此你会得到 mumbo jumbo 【参考方案1】:

递归几乎总是用来简化问题。递归算法通常在本质上也是函数式的(尽管它们并非必须如此)。

在反转字符串(或char[])的情况下,“更简单”意味着“在更小的数组上操作”。

例如,你可以按如下方式减少:

"test"
"est"   't'
"st"    'e'
"t"     's'
""      't'

(左边是减少的数据;右边是剪切的数据)。

在伪代码中,您可以按如下方式进行归约:

char[] reverse(char[] data) 
    if (data.Count() == 0) 
        return new char[]  ;
    

    char cut = data.First();
    char[] rest = data.Skip(1);

    char [] restReversed = reverse(rest);

    // ???

我会留给你来决定接下来需要对你拥有的数据做什么。

【讨论】:

【参考方案2】:

可能不是最有效的,但这应该会给你一些关于如何让递归工作的想法......

    static string ReverseNL (string s)
    
        if ((s == null) || (s.Length <= 1))
        
            return s;
        
        return ReverseNL(s.Substring(1)) + s[0];
    

    static void Main(string[] args)
    
        string src = "The quick brown fox";
        Console.WriteLine(src);
        src = ReverseNL(src);
        Console.WriteLine(src);
    

【讨论】:

实际上我认为这是我最喜欢的解决方案,因为它只有 3 行。简洁大方。【参考方案3】:

如果你想要一个使用 XOR 和递归的解决方案,试试这个:

private static void ReverseNL(char[] arr, int index)

    if (index <arr.Length/2)
    
        arr[index] ^= arr[arr.Length - index-1];
        arr[arr.Length - index-1] ^= arr[index ];
        arr[index] ^= arr[arr.Length - index-1];
        ReverseNL(arr,++index);
    

您不需要返回任何内容,因为所有内容都在数组中完成。当然,您可以只删除 XOR 部分并交换元素,但这更酷。 ;)

(编辑:索引应该从 0 开始)

【讨论】:

【参考方案4】:

一个观察:您正在操作并返回一个数组。总是相同的数组。数组始终是引用。

这意味着您的退货声明过于复杂且具有误导性。在所有情况下都以return arr; 结尾。

考虑一般提示的那一部分:让它更简单,你会更容易看到错误。仅在 return 语句中的 -- 就应该引发危险。


// untested, simplified return
private static char[] ReverseNL(char[] arr, int index)

    var len = arr.Length;
    if (index > 0)
        arr[len - index] ^= arr[index - 1];

    // return index-- < 1 ? arr : ReverseNL(arr, index);

    if (index >= 1)
         ReverseNL(arr, index-1);

    return arr;     

【讨论】:

我看不出我的 return 语句有什么问题。我可以把它分成几行,但它会做同样的事情。如果 index 为 0,则返回 arr,否则递归。该部分已经过测试并且工作正常。 @Sonic:你正在原地倒车。你根本不需要退货。如果你确实使用 return 它独立于递归是/否。【参考方案5】:

在这个特定的例子中,我宁愿这样做:

return arr.Reverse();

【讨论】:

谢谢,但我没有要求反转字符串的最佳方法。这只是一个好奇心练习 当然,作业结果应该要求尽可能简洁的答案...... 这不是家庭作业。我曾经在一次采访中被问到这个问题,但不需要编写代码。所以现在出于好奇而写它。 @Sonic Soul,在我看来,这仍然属于“家庭作业”的范畴。您需要在正确的方向上轻轻推动以使您回到正轨,而不是问题的完整答案。【参考方案6】:

XOR 必须被调用两次才能交换一对元素。它只在数组的前半部分被调用一次。 (编辑中:严格来说,每次赋值只调用一次,所以净效果就像对一半数组进行两次异或交换。)

【讨论】:

以上是关于递归字符串反转函数的主要内容,如果未能解决你的问题,请参考以下文章

在Java中递归反转字符串的最佳方法是啥?

在 Java 中使用递归反转字符串

递归:反转字符串

递归:反转字符串

递归:在其位置反转字符串

C++:使用递归反转字符串