我知道mergesort的最坏情况是O(nlogn),与普通情况相同。
但是,如果数据是升序或降序,则会导致最小比较次数,因此mergesort变得比随机数据更快。所以我的问题是:什么样的输入数据产生最大比较数导致mergesort变慢?
this问题的回答是:
对于某些排序算法(例如快速排序),初始顺序 元素可以影响要完成的操作数。不过它 不会对mergesort进行任何更改,因为它必须完全执行 无论如何,相同数量的操作:递归地分成小的 数组,然后将它们合并回来,总Θ(nlogn)时间。
然而这是错误的。在这一点上,我们有两个子阵列,如果初始数据已经排序,我们想合并它们,我们将只进行n / 2次比较。这是第一个子阵列的所有元素,仅第二个数组的第一个元素。但是,我们可以实现更多目标。我正在寻找输入数据。
答案 0 :(得分:64)
合并排序的最坏情况将是合并排序必须执行最大比较次数的情况。
所以我会尝试以自下而上的方式构建最糟糕的情况:
假设排序后的最后一步中的数组是{0,1,2,3,4,5,6,7}
对于最坏的情况,此步骤之前的数组必须为{0,2,4,6,1,3,5,7}
,因为此处左侧子阵列为{0,2,4,6}
而右侧子阵列为{1,3,5,7}
将导致最大比较。(在左右子阵列中存储备用元素)
原因:数组的每个元素至少会进行一次比较。
为前面的步骤对左右子阵列应用相同的上述逻辑:对于数组{0,2,4,6}
,最糟糕的情况是前一个数组是{0,4}
和{2,6}
以及数组{1,3,5,7}
最糟糕的情况是{1,5}
和{3,7}
。
{0,4}
必须为{4,0}
,{2,6}
必须为{6,2}
,{1,5}
必须为{5,1}
{ {1}}必须为{3,7}
。好吧,如果你看清楚这一步是没必要,因为如果set / array的大小是2,那么即使大小为2的数组已经排序,每个元素也至少会进行一次比较。{7,3}
现在,您可以对任何大小为n
的数组应用相同的逻辑以下是实现上述逻辑的程序。
注意:以下程序仅对2的幂有效。这是为任何大小为n的数组提供最坏情况的通用方法。您可以自己尝试使用不同的数组进行输入。
Applying Merge Sort using Divide and Conquer
Input array arr[] = [4,0,6,2,5,1,7,3]
/ \
/ \
[4,0,6,2] and [5,1,7,3]
/ \ / \
/ \ / \
[4,0] [6,2] [5,1] [7,3] Every pair of 2 will be compared atleast once therefore maximum comparison here
| | | |
| | | |
[0,4] [2,6] [1,5] [3,7] Maximum Comparison:Every pair of set is used in comparison
\ / \ /
\ / \ /
[0,2,4,6] [1,3,5,7] Maximum comparison again: Every pair of set compared
\ /
\ /
[0,1,2,3,4,5,6,7]
输出:
class MergeWorstCase
{
public static void print(int arr[])
{
System.out.println();
for(int i=0;i<arr.length;i++)
System.out.print(arr[i]+" ");
System.out.println();
}
public static void merge(int[] arr, int[] left, int[] right) {
int i,j;
for(i=0;i<left.length;i++)
arr[i]=left[i];
for(j=0;j<right.length;j++,i++)
arr[i]=right[j];
}
//Pass a sorted array here
public static void seperate(int[] arr) {
if(arr.length<=1)
return;
if(arr.length==2)
{
int swap=arr[0];
arr[0]=arr[1];
arr[1]=swap;
return;
}
int i,j;
int m = (arr.length + 1) / 2;
int left[] = new int[m];
int right[] = new int[arr.length-m];
for(i=0,j=0;i<arr.length;i=i+2,j++) //Storing alternate elements in left subarray
left[j]=arr[i];
for(i=1,j=0;i<arr.length;i=i+2,j++) //Storing alternate elements in right subarray
right[j]=arr[i];
seperate(left);
seperate(right);
merge(arr, left, right);
}
public static void main(String args[])
{
int arr1[]={0,1,2,3,4,5,6,7};
seperate(arr1);
System.out.print("For array 1:");
print(arr1);
int arr2[]={0,1,2,3,4,5,6,7,8};
seperate(arr2);
System.out.print("For array 2:");
print(arr2);
}
}
答案 1 :(得分:4)
一个简洁的算法我的一位教授让我用相反的方法解决了这个问题。您可以从基本案例开始并遵循递归模式,而不是将初始数组拆分为越来越小的块。
基本情况是[1]和[2,1],它们是大小为1
和2
的最坏情况数组的示例。从中可以构建3
和4
的数组,如下所示。
n
和m
的数组,例如n + m = x
,其中x是您正在寻找的尺寸使用此算法,这里是大小为3
和4
的数组的一系列步骤。
3
[1] + [2, 1]
[1 | 2, 1]
[2 | 2, 1]
[2 | 3, 1] -> [2, 3, 1]
4
[2, 1] + [2, 1]
[2, 1 | 2, 1]
[4, 2 | 2, 1]
[4, 2 | 3, 1] -> [4, 2, 3, 1]
7
[2, 3, 1] + [4, 2, 3, 1]
[2, 3, 1 | 4, 2, 3, 1]
[4, 6, 2 | 4, 2, 3, 1]
[4, 6, 2 | 7, 3, 5, 1] -> [4, 6, 2, 7, 3, 5, 1]
很容易看出如何采用这种方法并轻松构建大型阵列。
这是一个实现此算法的python函数。
import math
def worstCaseArrayOfSize(n):
if n == 1:
return [1]
else:
top = worstCaseArrayOfSize(int(math.floor(float(n) / 2)))
bottom = worstCaseArrayOfSize(int(math.ceil(float(n) / 2)))
return map(lambda x: x * 2, top) + map(lambda x: x * 2 - 1, bottom)