为什么Java中的字符串比较(CompareTo)比C#中更快
本文关键字:CompareTo Java 字符串 比较 为什么 | 更新日期: 2023-09-27 18:02:28
编辑3:
使用
StringComparer comparer1 = StringComparer.Ordinal;
而不是
IComparable v
IComparable w
comparer1.Compare(v, w)
解决了运行时问题。
我在Java和C#中做了一些排序算法的基准测试(例如Quicksort、Mergesort(。
我使用了Java 7和。NET Framework 4.5来实现和执行我的算法。结果表明,所有算法都可以使用Java实现更好的运行时间。
Quicksort:的一些运行时示例
C#
- n=1000000 4433毫秒
- n=2000000 10047毫秒
Java
- n=1000000 1311毫秒
- n=2000000 3164毫秒
然后,我使用评测工具进行了测量:C#使用75%的运行时进行字符串比较(即CompareTo(,而Java只使用2%的运行时来进行比较。
为什么字符串比较在C#中如此昂贵而在Java中却如此昂贵?
编辑:我还测试了C#排序函数Arrays.sort(INPUT(,当n=1000000时,它可以达到大约3000ms,所以我认为代码不是问题所在。但无论如何:
这是快速分拣的代码:
public class Quicksort {
public static void sort(IComparable[] a) {
sort(a, 0, a.Length - 1);
}
private static void sort(IComparable[] a, int lo, int hi) {
if (hi <= lo) return;
int j = partition(a, lo, hi);
sort(a, lo, j-1);
sort(a, j+1, hi);
}
private static int partition(IComparable[] a, int lo, int hi) {
int i = lo;
int j = hi + 1;
IComparable v = a[lo];
while (true) {
while (less(a[++i], v))
if (i == hi) break;
while (less(v, a[--j]))
if (j == lo) break;
if (i >= j) break;
exch(a, i, j);
}
exch(a, lo, j);
return j;
}
public static IComparable select(IComparable[] a, int k) {
if (k < 0 || k >= a.Length) {
throw new Exception("Selected element out of bounds");
}
Rnd.Shuffle(a);
int lo = 0, hi = a.Length - 1;
while (hi > lo) {
int i = partition(a, lo, hi);
if (i > k) hi = i - 1;
else if (i < k) lo = i + 1;
else return a[i];
}
return a[lo];
}
private static bool less(IComparable v, IComparable w) {
return (v.CompareTo(w) < 0);
}
private static void exch(Object[] a, int i, int j) {
Object swap = a[i];
a[i] = a[j];
a[j] = swap;
}
}
快速分拣的测量如下:
Stopwatch.Restart();
Quicksort.sort(stringArray);
Stopwatch.Stop();
第二版:有人想看看Java版本。这完全一样,我只是用Comparable代替IComparable,用Array.length代替Array。长度
所以我不认为代码是的问题
我不同意。在这两种情况下,你不是在比较相同的东西。诚然,您也没有向我们展示如何生成字符串等,但Java和。NET执行不同的默认字符串比较。
来自Java的String.compareTo
:
按字典顺序比较两个字符串。
以及来自。NET的String.CompareTo
:
此方法使用当前区域性执行单词(区分大小写和区域性(比较。
毫不奇怪,这比纯粹的词典学比较要慢。
仅仅进行比较就很容易看出这一点。NET本身。。。
using System;
using System.Diagnostics;
using System.Text;
class Test
{
static void Main()
{
string[] source = GenerateRandomStrings();
string[] workingSpace = new string[source.Length];
CopyAndSort(source, workingSpace);
Stopwatch sw = Stopwatch.StartNew();
for (int i = 0; i < 1000; i++)
{
CopyAndSort(source, workingSpace);
}
sw.Stop();
Console.WriteLine("Elapsed time: {0}ms",
(long) sw.Elapsed.TotalMilliseconds);
}
static string[] GenerateRandomStrings()
{
Random rng = new Random();
string[] ret = new string[10000];
for (int i = 0; i < ret.Length; i++)
{
ret[i] = GenerateRandomString(rng);
}
return ret;
}
static string GenerateRandomString(Random rng)
{
char[] chars = new char[30];
for (int i = 0; i < chars.Length; i++)
{
chars[i] = (char) rng.Next('A', 'z' + 1);
}
return new string(chars);
}
static void CopyAndSort(string[] original, string[] workingSpace)
{
Array.Copy(original, 0, workingSpace, 0, original.Length);
Array.Sort(workingSpace);
// Array.Sort(workingSpace, StringComparer.Ordinal);
}
}
您可以自己尝试,根据是否指定序号字符串比较器来更改CopyAndSort
方法。至少在我的盒子上,使用顺序比较器的速度要快得多。
我不是100%确定,但我认为在C#中。Net平台可能会在默认情况下进行一些扩展检查,如正确跳过注释或空白unicode字符,而Java可能不会在缺省情况下进行这些检查。我认为Java的运行时执行更简单的字节2字节比较,但我在这里可能大错特错,因为我已经很久没有接触过在Java中使用编码的细节了,所以这纯粹是猜测。
另一件事是:这两个平台之间的默认比较行为可能存在一些差异。如果你只是使用默认值,而没有任何精确的设置,我猜你只是含蓄地要求不同的行为。
至少在。Net有许多字符串比较选项。您可能只是简单地使用了外观相似的函数,该函数实际上与Java的函数进行了不同的比较。你有没有尝试过像这样的详细过载http://msdn.microsoft.com/en-us/library/cc190416.aspx?请注意,这是一种static
方法,使用方式略有不同:
var result1 = "mom".CompareTo("dad");
var result2 = string.Compare("mom", "dad", ...);
请调查ComparisonOptions和/或CultureInfo设置,并对它们进行调整,使整体行为尽可能与Java的行为相匹配。此外,如果有更多的重载,您可能还必须在Java端选择不同的重载。
此外,另一个区别可能是有些棘手的事实,即您正在测试的CompareTo方法是IComparable<T>
接口的实现,该接口旨在交叉比较实现该接口的各种对象,而静态Compare
方法旨在仅比较字符串。它们可能只是针对不同的事情进行了优化。如果它们之间有任何性能差异,我敢打赌静态Compare
在字符串与字符串比较中会更快。