【问题标题】:Array binary tree数组二叉树
【发布时间】:2021-03-02 12:26:08
【问题描述】:

我需要在三个定义中实现一个函数,并且我最初创建了一个固定长度为 512 的空二叉树构造函数来保存三个定义中的元素。

这是我的空二叉树构造函数:

def __init__(self):
    self._maxArraySize = 512
    self._array = [None]*self._maxArraySize
    self._size = 0

困难的部分是我需要实现一个函数,该函数将元素 e 放在一棵空树的根部,并返回根在 _add_root 中的位置

在 _add_left 函数中,它应该将元素 e 放在 p 的左孩子中并返回孩子的位置

最后,_add_right 函数应该将元素 e 放在 p 的右孩子中,并返回孩子的位置。

我完成但不起作用的代码如下所示,除了非公开的修改器之外,所有内容都给出了。

from binary_tree import BinaryTree

class ArrayBinaryTree(BinaryTree):
  """List representation of a binary tree structure."""

  #-------------------------- nested Position class --------------------------
  class Position(BinaryTree.Position):
    """An abstraction representing the location of a single element."""

    def __init__(self, container, arrayIndex):
      """Constructor should not be invoked by user."""
      self._container = container
      self._arrayIndex = arrayIndex

    def element(self):
      """Return the element stored at this Position."""
      if self._arrayIndex > self._container._maxArraySize:
          raise ValueError('invalid position')
      return self._container._array[self._arrayIndex]

    def __eq__(self, other):
      """Return True if other is a Position representing the same location."""
      return type(other) is type(self) and other._container is self._container and \
    other._arrayIndex == self._arrayIndex

  #------------------------------- utility methods -------------------------------
  def _validate(self, p):
    """Return associated array index, if position is valid."""
    if not isinstance(p, self.Position):
      raise TypeError('p must be proper Position type')
    if p._container is not self:
      raise ValueError('p does not belong to this container')
    return p._arrayIndex

  def _make_position(self, arrayIndex):
    """Return Position instance for given array index."""
    if  arrayIndex >= self._maxArraySize:
      return None
    if self._array[arrayIndex] is None:
      return None
    return self.Position(self, arrayIndex)

  def __init__(self):
    """Create an initially empty binary tree."""
    self._maxArraySize = 512
    self._array = [None]*self._maxArraySize
    self._size = 0


  #-------------------------- public accessors --------------------------
  def __len__(self):
    """Return the total number of elements in the tree."""
    # TODO: Implement the len() operator that returns the total number of elements
    # in the tree.
    return self._size
  
  def root(self):
    """Return the root Position of the tree (or None if tree is empty)."""
    # TODO: Implement the root function from the Tree base class.
    # Return the root Position of the tree. Use _make_position to create
    # the Position instance.
    return self._make_position(self._array)

  def parent(self, p):
    """Return the Position of p's parent (or None if p is root)."""
    # TODO: Implement the parent function from the Tree base class.
    # Return the Position of p's parent. Use _validate to get the 
    # index of p and _make_position to create the parent Position instance.
    arrayIndex = self._validate(p)
    return self._make_position(arrayIndex._parent)
  
  def left(self, p):
    """Return the Position of p's left child (or None if no left child)."""
    # TODO: Implement the left function from the BinaryTree base class.
    # Return the Position of p's left child. Use _validate to get the 
    # index of p and _make_position to create the left child Position instance.
    arrayIndex = self._validate(p)
    return self._make_position(arrayIndex._left)

  def right(self, p):
    """Return the Position of p's right child (or None if no right child)."""
    # TODO: Implement the right function from the BinaryTree base class.
    # Return the Position of p's right child. Use _validate to get the 
    # index of p and _make_position to create the right child Position instance.
    arrayIndex = self._validate(p)
    return self._make_position(arrayIndex._right)

  def num_children(self, p):
    """Return the number of children of Position p."""
    # TODO: Implement the num_children function from the Tree base class.
    # Return the number of children of p. Use _validate to get the index or
    # use left and right.
    arrayIndex = self._validate(p)
    count = 0
    if arrayIndex._left is not None:
      count += 1
    if arrayIndex._right is not None:
      count += 1
    return count

  #-------------------------- nonpublic mutators --------------------------
  def _add_root(self, e):
    """Place element e at the root of an empty tree and return new Position.

    Raise ValueError if tree nonempty.
    """
    # TODO: Implement a function that places the element e at the root 
    # of an empty tree and returns the Position of the root. Use 
    # _make_position to create the Position instance.
    if self._array is not None:
      raise ValueError('Root exists')
    self._size = 1
    self._array = self._array(e)
    return self._make_position(self._array)

  def _add_left(self, p, e):
    """Create a new left child for Position p, storing element e.

    Return the Position of new element.
    Raise ValueError if Position p is invalid or p already has a left child.
    """
    # TODO: implement a function that places the element e in the left child of
    # p and returns the Position of the child. Use _validate to get the 
    # index of p and _make_position to create the left child Position instance.
    arrayIndex = self._validate(p)
    if arrayIndex._left is not None:
      raise ValueError('Left child exists')
    self._size += 1
    arrayIndex._left = self._array(e, 2*p + 1)
    return self._make_position(arrayIndex._left)

  def _add_right(self, p, e):
    """Create a new right child for Position p, storing element e.

    Return the Position of new element.
    Raise ValueError if Position p is invalid or p already has a right child.
    """
    # TODO: implement a function that places the element e in the right child of
    # p and returns the Position of the child. Use _validate to get the 
    # index of p and _make_position to create the right child Position instance.
    arrayIndex = self._validate(p)
    if arrayIndex._right is not None:
      raise ValueError('Left child exists')
    self._size += 1
    arrayIndex._right = self._array(e, 2*p + 2)
    return self._make_position(arrayIndex._right)

