Javascript 对迭代器进行编码以遍历二叉树

Javascript 对迭代器进行编码以遍历二叉树,javascript,python,closures,binary-tree,binary-search-tree,Javascript,Python,Closures,Binary Tree,Binary Search Tree,问题是,给定一个BST,找出是否有两个数字加起来等于给定的数字k。不应使用额外的内存 现在,如果它是一个排序数组,我可以简单地保留两个指针,一个在开头,一个在结尾。在每一步中,我将计算指针指向的两个数字的和,如果和小于k,我将增加起始指针,否则减少结束指针,直到出现匹配,或者指针重叠 我可以对BST做同样的事情,通过按序遍历将其转换为排序数组,但这需要额外的内存。所以我认为迭代器解决方案是合适的。我将保留两个迭代器,一个将以正常的顺序遍历BST,调用它将返回下一个较大的数字,另一个将以相反的顺序

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

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

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

你知道如何设计这样的迭代器吗?我更喜欢Python/Javascript的解决方案。尽管Python提供了类似于iter的函数,但我想使用闭包来设计它。

这种迭代器(使用闭包)在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
我想到一个简单的主意;-): 如果您不想为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;
            }
        }
    }
}
var inst=new BST();
插入说明(-121);
说明书插页(13);
插入说明(1);
说明书插页(10);
GetAddends(inst,55);//我们开始
函数GetAddends(bst,目标){
var iter1=bst.GetIterator();
var iter2=bst.GetIterator(false);
而(iter1.IsValid()&&iter2.IsValid()&&iter1.Pos()target)iter2.Next();
else window.alert(iter1.data()+“+”+iter2.data()+“=”+target);
}
bst.ClearIterators();
}
函数BST(){
变量根,节点计数,锁定;
this.Insert=函数(数据){
如果(_locked==true)抛出“无法在迭代期间修改BST”;
_nodeCount++;
}
this.Delete=函数(数据){
如果(_locked==true)抛出“无法在迭代期间修改BST”;
_节点计数--;
返回null;
}
this.GetIterator=函数(isForward){return Iter(isForward);}
this.ClearIterators=function(){u locked=false;}
功能Iter(isForward){
如果(isForward==null)isForward=true;//如果省略该参数,则默认为true
_锁定=真;
var _pos=isForward?0:(_nodeCount-1);
var_curData;
返回函数(){
这是有效的(){
返回(isForward?(\u pos<\u nodeCount):(\u pos>=0));
}
this.Next=函数(){
isForward?_pos++:_pos--;
_curData=null;
}
this.Pos=函数(){return\u Pos;}
this.Data=function(){
如果(_curData==null){/*循环BST并查找_posTH节点,并存储在_curData中,以防以后需要它*/}
返回数据;
}
}
}
}

这些代码没有实现BST,但是想法应该很清楚。玩得高兴这里提醒一下,我们不允许在持有迭代器的过程中修改BST。当我们不在持有迭代器的范围内时,我们需要调用ClearIterators()。然而,一个优雅的解决方案是使用PUB/SUB让BST知道有多少迭代器。这可能是另一个问题,哈。

您可以按顺序遍历BST,而无需将其复制到数组中——这只是深度优先搜索。你是在问怎么写吗?我不知道他们是否能帮上忙,但尼古拉斯·扎卡斯在BST的Javascript系列节目中有两部分:@katrielex,不完全是。我正在寻找一个迭代器,它将记住上次访问的节点,因此在后续调用中,它将返回下一个节点。@Cupidvogel,yield正是为这类任务设计的。嗯,这有点简洁,但我正在寻找一个不使用
itertools
yield
之类的解决方案。这是可行的吗?@Cupidvogel,您要求使用闭包的解决方案,但这就是收益率所代表的。这是在python中执行此类操作的正确方法。
在不使用itertools或生成此类内容的情况下寻找解决方案是愚蠢的。这就是用Python编写迭代器的方法。顺便说一句,递归解决方案虽然更加优雅,但并不一定是最好的,因为Python不擅长递归。具体来说,这不再是常量空间,因为每个递归调用都会生成一个堆栈帧。您可以通过迭代遍历来编写一个常量空间版本:转到左子级,除非它不存在,然后转到右子级,然后再转到上;如果您来自正确的子级,则再次向上。还要注意,手动迭代
在这种情况下是正确的,但通常使用
for
循环在迭代器上进行迭代。