Python 分治数组求和还是基于循环的数组求和?
我尝试使用以下两种算法对数组求和:Python 分治数组求和还是基于循环的数组求和?,python,divide-and-conquer,Python,Divide And Conquer,我尝试使用以下两种算法对数组求和: 分而治之 基于朴素循环的算法 代码如下: # Summation divide and conquer def summation(array,left,right): if left == right: return array[left] else: if left == right-1: return array[left] + array[right] else:
- 分而治之
- 基于朴素循环的算法
# Summation divide and conquer
def summation(array,left,right):
if left == right:
return array[left]
else:
if left == right-1:
return array[left] + array[right]
else:
mid = left + (right-left)//2
left_hand = summation(array,left,mid)
right_hand = summation(array,mid+1,right)
return left_hand + right_hand
和
上述两种算法均能正确工作,且均渐近为O(n)
但我无法确定哪一个速度更快。
请帮忙我会这样做:
a = np.random.randint(0, 1000, 10000)
%timeit summation(a, 0, len(a)-1)
3.59 ms ± 81 µs per loop (mean ± std. dev. of 7 runs, 100 loops each)
输出:
%timeit summation_normal(a)
1.29 ms ± 7.45 µs per loop (mean ± std. dev. of 7 runs, 1000 loops each)
请务必记住,这些计时在很大程度上取决于处理器中正在进行的活动以及其他几个因素
显然,求和法是胜利者。在这两种算法中,对数组值执行的加法次数(几乎!)是相同的,但递归算法的开销更大,因此运行速度稍慢 您可以通过二叉树可视化递归算法,获取两个子节点的值并将它们相加到父节点中。因此(数组值的)添加数对应于该树的内部节点数 现在看一个由2个元素组成的短数组(索引为0和1): 加号表示递归算法中发生的唯一加法。现在将一个元素添加到数组中。这意味着其中一个叶节点成为两个叶节点的父节点(添加一个叶节点)。例如:
+
/ \
+ 2
/ \
0 1
因此,现在需要执行另外一个添加:还有一个内部节点。您可以很容易地看到,在这个结构中添加另一个数组元素会使内部节点的数量增加1。因此,将有一个额外的
同样,在树表示法中,叶节点表示数组值,内部节点表示中间求和
二叉树中的叶子数总是比内部节点数多一个。因此,涉及数组值的加法数是n-1。这比迭代解少一个,因为第一个(和额外的)加法是0+array[0]
。您可以从array[0]
开始,并从索引1开始循环,从而改进这一点。如果这样做,两种算法都将执行涉及数组值的n-1加法
显然,递归算法有更多的“内务管理”工作要做:计算中间索引,使用堆栈传递参数等等,因此它会稍微慢一点,但不会有不同的时间复杂度。要进行速度测试吗?然后重复相同的代码10000次,然后测量时间。我尝试使用%timeit。但是我想知道一个比另一个快的原因。但是,你说你无法识别哪一个更快。。。那你现在想说什么?你找到哪一个更快了吗?先生,我在某个地方读到过分治算法更快,但当我尝试%timeit时,结果正好相反。我只是想了解为什么上述两种算法有如此大的差异。计算涉及数组的加法执行的次数。你会发现这两种算法的数字总是相同的。递归算法只是有更多的开销。
+
/ \
0 1
+
/ \
+ 2
/ \
0 1