我刚刚在c# 2.0中写了一个字符串反向函数(即LINQ不可用),然后想到了这个:
public string Reverse(string text)
{
char[] cArray = text.ToCharArray();
string reverse = String.Empty;
for (int i = cArray.Length - 1; i > -1; i--)
{
reverse += cArray[i];
}
return reverse;
}
就我个人而言,我并不喜欢这个功能,我相信有更好的方法来实现它。是吗?
首先,你不需要调用ToCharArray,因为字符串已经可以被索引为char数组,所以这将节省你的分配。
下一个优化是使用StringBuilder来防止不必要的分配(因为字符串是不可变的,连接它们每次都会复制一个字符串)。为了进一步优化这一点,我们预先设置了StringBuilder的长度,这样它就不需要扩展它的缓冲区。
public string Reverse(string text)
{
if (string.IsNullOrEmpty(text))
{
return text;
}
StringBuilder builder = new StringBuilder(text.Length);
for (int i = text.Length - 1; i >= 0; i--)
{
builder.Append(text[i]);
}
return builder.ToString();
}
编辑:性能数据
我使用Array测试了这个函数和这个函数。用下面的简单程序进行反向,其中Reverse1是一个函数,Reverse2是另一个函数:
static void Main(string[] args)
{
var text = "abcdefghijklmnopqrstuvwxyz";
// pre-jit
text = Reverse1(text);
text = Reverse2(text);
// test
var timer1 = Stopwatch.StartNew();
for (var i = 0; i < 10000000; i++)
{
text = Reverse1(text);
}
timer1.Stop();
Console.WriteLine("First: {0}", timer1.ElapsedMilliseconds);
var timer2 = Stopwatch.StartNew();
for (var i = 0; i < 10000000; i++)
{
text = Reverse2(text);
}
timer2.Stop();
Console.WriteLine("Second: {0}", timer2.ElapsedMilliseconds);
Console.ReadLine();
}
事实证明,对于短字符串数组。反向方法大约是上面方法的两倍,对于更长的字符串,差异甚至更明显。已知这个数组。反向法既简单又快,我建议你用那个而不是这个。我把这个留在这里只是为了表明这不是你应该做的方式(让我很惊讶!)
public string Reverse(string input)
{
char[] output = new char[input.Length];
int forwards = 0;
int backwards = input.Length - 1;
do
{
output[forwards] = input[backwards];
output[backwards] = input[forwards];
}while(++forwards <= --backwards);
return new String(output);
}
public string DotNetReverse(string input)
{
char[] toReverse = input.ToCharArray();
Array.Reverse(toReverse);
return new String(toReverse);
}
public string NaiveReverse(string input)
{
char[] outputArray = new char[input.Length];
for (int i = 0; i < input.Length; i++)
{
outputArray[i] = input[input.Length - 1 - i];
}
return new String(outputArray);
}
public string RecursiveReverse(string input)
{
return RecursiveReverseHelper(input, 0, input.Length - 1);
}
public string RecursiveReverseHelper(string input, int startIndex , int endIndex)
{
if (startIndex == endIndex)
{
return "" + input[startIndex];
}
if (endIndex - startIndex == 1)
{
return "" + input[endIndex] + input[startIndex];
}
return input[endIndex] + RecursiveReverseHelper(input, startIndex + 1, endIndex - 1) + input[startIndex];
}
void Main()
{
int[] sizes = new int[] { 10, 100, 1000, 10000 };
for(int sizeIndex = 0; sizeIndex < sizes.Length; sizeIndex++)
{
string holaMundo = "";
for(int i = 0; i < sizes[sizeIndex]; i+= 5)
{
holaMundo += "ABCDE";
}
string.Format("\n**** For size: {0} ****\n", sizes[sizeIndex]).Dump();
string odnuMaloh = DotNetReverse(holaMundo);
var stopWatch = Stopwatch.StartNew();
string result = NaiveReverse(holaMundo);
("Naive Ticks: " + stopWatch.ElapsedTicks).Dump();
stopWatch.Restart();
result = Reverse(holaMundo);
("Efficient linear Ticks: " + stopWatch.ElapsedTicks).Dump();
stopWatch.Restart();
result = RecursiveReverse(holaMundo);
("Recursive Ticks: " + stopWatch.ElapsedTicks).Dump();
stopWatch.Restart();
result = DotNetReverse(holaMundo);
("DotNet Reverse Ticks: " + stopWatch.ElapsedTicks).Dump();
}
}
输出
尺寸:10
Naive Ticks: 1
Efficient linear Ticks: 0
Recursive Ticks: 2
DotNet Reverse Ticks: 1
尺寸:100
Naive Ticks: 2
Efficient linear Ticks: 1
Recursive Ticks: 12
DotNet Reverse Ticks: 1
规格:1000
Naive Ticks: 5
Efficient linear Ticks: 2
Recursive Ticks: 358
DotNet Reverse Ticks: 9
尺寸:10000
Naive Ticks: 32
Efficient linear Ticks: 28
Recursive Ticks: 84808
DotNet Reverse Ticks: 33