我正在通过Coursera学习Algorithms, Part I,并希望测试快速查找,快速联盟和加权快速联盟算法的运行时间。这门课程是用Java编写的,我不熟悉,所以我已经完成并尝试在Python中重新创建算法,我更熟悉。
现在我已经完成了所有工作,我的目标是测试每个函数以验证运行时间/复杂性。我一直在考虑使用timeit库,但这似乎会导致不正确的结果,例如,加权快速联盟比QuickUnion需要更长的时间才能完成。
如何验证加权快速联盟实际上是O(log n)并且比Quick Union快?以下是我迄今为止创建和尝试的内容:
class QuickFind_Eager:
def __init__(self, nodes):
self.array = [num for num in range(nodes)]
# Joins two nodes into a component
def union(self, first_node, second_node):
for pos, val in enumerate(self.array):
if self.array[pos] == self.array[first_node]:
self.array[pos] = self.array[second_node]
# Checks if two nodes are in the same component
def connected(self, first_node, second_node):
return self.array[first_node] == self.array[second_node]
class QuickUnion_Lazy:
def __init__(self, nodes):
self.array = [num for num in range(nodes)]
# Follows parent pointers to actual root
def root(self, parent):
while parent != self.array[parent]:
parent = self.array[parent]
return parent
# Joins two nodes into a component
def union(self, first_node, second_node):
self.array[first_node] = self.array[second_node]
# Checks if two nodes are in the same component
def connected(self, first_node, second_node):
return self.root(first_node) == self.root(second_node)
class WeightedQuickUnion:
def __init__(self, nodes):
self.array = [num for num in range(nodes)]
self.weight = [num for num in range(nodes)]
# Follows parent pointers to actual root
def root(self, parent):
while parent != self.array[parent]:
parent = self.array[parent]
return parent
# Joins two nodes into a component
def union(self, first_node, second_node):
if self.root(first_node) == self.root(second_node):
return
if (self.weight[first_node] < self.weight[second_node]):
self.array[first_node] = self.root(second_node)
self.weight[second_node] += self.weight[first_node]
else:
self.array[second_node] = self.root(first_node)
self.weight[first_node] += self.weight[second_node]
# Checks if two nodes are in the same component
def connected(self, first_node, second_node):
return self.root(first_node) == self.root(second_node)
class WeightedQuickUnion_PathCompression:
def __init__(self, nodes):
self.array = [num for num in range(nodes)]
self.weight = [num for num in range(nodes)]
# Follows parent pointers to actual root
def root(self, parent):
while parent != self.array[parent]:
self.array[parent] = self.array[self.array[parent]]
parent = self.array[parent]
return parent
# Joins two nodes into a component
def union(self, first_node, second_node):
if self.root(first_node) == self.root(second_node):
return
if self.weight[first_node] < self.weight[second_node]:
self.array[first_node] = self.root(second_node)
self.weight[second_node] += self.weight[first_node]
else:
self.array[second_node] = self.root(first_node)
self.weight[first_node] += self.weight[second_node]
# Checks if two nodes are in the same component
def connected(self, first_node, second_node):
return self.root(first_node) == self.root(second_node)
def test_quickfind(quickfind):
t = quickfind(100)
t.union(1,2)
t.connected(1,2)
t.union(4,2)
t.union(3,4)
t.connected(0,2)
t.connected(1,4)
t.union(0,3)
t.connected(0,4)
import timeit
t = timeit.timeit(stmt="test_quickfind(QuickFind_Eager)", setup="from __main__ import QuickFind_Eager; from __main__ import test_quickfind", number=100000)
print(t)
# 11.4380569069981
t = timeit.timeit(stmt="test_quickfind(QuickUnion_Lazy)", setup="from __main__ import QuickUnion_Lazy; from __main__ import test_quickfind", number=100000)
print(t)
# 1.4744456350017572
t = timeit.timeit(stmt="test_quickfind(WeightedQuickUnion)", setup="from __main__ import WeightedQuickUnion; from __main__ import test_quickfind", number=100000)
print(t)
# 2.738758583996969
t = timeit.timeit(stmt="test_quickfind(WeightedQuickUnion_PathCompression)", setup="from __main__ import WeightedQuickUnion_PathCompression; from __main__ import test_quickfind", number=100000)
print(t)
# 3.0113827050008695
更新 添加了timeit的结果。
答案 0 :(得分:2)
您需要将算法制成表格&#39;运行时间作为问题大小的函数,即。针对不同的问题规模调用quickfind
(比如100,200,300,400,500;请注意,期望后者至少运行3分钟的天真O(n^2)
算法。)
您仍然无法保证您观察到渐近运行时函数(O
符号的含义:O(f)
实际上描述了一系列函数g_i
, g_i = a_i * f(n) + b_i; a_i, b_i: const
[有点滥用符号]),因为你的某些实现可能会遇到资源耗尽(读取:不再使用ram),导致性能超出实现范围。
答案 1 :(得分:0)
在QuickFindEager类中实现并集函数不正确。
self.array[first_node]
和self.array[second_node]
应该在循环之前添加到变量中,而不是在变量中循环更改
def union(self, first_node, second_node):
pid = self.array[first_node]
qid = self.array[second_node]
for pos, val in enumerate(self.array):
if self.array[pos] == pid:
self.array[pos] = qid