在Java中优化Mergesort for O(Nlog(N))

时间:2013-06-14 01:18:44

标签: java algorithm sorting big-o mergesort

合作伙伴和我正在尝试用Java编写Mergesort。我们已经完成了算法,并且它正常运行。但是,在测试各种输入的算法时,我们注意到它不在O(Nlog(N))的范围内执行。我们一直在尝试进一步优化算法,并将欣赏任何和所有建议。唯一的要求是我们无法更改方法标头。我们的Java代码如下:

    /**
 * MergeSort algorithm driver.
 * 
 * @param arr - input ArrayList of objects
 */
public static <T extends Comparable<? super T>> void mergesort(
        ArrayList<T> arr)
{
    // Pre-allocation of a temporary ArrayList
    // for merge space.
    ArrayList<T> temp = new ArrayList<T>(arr.size());
    temp.addAll(arr);

    // Call the recursive mergesort method.
    mergesort(arr, temp, 0, arr.size() - 1);
}

/**
 * Main mergeSort method. Makes recursive calls. 
 * 
 * @param arr - input ArrayList of objects
 * @param temp - temporary ArrayList to hold the merged result 
 * @param left - start of the subarray 
 * @param right - end of the subarray
 */
private static <T extends Comparable<? super T>> void mergesort(
        ArrayList<T> arr, ArrayList<T> temp, int left, int right)
{

    // If the size of the subcollection is less than a given threshold,
    // then perform an insertion sort rather than a mergesort.
    //if ((right - left) < threshold)
    //  insertionsort(arr, left, right);


    // If the size of the subcollection was not less than our threshold and 
    // the left end is less than the right end of subcollection, then we are 
    // done performing the sort.
    if(left < right)
    {
        int center = (left + right) / 2;
        mergesort(arr, temp, left, center);
        mergesort(arr, temp, center + 1, right);
        merge(arr, temp, left, right);
    }
}

/**
 * Internal method for merging two sorted subarrays. This is to be used with the 
 * mergesort algorithm.
 * 
 * @param arr - input ArrayList of objects
 * @param temp - temporary ArrayList in  which the result with be placed
 * @param currentLeft - start of the subarray 
 * @param rightEnd - end of the subarray
 */
private static <T extends Comparable<? super T>> void merge(
        ArrayList<T> arr, ArrayList<T> temp, int leftStart, int rightEnd)
{
    int currentLeft = leftStart;
    int leftEnd = (currentLeft + rightEnd) / 2;
    int rightStart = leftEnd + 1;


    // Main loop - compares the value in the left position
    // to the value in the right position.  
    while( currentLeft <= leftEnd &&  rightStart <= rightEnd)
    {
        // If the value in the left position is less than the right, 
        // place the left position value in the temporary collections.
        if(arr.get(currentLeft).compareTo(arr.get(rightStart)) <= 0)
        {
            temp.add(arr.get(currentLeft++));

        }


        // Otherwise, place the value in the rightStart position in
        // the temporary collection.
        else
        {
            temp.add(arr.get(rightStart++));

        }
    }

    // Copy the remaining left half.
    while( currentLeft <= leftEnd )
        temp.add(arr.get(currentLeft++));


    // Copy the remaining right half.
    while( rightStart <= rightEnd )
        temp.add(arr.get(rightStart++));


    // Loop through the temporary collection and for each element
    // currently in the collection, copy the contents back into the
    // original collection.
    for (int i = leftStart, count = 0; i <= rightEnd; i++, count++)
        arr.set(i, temp.get(count));

    // After the above operation has been completed for this particular
    // call, clear the temporary collection.
    temp.clear();

}

2 个答案:

答案 0 :(得分:6)

将我的评论转换为答案 -

要说算法具有运行时O(n log n),意味着函数的运行时将完全匹配函数f(n)= n log n的图。相反,它意味着函数的运行时以与函数n log n的运行时相同的速率增长。因此,对于大n,如果您将输入的大小加倍,则运行时应略大于两倍。

你提到函数的运行时间大约是n log n值的三倍,这实际上证明你有一个O(n log n)运行时 - 你的函数运行时大约是3n log n,这意味着它的运行时间为O(n log n),因为big-O忽略常数因子。为了更加数学上准确 - 你可能的常数可能不是3,因为n的值是无量纲的(它测量数量),而运行时间是几秒钟,所以这里有一些单位转换。

希望这有帮助!

答案 1 :(得分:0)

由于@templatetypedef已经取消了BigO部分,让我们转到优化部分。我不懂Java语言,但这种方法是自我解释的。我注意到,在合并时,请继续添加并清除临时列表。

temp.add(arr.get(currentLeft++));
// ...
// ...
temp.add(arr.get(rightStart++));
// ...
// ...
temp.clear();

将项目附加到数组中不会花费任何时间。

相关问题