谢谢//

【问题讨论】:

  • 为什么方法名以下划线开头?习惯是,前导下划线表示该方法应该被视为私有方法,但您肯定希望允许您的实现用户添加节点...
  • _validate_make_position 的代码是什么?是否有您需要使用的样板代码?
  • 基于数组的树不需要节点类。如果父索引为p,则左子索引为(2*p)+1,右子索引为(2*p)+2
  • 嗯,这不是很有效...你应该回复 cmets。继续...
  • @trincot 对不起,伙计,是的,_validate 和 _make_position 都有代码。如果位置有效,_validate 返回关联的数组索引。 _make_position 返回给定数组索引的位置实例。我可以将两个样板代码都放在问题中。

标签: python tree binary-tree root


【解决方案1】:

您所描述的内容看起来像 binary heap(树)。使用从零开始的索引,您可以使用leftIndex = 2*p+1rightIndex = 2*p+2 计算任意位置p 的左孩子和右孩子的索引。

为了实现,我建议一些辅助方法,在给定位置分配一个值并根据需要扩展数组,在给定位置获取值并获取左右子位置:

def setValue(self,p,value):
     while p>=len(self._array): self._array.append(None)
     self._size    += (self._array[p] is None)-(value is None)
     self._array[p] = value

def getValue(self,p):
     if p>=len(self._array): return None
     return self._array[p]

def getLeftPos(self,p):  return p*2+1
def getRightPos(self,p): return p*2+2

您可以使用这些方法来实现其他功能:

def setRoot(self,value): self.setValue(0,value)

def setLeft(self,p,value):
    if self.getValue(p) is None: 
        raise ValueError('Parent does not exist')
    self.setValue(self.getLeftPos(p),value)

def setRight(self,p,value):
    if self.getValue(p) is None: 
        raise ValueError('Parent does not exist')
    self.setValue(self.getRightPos(p),value)

由此您可以添加更多验证,例如防止重新分配或确保树保持平衡等。

另一种比二叉堆更节省内存的方法是将元组存储在数组中,其中包含左右子节点的值和位置。

实现看起来会有些不同,但相同的辅助方法会使代码保持简单:

def __init__(self):
    self._maxArraySize = 512
    self._array = [(None,None,None)]*self._maxArraySize
    self._size = 0

def setValue(self,p,value): 
    _,left,right = self._array[p]
    self._size   = max(self._size,p+1)
    return self._array[p] = (value,left,right)

def getValue(self,p):    return self._array[p][0]

def getLeftPos(self,p):  return self._array[p][1]

def getRightPos(self,p): return self._array[p][2]

然后元素添加方法将是:

def setRoot(self,value):
    self.setValue(0,value)
    return 0

def setLeft(self,p,value):
    left = self.getLeftPos(p) or self._size
    self.setValue(left,value)
    self._array[p] = (self.getValue(p),left,self.getRightPos(p))
    return left

def setRight(self,p,value):
    right = self.getRightPos(p) or self._size
    self.setValue(right,value)
    self._array[p] = (self.getValue(p),self.getLeftPos(p),right)
    return right

您也可以为这些添加更多验证(最大大小、现有父级等)

【讨论】:

  • 哦,有趣,我应该如何在代码中实现它,正如你所见,我在 python 中有点新。
  • 我没有看到 OP 问题中表明它是二进制堆的条件。二叉堆必须是一棵完整的树......这里似乎不能保证。尽管如此,如果我们对非常不平衡的树的潜在占用空间很大,则可以使用数据结构。
  • 根据输入和输出的位置,这确实是我的一些推断。可能还有其他数据结构可以支持/管理“位置”的更优化使用,但二叉堆是一种众所周知的基于位置的二叉树存储模型。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2023-03-28
  • 1970-01-01
  • 2015-05-27
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多