二叉树的迭代器手写实现

简介: 二叉树的迭代器手写实现

公众号merlinsea


  • 迭代器
  • 对于底层存储结构不是顺序存储的数据集合而言,遍历这样的数据结构最好使用迭代器遍历。
  • 迭代器中就好比有一个指针,这个指针是会随着我们的遍历跟着我们动态移动的,因此java中针对LinkedList,HashMap这种数据结构推荐使用迭代器进行遍历。
  • 二叉树迭代器
  • 二叉树的迭代器遍历这颗二叉树是有一定顺序的,一旦我们创建了这个迭代器,那么就只能按照这个顺序进行遍历。比如我们创建了一个先序遍历迭代器,那就只能按照先序遍历的规则来进行迭代。
  • 迭代器的设计要饱含初始化功能,正向遍历、反向遍历,判断是否有下一个元素的操作。
  • 当迭代器中涉及两个相反方向遍历的时候,最好是使用栈这种数据结构来保存之前的遍历信息【相当于存储快照】,需要注意的是,我们所有这些信息都会随着我们的遍历操作进行动态更新

  • 先序遍历的迭代器代码实现


public class PreOrderIterator {
    private Stack<BTNode> stack;
    // 存的是上一次输出节点快照
    private Stack<BTNode> lastOutputNodeStack;
    public PreOrderIterator(BTNode root){
        stack = new Stack<>();
        lastOutputNodeStack = new Stack<>();
        if(root != null){
            stack.push(root);
            lastOutputNodeStack.push(null);
        }
    }
    public boolean hasNext(){
        // stack 为空  ---> true --> 没有next ---》 false
        return !stack.isEmpty();
    }
    public BTNode next(){
        BTNode top = stack.pop();
        if(top.right!=null){
            stack.push(top.right);
        }
        if(top.left!=null){
            stack.push(top.left);
        }
        lastOutputNodeStack.push(top);
        return top;
    }
    public boolean hasPre(){
        BTNode pre = lastOutputNodeStack.peek();
        return pre != null;
    }
    public BTNode pre(){
        // 删除之前入栈的节点
        BTNode lastOutputNode = lastOutputNodeStack.peek();
        if(lastOutputNode.left!=null){
            stack.pop();
        }
        if(lastOutputNode.right!=null){
            stack.pop();
        }
        stack.push(lastOutputNode);
        // 更新一下lastOutputNodeStack;
        return lastOutputNodeStack.pop();
    }
}


  • 中序遍历迭代器代码实现


public class InOrderIterator {
    private Stack<BTNode> stack;
    private Stack<BTNode> lastOutputNodeStack;
    public InOrderIterator(BTNode root){
        stack = new Stack<>();
        lastOutputNodeStack = new Stack<>();
        BTNode p = root;
        while(p!=null){
            stack.push(p);
            p = p.left;
        }
        lastOutputNodeStack.push(null);
    }
    public boolean hasNext(){
        return !stack.isEmpty();
    }
    public BTNode next(){
       BTNode p = stack.pop();
       BTNode node = p.right;
       // 为了方便下一次直接输出
       while(node != null){
           stack.push(node);
           node = node.left;
       }
       lastOutputNodeStack.push(p);
       return p;
    }
    public boolean hasPre(){
        BTNode pre = lastOutputNodeStack.peek();
        return pre != null;
    }
    public BTNode pre(){
        // 获取之前的输出节点
        BTNode pre = lastOutputNodeStack.pop();
        // 将stack恢复原状
        BTNode p = pre.right;
        while(p!=null){
            stack.pop();
            p = p.left;
        }
        stack.push(p);
        return pre;
    }
}


  • 后序遍历迭代器代码实现


public class PostOrderIterator { // 线性复杂度
    private Stack<BTNode> stack;
    private Stack<BTNode> lastOutputNodeStack;
    public PostOrderIterator(BTNode root){
        stack = new Stack<>();
        lastOutputNodeStack = new Stack<>();
        BTNode p = root;
        while(p!=null){
            stack.push(p);
            p = p.left;
        }
        lastOutputNodeStack.push(null);
    }
    public boolean hasNext(){
        //stack.isEmpty()---> true ---> 空 ---》 没有下一个节点---》 fasle
        return !stack.isEmpty();
    }
    public BTNode next(){
        BTNode p = stack.peek();
        if(p.right == null || p.right == lastOutputNodeStack.peek()){
            stack.pop();
            lastOutputNodeStack.push(p);
            return p;
        }
        // 先处理p的右子树 ---》 递归 ---》 尾递归 ---》 迭代
        while(p.right!=null){
            p = p.right;
            while(p!=null){
                stack.push(p);
                p = p.left;
            }
            p = stack.peek();
        }
        p = stack.pop();
        lastOutputNodeStack.push(p);
        return p;
    }
    public boolean hasPre(){
        BTNode pre = lastOutputNodeStack.peek();
        return pre != null;
    }
    public BTNode pre(){
        BTNode lastOutputNode = lastOutputNodeStack.pop();
        // 把stack恢复到原状
        if(lastOutputNode.right == null || lastOutputNode.right == lastOutputNodeStack.peek()){
            stack.push(lastOutputNode);
            return lastOutputNode;
        }
        BTNode p = lastOutputNode;
        BTNode lastNode = null;
        while(p.right!=null){
            p = p.right;
            while(p!=null){
                lastNode = stack.pop();
                p = p.left;
            }
            p = stack.peek();
        }
        // 用于处理最后next函数中最后执行pop()的操作
        stack.push(lastNode);
        return lastOutputNode;
    }
}


  • Main函数的调用


