我在Python之前的大部分编程是C++或MATLAB。我没有计算机科学学位(几乎完成了物理学博士学位),但我已经完成了一些课程和大量的实际编程。现在,我在上Coursera的一门算法课程(顺便说一句,斯坦福大学的一位教授的课程非常好)。我决定用Python实现家庭作业。然而,有时我发现自己想要的东西,语言不那么容易支持。我非常习惯于在C++中创建类和对象,以便将数据分组在一起(即,当没有方法时)。但是在Python中,你可以动态地添加字段,我最终想要的是Matlab结构。我想这可能是我没有用好的风格和“Python式”的方式做事。在
下面是我对union-find数据结构的实现(对于Kruskal的算法)。虽然这个实现相对较短并且工作良好(没有太多的错误检查),但也有一些奇怪的地方。例如,我的代码假设最初传递给union find的数据是一个对象列表。但是,如果传递的是显式数据片段列表(即int列表),则代码将失败。有没有更清晰、更具Python式的方法来实现这一点?我试着用google搜索,但是大多数例子都非常简单,并且更多地与过程代码相关(即在python中实现for循环的“正确”方式)。在
class UnionFind:
def __init__(self,data):
self.data = data
for d in self.data:
d.size = 1
d.leader = d
d.next = None
d.last = d
def find(self,element):
return element.leader
def union(self,leader1,leader2):
if leader1.size >= leader2.size:
newleader = leader1
oldleader = leader2
else:
newleader = leader2
oldleader = leader1
newleader.size = leader1.size + leader2.size
d = oldleader
while d != None:
d.leader = newleader
d = d.next
newleader.last.next = oldleader
newleader.last = oldleader.last
del(oldleader.size)
del(oldleader.last)
一般来说,以pythonical的方式做这类事情意味着你试图让你的代码不在乎被赋予了什么,至少不会比它真正需要的更多。在
让我们以您的union-find算法为例。union-find算法对传递给它的值的唯一实际操作是比较它们是否相等。因此,要生成一个通常有用的
UnionFind
类,代码不应该依赖于它接收到的值,而不是进行相等性测试。特别是,您不应该依赖于能够为值分配任意属性。在我建议解决这个问题的方法是让} ,或者制作一个小的包装类。当一个元素被添加到
UnionFind
使用包含给定值和使算法工作所需的任何属性的包装器对象。您可以按照另一个答案的建议使用^{UnionFind
时,首先将其包装在其中一个对象中,并使用包装器对象存储属性leader
、size
等。访问被包装的对象的唯一时间是检查它是否等于另一个值。在实际上,至少在这种情况下,可以安全地假设值是散列的,这样就可以在Python字典中使用它们作为键来查找与给定值对应的包装器对象。当然,并不是Python中的所有对象都必须是散列的,但是那些不属于散列的对象相对较少,要制作一个能够处理这些对象的数据结构还需要大量的工作。在
更像Python的方法是避免单调乏味的物体,如果你不需要的话。在
一种选择是使用字典来存储所需的有关数据项的信息,而不是直接存储该项上的属性。例如,您可以引用
d.size
,而不是引用size[d]
(其中size
是dict
实例)。这要求您的数据项是可散列的,但不需要允许对它们分配属性。在下面是使用此样式的当前代码的直接翻译:
最小测试用例:
^{pr2}$除此之外,您还可以考虑稍微更改一下您的实现,以减少初始化的需要。这是一个不做任何初始化的版本(它甚至不需要知道要处理的数据集)。它使用路径压缩和按等级联合,而不是始终为一个集合的所有成员维护一个最新的
leader
值。它应该比您当前的代码快得多,尤其是当您正在进行大量联合时:相关问题 更多 >
编程相关推荐