编写迭代器来遍历二叉树

时间:2012-12-14 13:05:13

标签: javascript python closures binary-tree binary-search-tree

问题是,给定BST,找出是否有两个数字加起来给定的数字k。不应使用额外的内存。

现在如果它是一个排序数组,我可以简单地保留两个指针,一个在开头,一个在结尾。在每一步,我将计算指针指向的两个数字的总和,如果总和小于k,我会增加起始指针,否则减少结束指针,直到匹配,或指针重叠。 / p>

我可以用BST做同样的事情,通过inorder遍历将它转换为有序数组,但这需要额外的内存。所以我认为迭代器解决方案是有序的。我会保留两个迭代器,一个将以正常的顺序遍历BST,调用哪个将返回下一个更大的数字,另一个将以反向顺序遍历BST,每次调用时返回下一个较小的数字。

知道如何设计这样的迭代器吗?我更喜欢Python / Javascript中的解决方案。虽然Python提供了像iter这样的函数,但我想用闭包来设计它。

2 个答案:

答案 0 :(得分:3)

这种迭代器(使用闭包)在python中称为生成器。

生成器是函数,使用'yield'关键字而不是'return'。遇到yield时,返回相应的值,但函数的执行状态将被暂停,直到需要下一个值。

所以,你可以使用'yield'而不是'return'来实现树遍历功能,你的目标就会完成。

它们很容易设计:

# Simple tree definition
class Tree:
    def __init__(self, data, left=None, right=None):
        self.data = data
        self.left = left
        self.right = right

# In-order lazy iterator (aka generator)
def inorder(tree):
    if tree is not None:
        for x in inorder(tree.left):
            yield x
        yield tree.data
        for x in inorder(tree.right):
            yield x

# Reverse in-order lazy iterator
def rev_inorder(tree):
    if tree is not None:
        for x in rev_inorder(tree.right):
            yield x
        yield tree.data
        for x in rev_inorder(tree.left):
            yield x

# Construct a tree
n1 = Tree(1)              
n2 = Tree(2)              
n3 = Tree(3)              #         7
n4 = Tree(4)              #       /   \
n5 = Tree(5, n1, n2)      #     5       6
n6 = Tree(6, n3, n4)      #    / \     / \
n7 = Tree(7, n5, n6)      #   1   2   3   4

for i in inorder(n7):
    print i, 
print

for i in rev_inorder(n7):
    print i, 
print

输出:

1 5 2 7 3 6 4
4 6 3 7 2 5 1

要手动迭代,请使用:

gen = rev_inorder(n7)
print gen.next()       # Output 4
print gen.next()       # Output 6

答案 1 :(得分:0)

我提出了一个简单的想法;-): 如果您不想为BST周围的迭代分配额外空间,则需要牺牲性能。

var inst = new BST();
inst.Insert(-121);
inst.Insert(13);
inst.Insert(1);
inst.Insert(10);
GetAddends(inst, 55); // here we go
function GetAddends(bst, target) {
    var iter1 = bst.GetIterator();
    var iter2 = bst.GetIterator(false);

    while (iter1.IsValid() && iter2.IsValid() && (iter1.Pos() < iter2.Pos())) {
        var temp = iter1.data() + iter2.data();
        if (temp < target) iter1.Next();
        else if (temp > target) iter2.Next();
        else window.alert(iter1.data() + "+" + iter2.data() + "=" + target);
    }
    bst.ClearIterators();
}

function BST() {
    var _root, _nodeCount, _locked;
    this.Insert = function(data) { 
        if (_locked === true) throw "could not modify the BST during iteration";
        _nodeCount++;
    }
    this.Delete = function(data) {
        if (_locked === true) throw "could not modify the BST during iteration";
        _nodeCount--;
        return null;
    }
    this.GetIterator = function(isForward) { return Iter(isForward); }
    this.ClearIterators = function() { _locked = false; }

    function Iter(isForward) {
        if (isForward == null) isForward = true; // if the parameter is omitted, then true by default
        _locked = true;
        var _pos = isForward ? 0 : (_nodeCount - 1);
        var _curData;
        return function() {
            this.IsValid() {
                return (isForward ? (_pos < _nodeCount) : (_pos >= 0));
            }
            this.Next = function() {
                isForward ? _pos++ : _pos--;
                _curData = null;
            }
            this.Pos = function() { return _pos; }
            this.Data = function() {
                if (_curData == null) { /* loop the BST and find _posTH node and stored in the _curData in case we need it later */ }
                return _curData;
            }
        }
    }
}

这些代码没有实现BST,但这个想法应该是明确的。玩得开心!提醒一下,我们不允许在持有迭代器的过程中修改BST。在我们不在持有迭代器的范围内之后,我们需要调用ClearIterators()。但是,一个优雅的解决方案可能是使用PUB / SUB让BST知道存在多少迭代器。也许这可能是另一个问题,哈哈。