函数式编程-高阶函数-二叉树

定义

  • 所谓高阶,就是他是其他函数的使用者
  • 柯里化就是 闭包 + 高阶函数的结合使用

在这里插入图片描述

内循环

需求

在这里插入图片描述

内循环-代码示例

对于调用者,不需要知道具体的遍历逻辑,只需要提供具体的处理逻辑就可以了

public static void main(String[] args) {

    List<Integer> list = Arrays.asList(1, 2, 3, 4, 5, 6, 7, 8, 9);
    //需求: 逆序遍历集合,只项负责元素处理,不能改变集合
    hiOrder(list, System.out::println);
}


// 高阶函数的第二个参数是一个函数  暴露给调用者,让调用者自己去实现具体的业务逻辑
public static <T> void hiOrder(List<T> list, Consumer<T> consumer) {
    // 逆序遍历
    // 这种比遍历方式是针对ArrayList的,底层是数组结构
    // 面对的如果是链表结构,这种方式就不适用了
    // for (int i = list.size() - 1; i >= 0; i--) {
    //     System.out.println(list.get(i));
    // }

    // 这种方式是面向所有集合的,不管是数组还是链表
    // 迭代器器是可以传递参数的,可以指定从哪个位置开始遍历 从0开始 或者 从size开始
    ListIterator<T> integerListIterator = list.listIterator(list.size());
    while (integerListIterator.hasPrevious()) {
        T previous = integerListIterator.previous();
        consumer.accept(previous);
    }
}

二叉树遍历

需求

在这里插入图片描述

初步代码

  • 定义一个二叉树类
  • 根节点
  • 节点类
  • 遍历方式枚举类
  • 主遍历:根据遍历方式选择遍历方法
  • 前序遍历方法
  • 中序遍历方法
  • 后续遍历方法
public class BinaryTree {


    TreeNode root;

    public record TreeNode(int val, TreeNode left, TreeNode right) {
    }

    // 遍历方式
    public enum Order {
        // 前序遍历
        PREORDER,
        // 中序遍历
        INORDER,
        // 后序遍历
        POSTORDER
    }

    // 前序遍历记录一下完整的路径 另外两种就只记录遍历的路径
    public static void  traversal(Order order, TreeNode node, StringBuilder path, Consumer<TreeNode> consumer) {
    }


    // 前序遍历
    public static void preorderTraversal(TreeNode node, StringBuilder path, Consumer<TreeNode> consumer) {

    }

    // 中序遍历
    public static void inorderTraversal(TreeNode node, StringBuilder path, Consumer<TreeNode> consumer) {

    }

    // 后序遍历
    public static void postorderTraversal(TreeNode node, StringBuilder path, Consumer<TreeNode> consumer) {

    }


    // 主函数
    public static void main(String[] args) {
    }
}

主遍历方法

// 前序遍历记录一下完整的路径 另外两种就只记录遍历的路径
public static void  traversal(Order order, TreeNode node, StringBuilder path, Consumer<TreeNode> consumer) {
    switch (order) {
        case PREORDER -> preorderTraversal(node, path,consumer);
        case INORDER -> inorderTraversal(node, path,consumer);
        case POSTORDER -> postorderTraversal(node, path,consumer);
    }
}

前序遍历方法

// 前序遍历
public static void preorderTraversal(TreeNode node, StringBuilder path, Consumer<TreeNode> consumer) {
   if (node == null) {
       return;
   }
   // 第一次访问到这个节点 保存节点值
   consumer.accept(node);
   // 递归遍历左子树
   if (node.left != null) {
       preorderTraversal(node.left, path,consumer);
       consumer.accept(node); // 左子树遍历完了,记录当前节点 作为返回标记
   }
   // 递归遍历右子树
   if (node.right != null) {
       preorderTraversal(node.right, path,consumer);
       consumer.accept(node); // 右子树遍历完了,记录当前节点 作为返回标记
   }
}

中序遍历方法

