当前位置: 首页 > news >正文

【数据结构】用Java实现一棵二叉树

目录

前言

1. 创建MyBinaryTree类

2. 从前序与中序遍历序列构造二叉树

3. 从中序与后序遍历序列构造二叉树

4. 用层序遍历验证二叉树是否构建成功

5. 整体代码(构建二叉树、二叉树的基本功能和测试代码)

6. 测试结果


前言

前面两篇文章已经给出了如何构建二叉树以及如何实现基本功能,感兴趣的友友可以点下面的链接看一看,在这里给出构建二叉树的简单说明以及构建二叉树和实现基本功能实现的代码。

二叉树的构建

二叉树的基本操作

    // 前序遍历void preOrder(TreeNode root);  // 中序遍历void inOrder(TreeNode root);// 后序遍历void postOrder(TreeNode root);// 获取树中节点的个数:遍历思路public static int nodeSize;void size(TreeNode root);// 获取节点的个数:子问题的思路int size2(TreeNode root);//获取叶子节点的个数:遍历思路public static int leafSize = 0;void getLeafNodeCount1(TreeNode root);// 获取叶子节点的个数:子问题int getLeafNodeCount2(TreeNode root);// 获取第K层节点的个数int getKLevelNodeCount(TreeNode root, int k);// 获取二叉树的高度,时间复杂度:O(N)int getHeight(TreeNode root);// 检测值为value的元素是否存在TreeNode find(TreeNode root, char val);//层序遍历void levelOrder(TreeNode root);// 判断一棵树是不是完全二叉树boolean isCompleteTree(TreeNode root);

1. 创建MyBinaryTree类

val存储二叉树节点的值,left为二叉树的左子树,right为二叉树右子树地址。

下面的所有方法都是在MyBinaryTree类中实现的。

public class MyBinaryTree {static class TreeNode {public int val;TreeNode left;//左孩子的引用TreeNode right;//右孩子的引用public TreeNode(int val) {this.val = val;}}}

2. 从前序与中序遍历序列构造二叉树

从前序遍历中获取根节点,中序遍历中根节点前面的是左子树的部分,中序遍历中根节点后面的是右子树部分。使用index下标来遍历前序数组。

1. 从前序遍历结果中获取到树的根节点

2. 在中序遍历结果中确定根节点的位置,按照该位置将中序遍历结果分为两部分

        左半部分是根节点的左子树,递归创建根节点的左子树

        右半部分是根节点的右子树,递归创建根节点的右子树

public TreeNode buildTree1(int[] preorder, int[] inorder) {return buildTreeHelper1(preorder,inorder,0,inorder.length - 1);}int index = 0;private TreeNode buildTreeHelper1(int[] preorder, int[] inorder, int left, int right) {if(index == inorder.length ){return null;}if (left > right){return null;}int pos = find(inorder,preorder);TreeNode root = new TreeNode(preorder[index]);index ++;root.left = buildTreeHelper1(preorder,inorder,left,pos - 1);root.right = buildTreeHelper1(preorder,inorder,pos + 1,right);return root;}private int find(int[] inorder,int[] preorder) {for (int i = 0; i < inorder.length; i++) {if (inorder[i] == preorder[index]){return i;}}return -1;}

3. 从中序与后序遍历序列构造二叉树

先看看同一颗树的前序遍历结果preorder = [3,9,20,15,7]和后序遍历的结果postorder = [9,15,7,20,3],对比一下这两。

发现将后序遍历的结果反转->[3,20,7,15,9],前序遍历是根左右,后序遍历反转后的是根右左,所以我们只需要将后序遍历的结果反转一下,然后向上一题那样构建二叉树,只不过是先构建右子树再构建左子树。

//    从中序与后序遍历序列构造二叉树, 返回这棵树的根节点public TreeNode buildTree2(int[] postorder, int[] inorder) {reverse(postorder);return buildTreeHelper2(postorder,inorder,0,inorder.length - 1);}private void reverse(int[] postorder){for (int i = 0; i < postorder.length/2; i++) {int temp = postorder[i];postorder[i] = postorder[postorder.length - i - 1];postorder[postorder.length - i - 1] = temp;}}private TreeNode buildTreeHelper2(int[] postorder, int[] inorder, int left, int right) {if(index == inorder.length ){return null;}if (left > right){return null;}int pos = find(inorder,postorder);TreeNode root = new TreeNode(postorder[index]);index ++;root.right = buildTreeHelper2(postorder,inorder,pos + 1,right);root.left = buildTreeHelper2(postorder,inorder,left,pos - 1);return root;}

4. 用层序遍历验证二叉树是否构建成功

1. 如果是空树直接返回

2. 层序遍历需要用到队列,定义一个队列,里面放置节点的地址,将根节点如队列

3. 队列非空时,循环进行一下操作:

        a. 队列中当前元素都是在同一层的,依次取出遍历,保存到同一个curList中

        取到一个节点时候,