public class Main {
    public static void main(String[] args) {
        BTNode root = create();
//        InOrderIterator inOrderIterator = new InOrderIterator(root);
//        while(inOrderIterator.hasNext()){
//            System.out.println(inOrderIterator.next());
//        }
//        System.out.println();
//        while(inOrderIterator.hasPre()){
//            System.out.println(inOrderIterator.pre());
//        }
//        PreOrderIterator preOrderIterator = new PreOrderIterator(root);
//         while(preOrderIterator.hasNext()){
//             System.out.println(preOrderIterator.next());
//         }
//        System.out.println();
//         while(preOrderIterator.hasPre()){
//             System.out.println(preOrderIterator.pre());
//         }
//
        PostOrderIterator iterator = new PostOrderIterator(root);
        while(iterator.hasNext()){
            System.out.println(iterator.next());
        }
        System.out.println();
        while(iterator.hasPre()){
            System.out.println(iterator.pre());
        }
    }
    public static BTNode create(){
        BTNode a = new BTNode(0,"A");
        BTNode b = new BTNode(1,"B");
        BTNode c = new BTNode(2,"C");
        BTNode d = new BTNode(3,"D");
        BTNode e = new BTNode(4,"E");
        BTNode f = new BTNode(5,"F");
        BTNode m = new BTNode(6,"M");
        BTNode n = new BTNode(7,"N");
        a.left = b;
        a.right = c;
        b.left = d;
        c.left = e;
        c.right = f;
//        d.right = m;
//        m.left = n;
        return a;
    }
}

640.png


相关文章
|
缓存 Ubuntu Java
Tool之Bazel:Bazel的简介、安装、使用方法之详细攻略
Tool之Bazel:Bazel的简介、安装、使用方法之详细攻略
|
机器学习/深度学习 存储 人工智能
基于内容的图像检索系统设计与实现(1)
基于内容的图像检索系统设计与实现(1)
基于内容的图像检索系统设计与实现(1)
|
开发框架 前端开发 Linux
开源项目推荐:C++ Web/Http Server/Rest开发框架(请重点关注Oat++和搜狗workflow)
开源项目推荐:C++ Web/Http Server/Rest开发框架(请重点关注Oat++和搜狗workflow)
4985 0
|
3月前
|
机器学习/深度学习 缓存 算法
2025年华为杯A题|通用神经网络处理器下的核内调度问题研究生数学建模|思路、代码、论文|持续更新中....
2025年华为杯A题|通用神经网络处理器下的核内调度问题研究生数学建模|思路、代码、论文|持续更新中....
439 1
|
自然语言处理 算法 Python
再谈递归下降解析器:构建一个简单的算术表达式解析器
本文介绍了递归下降解析器的原理与实现,重点讲解了如何使用Python构建一个简单的算术表达式解析器。通过定义文法、实现词法分析器和解析器类,最终实现了对基本算术表达式的解析与计算功能。
352 52
|
存储 人工智能 搜索推荐
Memoripy:支持 AI 应用上下文感知的记忆管理 Python 库
Memoripy 是一个 Python 库,用于管理 AI 应用中的上下文感知记忆,支持短期和长期存储,兼容 OpenAI 和 Ollama API。
865 6
Memoripy:支持 AI 应用上下文感知的记忆管理 Python 库
|
机器学习/深度学习 数据可视化 JavaScript
探索机器学习模型的可视化技术
【9月更文挑战第23天】在数据科学中,理解和解释机器学习模型的决策过程是至关重要的。本文将介绍几种流行的可视化工具和库,如TensorBoard、D3.js等,帮助读者更好地理解模型内部工作原理及其预测结果。通过实例演示如何使用这些工具进行模型可视化,增强模型的可解释性。
|
运维 监控 测试技术
5个常见运维场景,用这几个Python脚本就够了!
5个常见运维场景,用这几个Python脚本就够了!
447 0
|
JavaScript Dubbo Java
这份日志格式规范,拿走不谢(Java版)
这份日志格式规范,拿走不谢(Java版)
|
存储 Prometheus 监控
Flask监控与日志记录:掌握应用运行状况
【4月更文挑战第16天】本文介绍了在Flask应用中实现监控和日志记录的方法,以确保应用稳定性和问题排查。推荐使用Prometheus、Grafana、New Relic或Flask-MonitoringDashboard等工具进行监控,并通过Python的logging模块记录日志。监控集成涉及安装配置工具、添加监控代码,而日志管理则需要集中存储和使用分析工具。安全是关键,要防止未授权访问和数据泄露,避免记录敏感信息。监控和日志记录有助于提升应用性能和用户体验。