Javascript 对迭代器进行编码以遍历二叉树
问题是,给定一个BST,找出是否有两个数字加起来等于给定的数字Javascript 对迭代器进行编码以遍历二叉树,javascript,python,closures,binary-tree,binary-search-tree,Javascript,Python,Closures,Binary Tree,Binary Search Tree,问题是,给定一个BST,找出是否有两个数字加起来等于给定的数字k。不应使用额外的内存 现在,如果它是一个排序数组,我可以简单地保留两个指针,一个在开头,一个在结尾。在每一步中,我将计算指针指向的两个数字的和,如果和小于k,我将增加起始指针,否则减少结束指针,直到出现匹配,或者指针重叠 我可以对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
循环在迭代器上进行迭代。