// 中序遍历
public static void inorderTraversal(TreeNode node, StringBuilder path, Consumer<TreeNode> consumer) {
    if (node == null) {
        return;
    }
    // 递归遍历左子树
    if (node.left != null) {
        inorderTraversal(node.left, path,consumer);
    }
    // 保存节点值
    consumer.accept(node);
    // 递归遍历右子树
    if (node.right != null) {
        inorderTraversal(node.right, path,consumer);
    }
}

后序遍历方法

// 后序遍历
 public static void postorderTraversal(TreeNode node, StringBuilder path, Consumer<TreeNode> consumer) {
     if (node == null) {
         return;
     }
     // 递归遍历左子树
     if (node.left != null) {
         postorderTraversal(node.left, path,consumer);
     }
     // 递归遍历右子树
     if (node.right != null) {
         postorderTraversal(node.right, path,consumer);
     }
     // 保存节点值
     consumer.accept(node);
 }

主函数

  • 其实将 处理逻辑抽象为 Consumer的时候,使用到了柯里化,因为path 变量明显不是作为参数传递给函数对象的,但是却出现在方法体重重作为逻辑的一部分
    在这里插入图片描述
// 一个树的值 1 2 3 4 5 6
// 前序遍历 1 2 3 4 5 6 值左右
// 中序遍历 4 2 1 5 3 6 左值右
// 后序遍历 4 2 5 6 3 1 左右值
public static void main(String[] args) {
    TreeNode node6 = new TreeNode(6, null, null);
    TreeNode node5 = new TreeNode(5, null, null);
    TreeNode node4 = new TreeNode(4, null, null);
    TreeNode node3 = new TreeNode(3, node5, node6);
    TreeNode node2 = new TreeNode(2, node4, null);
    // 根节点 1
    TreeNode node1 = new TreeNode(1, node2, node3);

    // 定义一个StringBuilder 保存遍历的路径
    StringBuilder path = new StringBuilder();
    // 定义一个Consumer 存储对节点的操作  这个地方无意间就使用了柯里化 path就是外界的一个不可变参数
    Consumer<TreeNode> consumer = node -> path.append(node.val).append("-");
    traversal(Order.PREORDER,node1,path,consumer);
    // 去掉最后一个-
    path.deleteCharAt(path.length() - 1);
    System.out.println(path.toString());
}

相关推荐

  1. Python进:函数编程

    2024-05-14 11:20:09       51 阅读
  2. 搜索(相关函数实现)

    2024-05-14 11:20:09       24 阅读
  3. 【Python】函数

    2024-05-14 11:20:09       37 阅读
  4. 函数编程

    2024-05-14 11:20:09       57 阅读

最近更新

  1. docker php8.1+nginx base 镜像 dockerfile 配置

    2024-05-14 11:20:09       98 阅读
  2. Could not load dynamic library ‘cudart64_100.dll‘

    2024-05-14 11:20:09       106 阅读
  3. 在Django里面运行非项目文件

    2024-05-14 11:20:09       87 阅读
  4. Python语言-面向对象

    2024-05-14 11:20:09       96 阅读

热门阅读

  1. C++算法——函数对象\谓词\内置仿函数

    2024-05-14 11:20:09       35 阅读
  2. chatGPT 凌晨发布会内容总结

    2024-05-14 11:20:09       30 阅读
  3. LINQ(四) ——使用LINQ进行对象类型初始化

    2024-05-14 11:20:09       35 阅读
  4. 分享四种CAD图纸加密方法,严防盗图

    2024-05-14 11:20:09       32 阅读
  5. 矩阵的特征分解

    2024-05-14 11:20:09       30 阅读
  6. 蓝桥杯-移动距离(最简单的写法)

    2024-05-14 11:20:09       30 阅读
  7. 你眼中的IT行业现状与未来趋势

    2024-05-14 11:20:09       27 阅读
  8. 谈谈std::map的lower_bound

    2024-05-14 11:20:09       30 阅读
  9. Linux-vi/vim

    2024-05-14 11:20:09       29 阅读
  10. CentOS常见的命令

    2024-05-14 11:20:09       32 阅读