5

我有一个大约 1mb 大小的字符串。要求是在不分配另一个大小为 1 MB 的临时字符串的情况下反转字符串。我尝试了以下代码

string name = "abcde";

string target = "";
for(int i = name.Length - 1; i >=0; i--)
{
    target += name[i];
    name = name.Remove(i);                
    int n = name.Length;
}

但是我的朋友说如果我们使用该函数name.Remove(i),它将返回一个新字符串,但不能保证旧字符串会从内存中删除,因此不能保证大小会减小。是真的吗?如果是这样,是否有任何其他选项可用于在不分配额外内存的情况下反转字符串?

4

14 回答 14

13

您的字符串“abcde”是内存中的常量。你不能改变它,因为它是不可变的。您想要的是创建一个新字符串,为此您需要新的内存。

于 2012-07-05T08:56:55.453 回答
6

使用StringBuilder您可以使用 char 数组进行操作,但不能使用string,因为它是不可变的

于 2012-07-05T09:00:45.830 回答
3

字符串是不可变的,如果不分配新内存就无法反转它

来自 MSDN 的字符串

字符串是不可变的——字符串对象的内容在创建对象后不能更改,尽管语法使它看起来好像您可以这样做。

从同一个链接看到这个例子:

string b = "h";
b += "ello";

和解释。

当您编写此代码时,编译器实际上会创建一个新的字符串对象来保存新的字符序列,并将该新对象分配给 b。然后字符串“h”就可以进行垃圾回收了。

于 2012-07-05T08:57:25.470 回答
2

字符串是不可变的。当您声明它时,您无法更改它。所以无论你尝试什么,都会创造和使用新的记忆。

string name = "aaaaa":
name = name.Remove(0); // this is allocating new memory.
于 2012-07-05T08:57:39.910 回答
2
class Program
{
    static void Main(string[] args)
    {
        //Note how I don't bother to use a variable?
        //This is a nasty hack that knows the compiler will intern the value.
        //One of the many downsides of hacking the BCL.
        while (string.IsNullOrWhiteSpace(Console.ReadLine()))
        {
            Console.WriteLine("he\0llo");  
            "he\0llo".ReverseInPlace();
        }
    }
}

public static class Helper
{
    //Does not support multi-char values.
    public static unsafe void ReverseInPlace(this string str)
    {
        fixed (char* pfixed = str)
            for (int i = 0, ii = str.Length - 1; i < str.Length / 2; i++, ii--)
            {
                var p1 = (char*)pfixed + i;
                var p2 = (char*)pfixed + ii;
                var temp = *p1;
                *p1 = *p2;
                *p2 = temp;
            }
    }
}

如果你使用这个,你可能会死……或者什么。哎呀,我什至不知道如何编写不安全的代码。

于 2013-07-13T07:47:33.163 回答
1

如果您对原始数据有一定的控制权,您应该能够做到这一点。例如,如果您可以要求 achar[]而无需创建 a string,则可以将其原地反转。

例如,在您的示例中,您可以var name = new char[] { 'a', 'b', 'c', 'd', 'e'}代替字符串,然后将其反转。

(显然你不能对一个 1MB 的字符串执行此操作,但是无论你从哪里获取字符串,如果你最初可以将它加载为char[]...)

如果你只能有一个string,那你就不走运了。它们是不可变的——您只能通过以某种方式复制字符串来修改它。

于 2012-07-05T08:59:12.410 回答
1

StringBuilder 是可变的,在这种情况下应该给你最好的效率

string inpuStr = "The quick brown fox jumped over the lazy dog...blah blah blah up to 1MB";
StringBuilder builder = new StringBuilder();
            for (int i = inpuStr.Length - 1; i >= 0; i--)
            {
                builder.Append(inpuStr[i]); 
            }
           return builder.ToString();
于 2014-05-12T05:56:25.703 回答
0

编辑:完全失去了情节,最近使用 C++ 太多了,我忘记了 C# 字符串是不可变的。

简而言之,您必须分配新内存来更改 C# 中的字符串。您可以通过执行以下操作以最直接的方式执行此操作:

