【问题标题】:A generic MergeSort implementation in javajava中的通用MergeSort实现
【发布时间】:2018-06-16 17:34:18
【问题描述】:

我编写了一个 MergeSort 实现,它应该对任何数据类型的数组进行排序。

我在这里面临 2 个问题。

  1. 由于泛型类型不能定义为数组,因为编译器会出错 说“无法创建 T 的通用数组”, 我已经按照 StackOverflow 中的一个线程中建议的 kludge 使用

    T[] right = (T[]) Array.newInstance(clazz, rightSize);

因此,使用在运行时提供的类型信息,我们仍然可以实例化一个数组并将其转换回 T[],尽管无论我们是否处理它,它仍然容易受到 ClassCastException 的影响。

有没有其他有效和理想的方法来实现这一点?

  1. 现在下面的归并排序算法基于泛型工作, 我不能提供像 int[] 这样的原始类型数组来代替 T[]。

那么我是否需要为我想要排序的每个原始类型数组创建 MergeSort 类一个版本?

  1. 总的来说,这个算法可以进一步改进吗?

任何帮助将不胜感激。 谢谢。

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

【问题讨论】:

  • “我不能提供像 int[] 这样的原始类型数组来代替 T[]” - 您可以使用包装类,例如 Integer
  • 最好的解决方案是使用in-place merge sort。这样可以避免创建任何新数组。
  • 感谢 Jacob / Obicere。我将尝试就地合并排序。

标签: java arrays mergesort


【解决方案1】:

对于你的第一个问题:你可以使用

T[] newArray = (T[]) new Object[newSize];

您可以保证此转换将始终成功,并且新数组将始终仅包含Ts。因此,演员阵容得到纠正。要禁止unchecked cast-警告,请用@SuppressWarnings("unchecked") 标记方法。 OpenJDK's implementation of ArrayList 也采用了类似的方法。


对于您的第二个问题:为了获得最佳性能,是的。您应该为每种原始类型提供一个实现。协方差和自动装箱不足以将 int[] 转换为 Integer[]


对于您的第三个问题:您可以重新使用旧数组,而不是为左右部分创建新数组,只需将 leftright 作为参数传递给您的递归调用。有关实现,请参阅 this github link


对代码的注释:在 Java 中,方法名称应始终以小写字母开头。虽然我知道在 C++ 中使用 _ 启动私有方法很常见,但在 Java 中并非如此。


对您的问题的一些一般性评论:

  • 您应该限制自己在每个帖子中回答一个问题。
  • 如果您的代码可以正常运行,并且您希望获得有关代码的反馈,Code Review 可能更适合此。

【讨论】:

  • 感谢您的宝贵时间和回答。下次会尝试 Code Review。
  • 接受了这个答案
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2012-08-31
  • 1970-01-01
  • 1970-01-01
  • 2018-10-06
  • 2017-04-21
  • 1970-01-01
  • 2013-02-19
相关资源
最近更新 更多