一个更快的方法来反转一个字符串?

时间:2013-06-10 07:27:07

标签: c# pointers

以下是我可以创建的用于反转字符串

的最快代码
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);
}

我想解决这个等式中的每个瓶颈,使其尽可能快。到目前为止我唯一能找到的是阵列边界检查,我只是部分理解。无论如何都要禁用它,因为我理解它如果你使用.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个字符+范围内解决逆转问题。我仍然希望使用指针来测试这一点,以确定是否没有瓶颈,尤其是如此大量的字符。

3 个答案:

答案 0 :(得分:13)

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长度×5000次迭代测试)

答案 1 :(得分:3)

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

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

答案 2 :(得分: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]);
  }
}

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