通过具有过早停止条件的块遍历树

Tree Traversal via Blocks with a premature stopping condition

我正在对二叉树进行中序遍历,并在每个节点上执行特定的方法。我使用如下所示的 inOrderTraversalWithOperation: 方法执行此操作,该方法使用块来定义每个节点所需的功能。

-(void) inOrderTraversalWithOperation:(void (^) (BinaryTreeNode *))operation
{
    [self.leftChild inOrderTraversalWithOperation:operation];
    if (operation)
    {
        operation(self);
    }
    [self.rightChild inOrderTraversalWithOperation:operation];

}

假设我想在 Block 执行遇到特定条件时停止。一种方法是将 inOrderTraversalWithOperation: return 设为 BOOL,并将块 return 设为 BOOL,如下所示。

但我想知道我是否可以使用 Apple 在其许多 API 中使用的 BOOL *stop 方法来做到这一点。带有该标志的块如何工作 "underneath"?

-(BOOL) inOrderTraversalWithStopOperation:(BOOL (^) (BinaryTreeNode *))operation
{
    BOOL shouldStop = NO;

    shouldStop = [self.leftChild inOrderTraversalWithStopOperation:operation];
    if (operation !=nil && shouldStop == NO)
    {
        shouldStop = operation(self);
    }

    if (!shouldStop)
    {
        shouldStop = [self.rightChild inOrderTraversalWithStopOperation:operation];
    }

    return shouldStop;
}

编辑 根据 Josh 的评论,看起来 BOOL *stop 会允许这样做,但我仍然需要 inOrderTraversalWithStopOperation: 到 return 一个 BOOL

-(BOOL) inOrderTraversalWithStopOperation:(void (^) (BinaryTreeNode *, BOOL *))operation
{
    BOOL shouldStop = NO;

    shouldStop = [self.leftChild inOrderTraversalWithStopOperation:operation];
    if (operation !=nil && shouldStop == NO)
    {
        operation(self, &shouldStop);
    }

    if (!shouldStop)
    {
        shouldStop = [self.rightChild inOrderTraversalWithStopOperation:operation];
    }

    return shouldStop;
}

枚举块的 "stop" 参数就像任何其他间接 return 值一样:您从一个范围传递一个 地址 以便下一个范围可以把东西放在那里。然后在原始范围内可以使用某些东西。

要向您的操作类型添加停止标志,您需要更改其签名

typedef void (^NodeOperation)(BinaryTreeNode *, BOOL *);

在 Block 的调用上下文中,您将执行您已经完成的操作:为此标志创建一个 BOOL 并将其设置为 NO。然后你将它的地址传递给块:operation(self, &stop);.

在操作中,如有必要,您可以通过取消引用并分配一个值来设置标志:*stop = YES;(最好先检查它是否不是 NULL;取消引用 NULL 是非法的)。

回到控制范围,做你已经在做的事情:在每次操作后检查标志并决定做什么。

我对 What is the BOOL *stop argument for enumerateObjectsUsingBlock: used for?

的相关回答中有此机制的代码示例

要控制递归方法调用,您必须以某种方式将信息传回。您可以使用直接 return 值最轻松地做到这一点。另一种选择(虽然我认为在这种情况下它不会给你带来任何好处)是向方法添加一个 BOOL 指针参数;然后你可以继续将相同的引用传递给每个级别。 (这可能意味着创建一个辅助方法,以便原始调用者不必担心该参数。)