我正在使用Mergesort订购50.000.000字符串,根据我使用的参数类型,有两种不同的结果。
使用IComparable接口:
直接使用字符串:
Mergesort代码:
public class Mergesort2
{
static private StringComparer comparer1 = StringComparer.Ordinal;
public static void merge(IComparable[] a, IComparable[] aux, int lo, int mid, int hi)
{
for (int k = lo; k <= hi; k++)
{
aux[k] = a[k];
}
// merge back to a[]
int i = lo, j = mid + 1;
for (int k = lo; k <= hi; k++)
{
if (i > mid)
{
a[k] = aux[j++];
}
else if (j > hi)
{
a[k] = aux[i++];
}
else if (less(aux[j], aux[i]))
{
a[k] = aux[j++];
}
else
{
a[k] = aux[i++];
}
}
}
private static void sort(IComparable[] a, IComparable[] aux, int lo, int hi)
{
if (hi <= lo)
{
return;
}
int mid = lo + (hi - lo) / 2;
sort(a, aux, lo, mid);
sort(a, aux, mid + 1, hi);
merge(a, aux, lo, mid, hi);
}
public static void sort(IComparable[] a)
{
IComparable[] aux = new IComparable[a.Length];
sort(a, aux, 0, a.Length - 1);
}
///*********************************************************************
/// Helper sorting functions
/// **********************************************************************
// is v < w ?
private static bool less(IComparable v, IComparable w)
{
return (comparer1.Compare(v, w) < 0);
}
// exchange a[i] and a[j]
private static void exch(Object[] a, int i, int j)
{
Object swap = a[i];
a[i] = a[j];
a[j] = swap;
}
/// <summary>
///*********************************************************************
/// Index mergesort
/// **********************************************************************
/// </summary>
// stably merge a[lo .. mid] with a[mid+1 .. hi] using aux[lo .. hi]
private static void merge(IComparable[] a, int[] index, int[] aux, int lo, int mid, int hi)
{
// copy to aux[]
for (int k = lo; k <= hi; k++)
{
aux[k] = index[k];
}
// merge back to a[]
int i = lo, j = mid + 1;
for (int k = lo; k <= hi; k++)
{
if (i > mid)
{
index[k] = aux[j++];
}
else if (j > hi)
{
index[k] = aux[i++];
}
else if (less(a[aux[j]], a[aux[i]]))
{
index[k] = aux[j++];
}
else
{
index[k] = aux[i++];
}
}
}
// return a permutation that gives the elements in a[] in ascending order
// do not change the original array a[]
public static int[] indexSort(IComparable[] a)
{
int N = a.Length;
int[] index = new int[N];
for (int i = 0; i < N; i++)
{
index[i] = i;
}
int[] aux = new int[N];
sort(a, index, aux, 0, N - 1);
return index;
}
// mergesort a[lo..hi] using auxiliary array aux[lo..hi]
private static void sort(IComparable[] a, int[] index, int[] aux, int lo, int hi)
{
if (hi <= lo)
{
return;
}
int mid = lo + (hi - lo) / 2;
sort(a, index, aux, lo, mid);
sort(a, index, aux, mid + 1, hi);
merge(a, index, aux, lo, mid, hi);
}
}
此代码产生慢运行时。
如果我将所有 IComparable 类型更改为字符串,性能会提高。为什么使用不同的类型存在如此巨大的性能差异?
答案 0 :(得分:1)
回答有关性能的问题:您的测试使用的字符串足够小,以至于使用非通用IComparable
接口所需的附加类型检查,以及使用interface-dispatch而不是virtual-dispatch (像.NET和Java VM这样的虚拟机的低级细节)比字符串比较更昂贵。如果您使用具有长公共前缀的字符串,则比较操作将成为主要的性能成本,并且两个表单之间的差距将关闭。 编辑:在代码的发布版本上运行测试也可能缩小差距(没有在本地运行测试,我不确定构建用于测试的OP是什么)。
现在更重要的是整个实验, 忽略代码的所有其他问题 ,我将具体指出支持“可比”项目的常见做法在.NET中以通用方式。
T
(可能是string
,也可能不是IComparable
,如果它可能会或可能不会实现IComparer<T>
。)null
来比较元素。如果用户将comparer
参数的Comparer<T>.Default
传递给其中一个公共方法,则默认为public class Mergesort2
{
public static void merge<T>(T[] a, T[] aux, int lo, int mid, int hi, IComparer<T> comparer)
{
comparer = comparer ?? Comparer<T>.Default;
for (int k = lo; k <= hi; k++)
{
aux[k] = a[k];
}
// merge back to a[]
int i = lo, j = mid + 1;
for (int k = lo; k <= hi; k++)
{
if (i > mid)
{
a[k] = aux[j++];
}
else if (j > hi)
{
a[k] = aux[i++];
}
else if (less(aux[j], aux[i], comparer))
{
a[k] = aux[j++];
}
else
{
a[k] = aux[i++];
}
}
}
private static void sort<T>(T[] a, T[] aux, int lo, int hi, IComparer<T> comparer)
{
if (hi <= lo)
{
return;
}
int mid = lo + (hi - lo) / 2;
sort(a, aux, lo, mid, comparer);
sort(a, aux, mid + 1, hi, comparer);
merge(a, aux, lo, mid, hi, comparer);
}
public static void sort<T>(T[] a, IComparer<T> comparer)
{
comparer = comparer ?? Comparer<T>.Default;
T[] aux = new T[a.Length];
sort(a, aux, 0, a.Length - 1, comparer);
}
///*********************************************************************
/// Helper sorting functions
/// **********************************************************************
// is v < w ?
private static bool less<T>(T v, T w, IComparer<T> comparer)
{
return (comparer.Compare(v, w) < 0);
}
// exchange a[i] and a[j]
private static void exch<T>(T[] a, int i, int j)
{
T swap = a[i];
a[i] = a[j];
a[j] = swap;
}
/// <summary>
///*********************************************************************
/// Index mergesort
/// **********************************************************************
/// </summary>
// stably merge a[lo .. mid] with a[mid+1 .. hi] using aux[lo .. hi]
private static void merge<T>(T[] a, int[] index, int[] aux, int lo, int mid, int hi, IComparer<T> comparer)
{
// copy to aux[]
for (int k = lo; k <= hi; k++)
{
aux[k] = index[k];
}
// merge back to a[]
int i = lo, j = mid + 1;
for (int k = lo; k <= hi; k++)
{
if (i > mid)
{
index[k] = aux[j++];
}
else if (j > hi)
{
index[k] = aux[i++];
}
else if (less(a[aux[j]], a[aux[i]], comparer))
{
index[k] = aux[j++];
}
else
{
index[k] = aux[i++];
}
}
}
// return a permutation that gives the elements in a[] in ascending order
// do not change the original array a[]
public static int[] indexSort<T>(T[] a, IComparer<T> comparer)
{
comparer = comparer ?? Comparer<T>.Default;
int N = a.Length;
int[] index = new int[N];
for (int i = 0; i < N; i++)
{
index[i] = i;
}
int[] aux = new int[N];
sort(a, index, aux, 0, N - 1, comparer);
return index;
}
// mergesort a[lo..hi] using auxiliary array aux[lo..hi]
private static void sort<T>(T[] a, int[] index, int[] aux, int lo, int hi, IComparer<T> comparer)
{
if (hi <= lo)
{
return;
}
int mid = lo + (hi - lo) / 2;
sort(a, index, aux, lo, mid, comparer);
sort(a, index, aux, mid + 1, hi, comparer);
merge(a, index, aux, lo, mid, hi, comparer);
}
}
。以下是更新后的代码:
{{1}}
答案 1 :(得分:-3)
恕我直言,我不得不简单地说:对象本身的大小...所以每当你声明一个包含一堆额外属性,方法等的ICompare时,它需要比你更多的时间声明较小的字符串......