合作伙伴和我正在尝试用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();
}
答案 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();
将项目附加到数组中不会花费任何时间。