简体   繁体   English

迭代逆序遍历

[英]iterative reverse preorder traversal

I'd like to find the item that layout places directly above an element. 我想找到放置在元素正上方的项目。 In the DOM structure of the page, this means that something could be nested a few levels deep, or it could also mean stepping up a few levels in the hierarchy. 在页面的DOM结构中,这意味着某些内容可能嵌套在几个级别的深处,或者也可能意味着在层次结构中增加几个级别。 For example 例如

div.a        
  div.b      
    div.c      
    div.d    
      div.e  
        div.f
    div.g    
  div.h      
  div.i      
div.j        
div.k        

Where .b, .h, .i are immediate children of .a , and so on. 其中.b, .h, .i.a直接子代,依此类推。

For example when I call getBefore($('.h')); 例如,当我调用getBefore($('.h')); I expect to fetch .g . 我希望获取.g This would ostensibly involve a preorder reverse search that hits div.b first. 从表面div.b ,这将涉及预搜索反向搜索,该搜索首先div.b

The problem that I'm having is that without performing a global recursive scan, it's difficult to deal with the case of getBefore($('.c')); 我遇到的问题是,如果不执行全局递归扫描,则很难处理getBefore($('.c')); where I am expecting to get .b because it is the item that lies before it in the layout. 我希望得到.b因为它是布局中位于它之前的项目。 The routine, not having a global traversal recursion stack to know any better, would look at .b (unaware that .d was a middle child and that it should not recurse down) and fetch the bottom-most item in its hierarchy which turns out to be .g , taking us in the wrong direction. 该例程没有全局遍历递归堆栈,无法了解任何信息,将查看.b (不知道.d是中间子对象,并且不应向下递归),然后获取其层次结构中最底层的项目是.g ,把我们带向错误的方向。

So based on this observation it seems to me like a recursive implementation can't be done cleanly, as the input to the routine is not the root node but some node inside of some tree whose structure is not known. 因此,基于这种观察,在我看来,似乎无法彻底地执行递归实现,因为例程的输入不是根节点,而是结构未知的树中的某些节点。 What, then, is a reasonable way to implement this iteratively? 那么,什么是合理的迭代实现方式呢? The DOM gives me pointers to move up to the parent node, and i also have pointers to the previous node, if any, and I can also fetch the list of children of any given mode, if any. DOM给了我向上移动到父节点的指针,并且我也有指向上一个节点的指针(如果有的话),并且我还可以获取任何给定模式的孩子的列表(如果有的话)。

This is how I got it to work. 这就是我如何使其工作。 It uses a combination of a regular recursive preorder traversal routine which is called by an iterative routine that is aware of which direction to go. 它使用常规递归预遍历例程的组合,该例程由知道要往哪个方向的迭代例程调用。

The iterative routine takes a node, and walks up the sibling list by calling node = node.previousSibling . 迭代例程获取一个节点,并通过调用node = node.previousSibling同级列表。 When it reaches the top it goes to the parent: node = node.parentNode . 当到达顶部时,转到父node = node.parentNodenode = node.parentNode At every step it will call a method that uses standard recursive preorder search which fetches the last suitable item in the tree rooted by the node. 在每个步骤中,它将调用一个使用标准递归预排序搜索的方法,该方法将提取该节点所扎根的树中的最后一个合适的项。 This way .g leads to .f because $('.g')[0].previousSibling is .d and .d 's last item is .f . 这种方式.g导致.f因为$('.g')[0].previousSibling.d.d的最后一项是.f

Strangely enough, moving forward, the getAfter() routine which does the same, but goes in the forward direction, does not require recursion. 奇怪的是,向前移动,执行相同的但在向前方向执行的getAfter()例程不需要递归。 Doing it recursively does make for slightly more elegant code though. 递归地做确实会使代码更优雅。

Key idea of preorder traversal using stack is to push right child and then left child so that left child will be processed before right child. 使用堆栈进行遍历的关键思想是先推右孩子,然后推左孩子,以便在左孩子之前处理左孩子。

class Node {
    int key;
    Node left, right;

    public Node() {}

    public Node(int key) {
        this.key = key;
    }
}

public List<Integer> preOrderIterative() {
    List<Integer> list = new ArrayList<>();
    Stack<Node> nodeStack = new Stack<>();

    nodeStack.push(root);

    while (!nodeStack.empty()) {
         Node node = nodeStack.pop();
         list.add(node.key);

         if (null != node.right) nodeStack.push(node.right);
         if (null != node.left) nodeStack.push(node.left);
    }
    return list;
}

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM