在Python中从k-d-Tree中删除root

时间:2017-04-04 09:18:50

标签: python kdtree

对于刚接触python的人,我不了解如何从递归函数中删除类的实例。

考虑k-d Tree的代码:

def remove(self, bin, targetAxis=0, parent=None):
  if not self:
    return None
  elif self.data.x == bin.x and self.data.y == bin.y: 
    if self.rightNode:
      self.data = self.rightNode.findMin((targetAxis+1)% KdSearch.DIMENSION)
      self.rightNode = self.rightNode.remove(self.data, (targetAxis+1)% KdSearch.DIMENSION,self)
    elif self.leftNode:
      self.data = self.leftNode.findMin((targetAxis+1)% KdSearch.DIMENSION)
      self.rightNode = self.leftNode.remove(self.data, (targetAxis+1)% KdSearch.DIMENSION,self)
    else:
      if not parent is None:
        #get direction if child....
        if not parent.leftNode is None:
          if parent.leftNode.data.x == bin.x and parent.leftNode.data.y == bin.y:
            parent.leftNode=None

        if not parent.rightNode is None:
          if parent.rightNode.data.x == bin.x and parent.rightNode.data.y == bin.y:
            parent.rightNode=None

      else:
        print("Trying to delete self")
        del self.data
        del self.leftNode
        del self.rightNode
        del self.splittingAxis


  else:
    axis = self.splittingAxis  % KdSearch.DIMENSION
    if axis==0:
      if bin.x <= self.data.x :
        if self.leftNode:
          self.leftNode.remove(bin,(targetAxis+1)% KdSearch.DIMENSION,self)
      else:
        if self.rightNode:
          self.rightNode.remove(bin,(targetAxis+1)% KdSearch.DIMENSION,self)
    else:
      if bin.y <= self.data.y:
        if self.leftNode:
          self.leftNode.remove(bin,(targetAxis+1)% KdSearch.DIMENSION,self)

      else:
        if self.rightNode:
          self.rightNode.remove(bin,(targetAxis+1)% KdSearch.DIMENSION,self)

重要的是这个:

        del self.data
        del self.leftNode
        del self.rightNode
        del self.splittingAxis

如何删除当前实例? del selfself=None或我的方法无效

2 个答案:

答案 0 :(得分:3)

你想要做的事情在文字中没有意义,更不用说在Python中了。您要做的是从树中删除节点 。但是,您没有树对象,只有节点。那么当没有树从树中删除时,如何从树中删除节点?

慷慨,你可以说你在没有显式树类的情况下通过说节点集合是一棵树来实现树。但是你有问题,空树看起来像什么?此外,树的客户端需要对树的引用(因此它可以添加和删除节点),但由于您没有树对象,因此它只能引用节点。因此,客户端是唯一能够清空树的客户端,它必须通过删除对节点的引用来完成。 Python中的对象不可能在不知道这些对象的情况下从其他对象中删除对自身的任意引用,因此您的根节点通常不能从“树”中删除自己,这意味着删除引用客户端持有的节点。要实现这一点,需要在根节点和客户端之间定义一个接口,所以当客户端说“删除这个节点”时,根节点可以回复并说“那就是我,所以删除我,你就有了一棵空树” 。但这会很痛苦。

此外,作为节点集合的隐式概念树违反Zen of Python

  

明确比隐含更好。

所以我建议你实现一个可以为空的显式简单树类,并且你的客户端可以保存对它的引用。如果使它看起来有点像节点,它可以只是根节点的父节点,并且就根节点而言(根节点)是正常的子节点。类似(警告:未经测试,并假设上面的remove()函数实际上是节点类上的方法)

class Tree:

    def __init__(self):
        self.leftNode = None
        # need a rightNode to look like a node, but otherwise unused.
        self.rightNode = None

    # This will probably be useful.
    @property
    def isEmpty(self):
        return self.leftNode is None

    def addNode(self, node):
        if self.leftNode is not None:
            self.leftNode = node
            return
        self.leftNode.add(node, parent=self)

    def removeNode(self, node):
        # the node will remove itself from us, the parent, if needed
        self.leftNode.remove(node, parent=self)

然后客户端执行以下操作:

tree = Tree()
tree.isEmpty
tree.addNode(node)
tree.removeNode(node)

答案 1 :(得分:3)

在查看Python之前,请考虑以下C / C ++代码:

struct A {
   virtual void suicide() {
      delete this;
   }
};

int main() {
   A* a = new A();
   a->suicide();
   return 0;
}

首先,显式创建类型为A的对象。这归结为分配和初始化一小块内存(对象中存储的唯一内容是指向suicide函数的指针)并将变量a设置为指向该内存。 / p>

接下来,调用suicide函数,该函数在内部要求运行时通过调用delete this来释放对象的内存。这是一个完全有效的操作,尽管在现实代码中它是not something you would normally do。也就是说,在调用a->suicide()之后,指针a变为无效,因为它继续指向的内存不再存在。例如,如果您之后尝试再次调用a->suicide(),则会出现分段错误(因为要调用a->suicide,您需要在内存中查找指向方法suicide的指针由a指向,并且此内存不再有效。

但有意义或无意义,你真的可以从任何地方销毁一个C / C ++对象(即释放它的内存),包括对象自己的方法(假设它是在堆上创建的,疗程)。

现在让我们回到Python。在Python中,情况有所不同。虽然您在Python中显式创建对象,就像在C / C ++中一样,但无法强行释放内存。所有内存都由垃圾收集器管理,垃圾收集器跟踪当前引用的对象,哪些不是,并清除无法访问的对象at the moments it decides appropriate

尽管Python语句del self在语法上可能与C / C ++中的delete this类似,但它确实是something completely different是内存管理器清理内存的命令。相反,它只是从“局部变量”字典中删除键self。相应的值(即内存self正在引用)仍然在堆上的某处暂停。

当然,如果没有其他人指向那个内存,很可能垃圾收集器很快会释放它(虽然这不能保证,因为它确实取决于所使用的GC算法),但正如你做的那样{{1某人 仍指着内存,因为有人刚刚调用了该方法。

考虑将上面的C / C ++代码“直译”到Python中:

del self

它也是完全有效的Python代码,但是class A(object): def suicide(self): del self a = A() a.suicide() 这里什么都不做(除了禁止你稍后在同一方法中引用del self,因为你从范围中删除了变量)。 只要存在从某处指向创建的对象的变量self,就不会释放其内存。正如内存不会在这里发布一样,例如:

a

为了更好地理解,我建议你也将Python中的a = A() b = a del a 与C / C ++中del d[key]的含义进行比较。