def three_way_merge(L1,L2,L3):
L = []
i1 = 0
i2 = 0
i3 = 0
done1 = False
done2 = False
done3 = False
while not (done1 and done2 and done3):
if not done1 and (done2 or L1[i1] < L2[i2]) and (done3 or L1[i1] < L3[i3]):
L.append(L1[i1])
i1 += 1
done1 = i1 >= len(L1)
elif not done2 and (done3 or L2[i2] < L3[i3]):
L.append(L2[i2])
i2 += 1
done2 = i2 >= len(L2)
else:
L.append(L3[i3])
i3 += 1
done3 = i3 >= len(L3)
return L
我想计算我发现的这个算法的最差可能数量的比较,因为我的算法课程中有一个考试,我希望能够进行这种分析。我的想法是写一个程序,创建这个“最坏情况”的许多随机例子(我猜这是类型的东西:L1 = [9,10,11], L2 = [6,7,8], L3 = [3,4,5]
,其中所有列表都被排序但是L3
和{{ 1}}具有比L2
等严格小的值,然后每次进行任何比较时,我都会递增计数器并返回最终计数,然后尝试在输出中找出某种模式,但是这似乎是一种效率低下的方法。
有没有办法以与合并排序中经典合并的分析相似的方式来计算它?
答案 0 :(得分:1)
作为一般规则,生成随机输入并不是解决最坏情况运行时间的好方法。例如,quicksort平均在O(n log n)中运行,但在最坏的情况下,它以O(n ^ 2)运行。但是,即使你生成了大量的随机样本,对于中等大小的n,你也永远不会接近最坏的情况。相反,尝试手动构建最坏情况输入。
在这种情况下,似乎最坏的情况,假设每个数组的长度为N,如果
L1 = (N,2N,2N+1,...,3N-3,3N)
L2 = (N+1,N+2,...,2N-1,3N-1)
L3 = (1,2,...,N-1,3N-2)
要了解原因,请跟踪算法的执行情况。首先发生的事情是L3
的前N-1个元素会被添加到L
。循环的每个迭代将进行3次比较:第一次if
语句中有两次,第二次中有一次。请注意,我们需要L1[1]<L2[1]
否则它会跳过第一个if
接下来将是元素L[1]=N
,它仅进行一次比较。
在此之后出现L[2]
的第一个N-1个元素,每个元素需要进行两次比较,一次为L1
,另一次为L3
。
接下来是来自L1
的下一个N-2元素,每个元素都有一个比较。
此时每个列表中只剩下一个元素。首先选择L3
,进行3次比较,然后对L2
进行一次比较,就是这样。
总数
(N-1)*(3+2+1)+3+1 = 6N - 2
我认为这是最糟糕的情况,但你可能会在某处挤出一个。此外,我可能犯了一个错误,在这种情况下,这里有人可能会抓住它。接下来你要做的就是尽量证明这是最糟糕的运行时间。
PS此算法不是合并三个列表的最佳选择。从三个列表的前面挑选最小元素应该最多只需要2次比较,而不是3.如果你发现L2<L1
和L1<L3
那么就没有必要比较L2
和{ {1}}因为您已经知道L3
较小。
编辑时:要证明这实际上是最糟糕的情况应该不会太难。假设没有列表为空,则每次迭代的比较次数为:
那就是给你一个N * 6的上限,因为每个列表只能是最小的N次。因此,完成证明只需要检查列表变空的结束时发生的事情。
答案 1 :(得分:0)
正如您所说,最糟糕的情况是使L3(或L2)的数字小于L1,因为IF子句将失败并且它将执行elif部分计算更多的比较。
在第一个IF内部(假设我们将每个检查布尔值计算为个体比较,如done1,done2等)并考虑到逻辑表达式是以懒惰方式计算的,那么最坏的情况在其他之前永远不会达到done1 = true(保证L1具有比L2和L3更大的值),done2既不能达到真(可以保证L2中的值大于L3中的值),所以L1 [i1]&lt; L2 [i2]在每个步骤中计算。
当L3完成,并且每个周期进入IF部分并且仅执行4次比较,因为done3为真,并且由于懒惰,不计算最后的比较。进入elif部分时也同样适用,只进行了2次比较。
当L2完成时,在IF子句中只进行了3次比较(如do2和done3为真)
因此,具有此配置(L1>&gt;&gt;&gt;&gt; L3)此算法将执行:
Len(L3)*(3(while子句)+ 5(IF子句)+ 3(elif部分)+ 1(done3 calulation))+ Len(L2)*(3(while子句)+ 4(IF子句)+ 2(elif部分)+ 1(done2 calulation))+ Len(L1)*(3(while子句)+ 3(IF子句)+ 1(done1 calulation))
所以最终的计数是
Len(L3)* 12 + Len(L2)* 10 + Len(L1)* 7
在3个数组的排序中,计算顺序是相同的,Order是Len(3)+ Len(2)+ Len(1)