[英]A generic MergeSort implementation in java
I have written a MergeSort implementation that should sort an array of any data type.我编写了一个 MergeSort 实现,它应该对任何数据类型的数组进行排序。
Am facing 2 issues here.我在这里面临两个问题。
Since Generic types cannot be defined as an array as the compiler errors out saying that ' cannot create a generic array of T ', I have followed a kludge suggested in one of the threads in StackOverflow to use由于泛型类型不能定义为数组,因为编译器错误说“无法创建 T 的泛型数组”,因此我遵循了 StackOverflow 中的一个线程中建议的 kludge 使用
T[] right = (T[]) Array.newInstance(clazz, rightSize); T[] right = (T[]) Array.newInstance(clazz, rightSize);
so that with the type info supplied during runtime, we still can instantiate an array and cast it back to T[] though it is still vulnerable to ClassCastException irrespective of whether we handle it or not.因此,使用运行时提供的类型信息,我们仍然可以实例化一个数组并将其转换回 T[],尽管无论我们是否处理它,它仍然容易受到 ClassCastException 的影响。
Is there any other efficient and ideal way of achieving this?有没有其他有效和理想的方法来实现这一目标?
So should i need to create the MergeSort class one version for each of primitive typed array that i wanted to sort?那么我是否需要为我想要排序的每个原始类型数组创建一个版本的 MergeSort 类?
Any help would be greatly appreciated.任何帮助将不胜感激。 Thanks.谢谢。
import java.lang.reflect.Array;
import java.util.Arrays;
import java.util.Comparator;
public class MergeSort {
public <T> void sort(T[] values, Class<T> clazz, Comparator<T> comparator) {
if (values == null) {
throw new IllegalArgumentException("values is null.");
}
// recursion exit criteria.
if (values.length < 2) {
return;
}
// segregate the values array into 2 halves.
int median = values.length / 2;
int leftSize = median;
int rightSize = values.length - median;
// construct the left array.
T[] left = (T[]) Array.newInstance(clazz, leftSize);
for (int l = 0; l < leftSize; ++l) {
left[l] = values[l];
}
// construct the right array.
T[] right = (T[]) Array.newInstance(clazz, rightSize);
for (int r = 0; r < rightSize; ++r) {
right[r] = values[leftSize + r];
}
// recursively do merge sort on either side of the array.
sort(left, clazz, comparator);
sort(right, clazz, comparator);
// merges the left and right and keeps the intermediate
// values array sorted as it works it's way up.
_merge(values, left, right, comparator);
}
private <T> void _merge(T[] values, T[] left, T[] right, Comparator<T> comparator) {
int leftIndex = 0;
int rightIndex = 0;
int sortedIndex = 0;
while (leftIndex < left.length && rightIndex < right.length) {
int comparison = comparator.compare(left[leftIndex], right[rightIndex]);
if (comparison <= 0) {
values[sortedIndex] = left[leftIndex];
leftIndex++;
} else {
values[sortedIndex] = right[rightIndex];
rightIndex++;
}
sortedIndex++;
}
// Handle the left over elements if any in the left side
// and places them in the sorted array.
while (leftIndex < left.length) {
values[sortedIndex] = left[leftIndex];
leftIndex++;
sortedIndex++;
}
// Handle the left over elements if any in the right side.
// and places them in the sorted array.
while (rightIndex < right.length) {
values[sortedIndex] = right[rightIndex];
rightIndex++;
sortedIndex++;
}
}
public static void main(String[] args) {
Integer[] values = new Integer[] { 5, 0, 10, 4, 1, 8, 3, 9, 6, 2, 7 };
new MergeSort().sort(values, Integer.class, new Comparator<Integer>() {
@Override
public int compare(Integer o1, Integer o2) {
return o1.compareTo(o2);
}
});
System.out.println(Arrays.toString(values));
}
}
To your first question: You can use对于您的第一个问题:您可以使用
T[] newArray = (T[]) new Object[newSize];
You can guarantee that this cast will always succeed and that the new array will always only hold T
s.您可以保证此转换将始终成功,并且新数组将始终仅包含T
s。 Thus, the cast is rectified 1 .因此,演员阵容得到纠正1 。 To suppress the unchecked cast
-warning, mark the method with @SuppressWarnings("unchecked")
.要抑制unchecked cast
强制转换警告,请使用@SuppressWarnings("unchecked")
标记该方法。 A similar approach is by the way used for OpenJDK's implementation of ArrayList
.一种类似的方法是用于OpenJDK 的ArrayList
实现。
To your second question: For optimal performance, yes.对于您的第二个问题:为了获得最佳性能,是的。 You should provide one implementation per primitive type.您应该为每个原始类型提供一个实现。 Covariance and autoboxing are not sufficient to convert an int[]
into an Integer[]
.协方差和自动装箱不足以将int[]
转换为Integer[]
。
To your third question: Instead of creating new arrays for the left and right part, you could acutally re-use the old array, and just pass left
and right
as parameters down your recursive calls.对于您的第三个问题:您可以重新使用旧数组,而不是为左右部分创建新数组,而只需将left
和right
作为参数传递left
您的递归调用。 See this github link for an implementation.有关实现,请参阅此 github 链接。
A remark on your code: In Java, a method name should always start with a lowercase letter.代码注释:在 Java 中,方法名称应始终以小写字母开头。 While I know that it is common in C++ to start a private methode with an _
, this is not the case in Java.虽然我知道在 C++ 中用_
启动私有方法是很常见的,但在 Java 中情况并非如此。
Some general remarks to your question:对你的问题的一些一般性评论:
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.