                >> 保存该节点

                >> 如果该节点左子树存在,将该左子树入队列

                >> 如果该节点右子树存在,将该节点右子树入队列

                 >> 将当前已遍历节点从队列中拿出来

         b. 本层节点遍历结束后,保存到返回的curList中,此时下一层节点已经全部入队列

public void levelOrder(TreeNode root) {List<List<Integer>> list = new ArrayList<>();if (root == null){System.out.println(list);return;}Deque<TreeNode> queue = new LinkedList<>();queue.offer(root);while (!queue.isEmpty()){int size = queue.size();List<Integer> curList = new ArrayList<>();for (int i = 0; i < size; i++) {TreeNode temp = queue.pop();curList.add(temp.val);if (temp.left != null){queue.offer(temp.left);}if (temp.right != null){queue.offer(temp.right);}}list.add(curList);}System.out.println(list);}

5. 整体代码(构建二叉树、二叉树的基本功能和测试代码)

构建的二叉树:

import java.util.ArrayList;
import java.util.Deque;
import java.util.LinkedList;
import java.util.List;public class MyBinaryTree {static class TreeNode {public int val;TreeNode left;//左孩子的引用TreeNode right;//右孩子的引用public TreeNode(int val) {this.val = val;}}//    从前序与中序遍历序列构造二叉树, 返回这棵树的根节点public TreeNode buildTree1(int[] preorder, int[] inorder) {return buildTreeHelper1(preorder,inorder,0,inorder.length - 1);}int index = 0;private TreeNode buildTreeHelper1(int[] preorder, int[] inorder, int left, int right) {if(index == inorder.length ){return null;}if (left > right){return null;}int pos = find(inorder,preorder);TreeNode root = new TreeNode(preorder[index]);index ++;root.left = buildTreeHelper1(preorder,inorder,left,pos - 1);root.right = buildTreeHelper1(preorder,inorder,pos + 1,right);return root;}private int find(int[] inorder,int[] preorder) {for (int i = 0; i < inorder.length; i++) {if (inorder[i] == preorder[index]){return i;}}return -1;}//    从中序与后序遍历序列构造二叉树, 返回这棵树的根节点public TreeNode buildTree2(int[] postorder, int[] inorder) {reverse(postorder);return buildTreeHelper2(postorder,inorder,0,inorder.length - 1);}private void reverse(int[] postorder){for (int i = 0; i < postorder.length/2; i++) {int temp = postorder[i];postorder[i] = postorder[postorder.length - i - 1];postorder[postorder.length - i - 1] = temp;}}private TreeNode buildTreeHelper2(int[] postorder, int[] inorder, int left, int right) {if(index == inorder.length ){return null;}if (left > right){return null;}int pos = find(inorder,postorder);TreeNode root = new TreeNode(postorder[index]);index ++;root.right = buildTreeHelper2(postorder,inorder,pos + 1,right);root.left = buildTreeHelper2(postorder,inorder,left,pos - 1);return root;}//    层序遍历
//    用数组输出层序遍历结果public void levelOrder(TreeNode root) {List<List<Integer>> list = new ArrayList<>();if (root == null){System.out.println(list);return;}Deque<TreeNode> queue = new LinkedList<>();queue.offer(root);while (!queue.isEmpty()){int size = queue.size();List<Integer> curList = new ArrayList<>();for (int i = 0; i < size; i++) {TreeNode temp = queue.pop();curList.add(temp.val);if (temp.left != null){queue.offer(temp.left);}if (temp.right != null){queue.offer(temp.right);}}list.add(curList);}System.out.println(list);}
//    直接输出结果
//    void levelOrder(TreeNode root) {
//        if (root == null){
//            System.out.println("这是颗空树!!!");
//            return;
//        }
//        Deque<TreeNode> queue = new LinkedList<>();
//        queue.offer(root);
//        while (!queue.isEmpty()){
//            TreeNode cur = queue.pop();
//            System.out.print(cur.val + " ");
//            if (cur.left != null){
//                queue.offer(cur.left);
//            }
//            if (cur.right != null){
//                queue.offer(cur.right);
//            }
//        }
//    }// 前序遍历public void preOrder(TreeNode root) {if(root == null){return;}System.out.print(root.val + " ");preOrder(root.left);preOrder(root.right);}// 中序遍历void inOrder(TreeNode root) {if(root == null){return;}inOrder(root.left);System.out.print(root.val + " ");inOrder(root.right);}// 后序遍历void postOrder(TreeNode root) {if(root == null){return;}postOrder(root.left);postOrder(root.right);System.out.print(root.val + " ");}public static int nodeSize;/*** 获取树中节点的个数:遍历思路*/void size(TreeNode root) {if (root == null){return;}nodeSize ++;size(root.left);size(root.right);}/*** 获取节点的个数:子问题的思路*/int size2(TreeNode root) {if (root == null) return 0;return size2(root.left) + size2(root.right) + 1;}/*获取叶子节点的个数:遍历思路*/public static int leafSize = 0;void getLeafNodeCount1(TreeNode root) {if(root == null){return;}if (root.left == null && root.right == null){leafSize ++;}getLeafNodeCount1(root.left);getLeafNodeCount1(root.right);}/*获取叶子节点的个数:子问题*/int getLeafNodeCount2(TreeNode root) {if (root == null) return 0;if (root.left == null && root.right == null) {return 1;}return getLeafNodeCount2(root.left) + getLeafNodeCount2(root.right);}/*获取第K层节点的个数*/int getKLevelNodeCount(TreeNode root, int k) {if (root == null || k <= 0){return 0;}if (k == 1){return 1;}return getKLevelNodeCount(root.left,k - 1) + getKLevelNodeCount(root.right,k - 1);}/*获取二叉树的高度时间复杂度:O(N)*/int getHeight(TreeNode root) {if (root == null){return 0;}if(root.left == null && root.right == null){return 1;}return 1 + Math.max(getHeight(root.left),getHeight(root.right));}// 检测值为value的元素是否存在TreeNode find(TreeNode root, char val) {if (root == null){return null;}if (root.val == val){return root;}TreeNode node = find(root.left,val);if (node != null){return node;}return find(root.right,val);}// 判断一棵树是不是完全二叉树boolean isCompleteTree(TreeNode root) {Deque<TreeNode> queue = new LinkedList<>();queue.offer(root);boolean isStep1 = true;while (!queue.isEmpty()){TreeNode node = queue.poll();if(isStep1){if(node.left != null && node.right != null){queue.offer(node.left);queue.offer(node.right);} else if (node.left != null) {queue.offer(node.left);isStep1 = false;} else if (node.right != null){return false;}else {isStep1 = false;}}else {if(node.left != null || node.right != null){return false;}}}return true;}public static void main(String[] args) {MyBinaryTree tree = new MyBinaryTree();//用前序遍历和后序遍历构建二叉树int[] pre = {3,9,20,15,7};int[] in = {9,3,15,20,7};TreeNode root = tree.buildTree1(pre,in);System.out.println("前序遍历");tree.preOrder(root);System.out.println();System.out.println("中序遍历");tree.inOrder(root);System.out.println();System.out.println("后序遍历");tree.postOrder(root);System.out.println();System.out.println("层序遍历");tree.levelOrder(root);System.out.println();System.out.println("统计树的节点个数");tree.size(root);System.out.println(nodeSize);System.out.println("统计叶子节点个数");tree.getLeafNodeCount1(root);System.out.println(leafSize);System.out.println("树的高度");System.out.println(tree.getHeight(root));System.out.println("检测树中值为val的元素是否存在 Q  B");
//        System.out.println(tree.find(root,'x').val);if (tree.find(root,'Q') == null){System.out.println("没有找到该元素");}else {System.out.println(tree.find(root,'x').val);}if (tree.find(root,'B') == null){System.out.println("没有找到该元素");}else {System.out.println(tree.find(root,'B').val);}System.out.println("获取第K层节点的个数");System.out.println(tree.getKLevelNodeCount(root,3));System.out.println("判断一棵树是不是完全二叉树");System.out.println(tree.isCompleteTree(root));}
}

6. 测试结果

http://www.lryc.cn/news/45827.html

相关文章:

  • 【面试】面试官问的几率较大的网络安全面试题
  • [Python] 循环语句
  • 计算机网络考试复习——第一章 1.5 1.6
  • 3.29 最小生成树算法
  • 计算机科班与培训开发编程的区别在哪里?
  • idea设置常用自设置快捷键及坐标
  • Vue 3.0 实例方法
  • 日撸 Java 三百行day1-10
  • Ubuntu Instant-ngp 训练自有数据集
  • k8s集群只一台节点,重启节点后命名空间找不到了
  • MarkDown示例
  • spring cloud 雪崩效应
  • Python 自动化指南(繁琐工作自动化)第二版:三、函数
  • c++多线程 1
  • STM32F103制作FlashDriver
  • springboot树形结构接口, 懒加载实现
  • java企业级信息系统开发学习笔记02初探spring——利用组件注解符精简spring配置文件
  • 用Python发送电子邮件?这也太丝滑了吧(21)
  • 分类预测 | MATLAB实现CNN-GRU-Attention多输入分类预测
  • C++提高编程(1)
  • day26 回溯算法的部分总结
  • 带你玩转Python爬虫(胆小者勿进)千万别做坏事·······
  • 【JavaScript 】严格模式,With关键字,测试框架介绍,assert
  • mybatis实现一个简单的CRUD功能的小案例(后端)编写流程
  • 腾讯云轻量应用服务器价格表(2023版)
  • 网络层IP协议和数据链路层
  • 零基础学习Java 03
  • PG数据库超时退出 TCP设定
  • 每日学术速递4.4
  • ChatGPT将引发大量而普遍的网络安全隐患