string ReverseString(string value)
{
    if (!string.IsNullOrEmpty(value))
    {
        char[] newBuffer = new char[value.Length];
        for(int i = 0; i < value.Length; i++)
            newBuffer[newBuffer.Length - i - 1] = value[i];
        value = new string(newBuffer);
    }
    return value;
}
于 2012-07-05T08:54:51.360 回答
0
you can try with linq to reverse

    string original = "abcde";
    string reverseValue = new string(original.Reverse().ToArray());

you can try also with 

string result= new string(original.Select((c, index) => new { c, index })
                                         .OrderByDescending(x => x.index)
                                         .ToArray());
于 2012-07-05T08:56:25.163 回答
0

实际上,如果不至少分配与要反转的字符串所占用的内存量相同的内存量,就没有正确的方法来反转字符串。(理论上它可以在内存中反转一个字符串,但这是非常不推荐的,我什至不会进入那个区域)。现在至于反转字符串本身。我正在做一个名为 StringExtensions 的小项目,在这个项目中,我尝试解决使用字符串时可能出现的所有问题。最大的问题之一是使用在整个框架中广泛使用的 UTF-16 编码。我反转字符串的实现如下所示:

    static IEnumerable<Tuple<int, int>> GetTextElementSegments(string value)
    {
        int[] elementOffsets = StringInfo.ParseCombiningCharacters(value);

        int lastOffset = -1;
        foreach (int offset in elementOffsets)
        {
            if (lastOffset != -1)
            {
                int elementLength = offset - lastOffset;
                Tuple<int, int> segment = new Tuple<int,int>(lastOffset, elementLength);
                yield return segment;
            }

            lastOffset = offset;
        }

        if (lastOffset != -1)
        {
            int lastSegmentLength = value.Length - lastOffset;

            Tuple<int, int> segment = new Tuple<int, int>(lastOffset, lastSegmentLength);
            yield return segment;
        }
    }

    static void Main(string[] args)
    {
        string input = "t\u0301e\u0302s\u0303t\u0304";
        StringBuilder resultBuilder = new StringBuilder(input.Length);

        var segments = GetTextElementSegments(input);

        foreach (var segment in segments.Reverse())
        {
            resultBuilder.Append(input, segment.Item1, segment.Item2);
        }

        Debug.Assert(resultBuilder.ToString() == "t\u0304s\u0303e\u0302t\u0301s");
    }

请注意,这会处理代理对、unicode 标记代码点,并且只分配与输入字符串本身占用的内存量相似的内存。

于 2012-07-05T09:31:30.597 回答
0

如果您真的很重视没有额外的分配,fix则需要字符串并使用unsafe指针代码。或者,也许,char[]使用反射获得对内部的引用。

你真的不想这样做。真的。我的意思是,真的。请不要这样做,除非作为学习练习。如果人们在生产中发现这样的代码,他们很可能会带着武器来找你。

我不会尝试编写这样的代码(因为我知道我会弄错的)。但这里有一些链接可以帮助您入门:

于 2012-07-11T07:03:50.780 回答
0

我刚刚通过使用字符串的 toCharArray() 函数和 XOR 操作来交换字符为此做了一个 Java 解决方案:

public static String reverseString(String str) {
    return reverseStringXor(str.toCharArray(), 0, str.length() - 1);
}

private static String reverseStringXor(char[] str, int start, int end) {
    while (start < end) {
        str[start] ^= str[end];
        str[end] ^= str[start];
        str[start] ^= str[end];
        start++;
        end--;
    }
    return String.valueOf(str);
}
于 2021-04-02T11:13:21.207 回答
-1

这应该有帮助

string reverse = new string("ABCDEFGHI".ToCharArray().Reverse().ToArray());
于 2012-07-05T08:56:39.290 回答
-2

这是你的答案之一。

 for (int i = textBox1.TextLength - 1; i >= 0; i--)
 {
    textBox1.Text += textBox1.Text[i];
 }
 textBox1.Text = textBox1.Text.Remove(0, textBox1.Text.Length / 2);
于 2015-06-25T06:20:57.700 回答