计算比较次数并使用编程和/或数学分析特定算法的效率

时间:2013-10-01 17:18:59

标签: python algorithm sorting analysis review

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等严格小的值,然后每次进行任何比较时,我都会递增计数器并返回最终计数,然后尝试在输出中找出某种模式,但是这似乎是一种效率低下的方法。

有没有办法以与合并排序中经典合并的分析相似的方式来计算它?

2 个答案:

答案 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<L1L1<L3那么就没有必要比较L2和{ {1}}因为您已经知道L3较小。

编辑时:要证明这实际上是最糟糕的情况应该不会太难。假设没有列表为空,则每次迭代的比较次数为:

  • 3如果L3最小且L1 <1。 L2
  • 2如果L2最小
  • 1,如果L1最小

那就是给你一个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)