3

下面是我可以创建的用于反转字符串的最快代码

public static void ReverseFast(string x)
{
    string text = x;
    StringBuilder reverse = new StringBuilder();

    for (int i = text.Length - 1; i >= 0; i--)
    {
        reverse.Append(text[i]);
    }
      Console.WriteLine(reverse);
}

我想解决这个等式中的每一个瓶颈,以使其尽可能快。到目前为止,我唯一能找到的是我只部分理解的 Array Bounds 检查。如果您使用.Length编译器决定不检查边界,但如果您在循环中递减,for它仍然会进行边界检查,是否有禁用此功能?有人可以将其转换为使用指针来避免边界检查吗,我想测试 100k+ 个字符范围内的字符串的速度差异。

根据下面的评论和帖子,这是我迄今为止提出的。

public static void ReverseFast(string x)
{
    StringBuilder reverse = new StringBuilder(x.Length);
    for (int i = x.Length - 1; i >= 0; i--)
    {
        reverse.Append(x[i]);
    }
    Console.WriteLine(reverse);
}

上述解决方案比建议的重复问题答案要快得多。这个问题实际上是在解决 5000 * 26 个字符 + 范围内的反转问题。我仍然想使用指针来测试它,以真正查看是否没有瓶颈,尤其是对于如此大量的字符。

4

3 回答 3

14
var arr = x.ToCharArray();
Array.Reverse(arr);
return new string(arr);

但是请注意,这将反转任何 unicode 修饰符(重音等)。

基准:

Array.Reverse: 179ms
StringBuilder: 475ms

和:

static void Main()
{
    string text = new string('x', 100000);
    GC.Collect();
    GC.WaitForPendingFinalizers();
    var watch = Stopwatch.StartNew();
    const int LOOP = 1000;
    for (int i = 0; i < LOOP; i++)
    {
        var arr = text.ToCharArray();
        Array.Reverse(arr);
        string y = new string(arr);
    }
    watch.Stop();
    Console.WriteLine("Array.Reverse: {0}ms", watch.ElapsedMilliseconds);

    GC.Collect();
    GC.WaitForPendingFinalizers();
    watch = Stopwatch.StartNew();
    for (int i = 0; i < LOOP; i++)
    {
        var reverse = new StringBuilder(text.Length);
        for (int j = text.Length - 1; j >= 0; j--)
        {
            reverse.Append(text[j]);
        }
        string y = reverse.ToString();
    }
    watch.Stop();
    Console.WriteLine("StringBuilder: {0}ms", watch.ElapsedMilliseconds);
}

如果我们尝试一个长度为 500 的字符串并循环 500000 次:

Array.Reverse: 480ms
StringBuilder: 1176ms

我也尝试添加unsafe到其中,即

fixed (char* c = text)
{
    for (int j = text.Length - 1; j >= 0; j--)
    {
        reverse.Append(c[j]);
    }
}

这没有任何区别。

我也加入了 JeffRSon 的回答;我得到:

Array.Reverse: 459ms
StringBuilder: 1092ms
Pointer: 513ms

(对于 500 长度 x 5000 次迭代测试)

于 2013-06-10T07:28:39.510 回答
4

这是一个基于指针的解决方案:

unsafe String Reverse(String s)
        {
            char[] sarr = new char[s.Length];
            int idx = s.Length;
            fixed (char* c = s)
            {
                char* c1 = c;
                while (idx != 0)
                {
                    sarr[--idx] = *c1++;
                }
            }

            return new String(sarr);
        }

摆脱数组索引 (sarr[--idx]) 可能会更快:

unsafe String Reverse(String s)
        {
            char[] sarr = new char[s.Length];
            fixed (char* c = s)
            fixed (char* d = sarr)
            {
                char* c1 = c;
                char* d1 = d + s.Length;
                while (d1 > d)
                {
                    *--d1 = *c1++;
                }
            }

            return new String(sarr);
        }
于 2013-06-10T07:52:09.830 回答
2

在创建时设置容量StringBuilder,这样它就不必在循环期间增长并分配更多内存。将参数分配给局部变量是不必要的步骤,因为参数已经是局部变量。

public static void ReverseFast(string text) {
  StringBuilder reverse = new StringBuilder(text.Length);
  for (int i = text.Length - 1; i >= 0; i--) {
    reverse.Append(text[i]);
  }
}

这只是删除任何不必要工作的基本步骤。如果您的代码确实存在性能问题,则需要分析生成的代码的作用,并可能根据当前框架和硬件创建不同的版本来执行不同的操作。

于 2013-06-10T07:35:00.043 回答