From 7d9b21790c5c58ddd1c0c329b94d1bccf21a4304 Mon Sep 17 00:00:00 2001 From: dingjiawen <745518019@qq.com> Date: Mon, 19 Sep 2022 15:31:02 +0800 Subject: [PATCH] =?UTF-8?q?leecode=E6=9B=B4=E6=96=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../leecode/tree/InorderTraversal.java | 160 ++++++++++--- .../leecode/tree/PreOrderTraversal.java | 211 ++++++++++++++++++ 2 files changed, 336 insertions(+), 35 deletions(-) create mode 100644 Leecode/src/main/java/com/markilue/leecode/tree/PreOrderTraversal.java diff --git a/Leecode/src/main/java/com/markilue/leecode/tree/InorderTraversal.java b/Leecode/src/main/java/com/markilue/leecode/tree/InorderTraversal.java index 920a458..e9ec1a8 100644 --- a/Leecode/src/main/java/com/markilue/leecode/tree/InorderTraversal.java +++ b/Leecode/src/main/java/com/markilue/leecode/tree/InorderTraversal.java @@ -1,9 +1,9 @@ package com.markilue.leecode.tree; - import java.util.ArrayList; import java.util.List; +import java.util.Stack; /** * 中序遍历二叉排序树 @@ -25,34 +25,34 @@ public class InorderTraversal { TreeNode2.setRight(TreeNode5); TreeNode3.setLeft(TreeNode6); - List integers = inorderTraversal1(root); + List integers = inorderTraversal4(root); System.out.println(integers); - } - public static List list =new ArrayList(); - public static List list2 =new ArrayList(); + public static List list = new ArrayList(); + public static List list2 = new ArrayList(); /** * 递归法:中序遍历 + * * @param root */ - public static void inorderTraversal(TreeNode root){ + public static void inorderTraversal(TreeNode root) { - if(root == null){ + if (root == null) { return; } - if(root.left !=null){ + if (root.left != null) { inorderTraversal(root.left); } list.add(root); - if(root.right !=null){ + if (root.right != null) { inorderTraversal(root.right); } @@ -60,73 +60,163 @@ public class InorderTraversal { /** * 递归法原题:中序遍历 => O(n) + * * @param root */ - public static List inorderTraversal2(TreeNode root){ + public static List inorderTraversal2(TreeNode root) { - if(root == null){ + if (root == null) { return null; } - if(root.left !=null){ + if (root.left != null) { inorderTraversal2(root.left); } list2.add(root.val); - if(root.right !=null){ + if (root.right != null) { inorderTraversal2(root.right); } return list2; } + /** + * 自己的非递归法:使用一个栈记录上次还需要进一步遍历的节点,等现在的遍历完了,就可以出栈到这里,让上一次的继续去遍历 + * + * @param root + * @return + */ + public static List inorderTraversal3(TreeNode root) { + List list = new ArrayList<>(); + + if (root == null) { + return list; + } + + //使用栈记录需要遍历的root + Stack stack = new Stack<>(); + TreeNode node = root; + + //核心理念是:先找到当前节点的最左节点,把这个值pop出之后就可以加入result,然后看看他的右子树 + while (stack.size() > 0 || node != null) { + //指针访问节点,访问到底层 + if (node != null) { + //将访问的节点放入栈 + stack.push(node); + node = node.left; + } else { + //从栈里弹出的数据就是要处理的数据(放入result数组的数据) + node = stack.pop(); + list.add(node.val); + node = node.right; + + } + } + + return list; + } + /** * 非递归法:中序遍历(题解第三种方法) ->空间复杂度 O(1)Morris 中序遍历 * 循环: - * 寻找当前节点的左子树: - * 如果左子树为空:将当前节点加入list,将当前节点右移 - * 如果不为空: - * 寻找当前节点的左子树最右节点flag,判断flag的右子节点是否为空: - * 如果为空:当前节点左移,设置flag的右子节点为当前节点 - * 如果不为空:说明已经遍历完当前节点的左子树,将flag的右子节点为置空,将当前节点加入list,当前节点右移 + * 寻找当前节点的左子树: + * 如果左子树为空:将当前节点加入list,将当前节点右移 + * 如果不为空: + * 寻找当前节点的左子树最右节点flag,判断flag的右子节点是否为空: + * 如果为空:当前节点左移,设置flag的右子节点为当前节点 + * 如果不为空:说明已经遍历完当前节点的左子树,将flag的右子节点为置空,将当前节点加入list,当前节点右移 + * * @param root */ - public static List inorderTraversal1(TreeNode root){ + public static List inorderTraversal1(TreeNode root) { - List list1 =new ArrayList(); + List list1 = new ArrayList(); - while (root != null){ - if(root.left ==null){ + while (root != null) { + if (root.left == null) { //如果左子树为空 list1.add(root.val); - root=root.right; - }else { + root = root.right; + } else { //如果左子树不为空: //记录左子树最右节点 - TreeNode p=root.left; + TreeNode p = root.left; //寻找flag - while (p.right !=null &&p.right != root){ - p=p.right; + while (p.right != null && p.right != root) { + p = p.right; } - TreeNode flag=p; + TreeNode flag = p; //判断flag是根据什么条件出来的,是flag.right ==null还是p.right != root - if(flag.right == null){ + if (flag.right == null) { //flag无右子节点,第一次遍历 - flag.right =root; - root=root.left; - }else if(flag.right == root){ + flag.right = root; + root = root.left; + } else if (flag.right == root) { //flag已经被加载过了,即当前节点的左子树已经被遍历完了 - flag.right =null; + flag.right = null; list1.add(root.val); - root=root.right; + root = root.right; } } } + return list1; + } + + + /** + * 自己尝试Morris中序遍历 + * 速度超过100%,内存超过81.82% + * @param root + */ + public static List inorderTraversal4(TreeNode root) { + + List list1 = new ArrayList(); + + TreeNode node1 = root; + TreeNode node2 = null; + + while (node1 != null) { + node2 = node1.left; + + //判断左边还有没有值 + if(node2!=null){ + //首先找到遍历node1之前的最后一个节点 + while (node2.right != null && node2.right != node1) { + node2 = node2.right; + } + + //判断是从哪个条件出来的 + if (node2.right == null) { + //如果是从第一个条件出来的,那么就是没有遍历过得节点 + + //将这个节点的右边定为node1方便以后回来,找到node1 + node2.right = node1; + //node1已经可以回溯,放心将node1左移 + node1 = node1.left; + continue; + } else { + //如果是从第二个条件出来的,那么就是遍历过的节点 + + //那么他的左边一定是遍历完了,这时将node的值加入结果 + list1.add(node1.val); + //左边遍历完了,往右移 + node1 = node1.right; + } + }else { + //左边没值了 + list1.add(node1.val); + node1=node1.right; + + } + + + } return list1; diff --git a/Leecode/src/main/java/com/markilue/leecode/tree/PreOrderTraversal.java b/Leecode/src/main/java/com/markilue/leecode/tree/PreOrderTraversal.java new file mode 100644 index 0000000..6bffeb5 --- /dev/null +++ b/Leecode/src/main/java/com/markilue/leecode/tree/PreOrderTraversal.java @@ -0,0 +1,211 @@ +package com.markilue.leecode.tree; + +import org.junit.Test; +import org.omg.CORBA.PUBLIC_MEMBER; + +import java.util.ArrayList; +import java.util.Collections; +import java.util.List; +import java.util.Stack; + +/** + * @BelongsProject: Leecode + * @BelongsPackage: com.markilue.leecode.tree + * @Author: dingjiawen + * @CreateTime: 2022-09-19 09:45 + * @Description: + * TODO 力扣144题 二叉树的前序遍历: + * 给你二叉树的根节点 root ,返回它节点值的 前序 遍历。 + * @Version: 1.0 + */ +public class PreOrderTraversal { + + + @Test + public void test(){ + + TreeNode root = new TreeNode(1); +// TreeNode TreeNode2 = new TreeNode(2); +// TreeNode TreeNode3 = new TreeNode(3); +// TreeNode TreeNode4 = new TreeNode(1); +// TreeNode TreeNode5 = new TreeNode(3); +// TreeNode TreeNode6 = new TreeNode(5); + +// root.setRight(TreeNode2); +// TreeNode2.setLeft(TreeNode3); +// TreeNode2.setLeft(TreeNode4); +// TreeNode2.setRight(TreeNode5); +// TreeNode3.setLeft(TreeNode6); + System.out.println(preorderTraversal1(root)); + } + + @Test + public void test1(){ + + TreeNode root = new TreeNode(1); + TreeNode TreeNode2 = new TreeNode(2); + TreeNode TreeNode3 = new TreeNode(3); +// TreeNode TreeNode4 = new TreeNode(1); +// TreeNode TreeNode5 = new TreeNode(3); +// TreeNode TreeNode6 = new TreeNode(5); + + root.setRight(TreeNode2); + TreeNode2.setLeft(TreeNode3); +// TreeNode2.setLeft(TreeNode4); +// TreeNode2.setRight(TreeNode5); +// TreeNode3.setLeft(TreeNode6); + System.out.println(preorderTraversal1(root)); + } + + @Test + public void test2(){ + + TreeNode root = new TreeNode(1); + TreeNode TreeNode2 = new TreeNode(2); + TreeNode TreeNode3 = new TreeNode(3); +// TreeNode TreeNode4 = new TreeNode(1); +// TreeNode TreeNode5 = new TreeNode(3); +// TreeNode TreeNode6 = new TreeNode(5); + + root.setRight(TreeNode2); + TreeNode2.setLeft(TreeNode3); +// TreeNode2.setLeft(TreeNode4); +// TreeNode2.setRight(TreeNode5); +// TreeNode3.setLeft(TreeNode6); + System.out.println(preorderTraversal1(null)); + } + + @Test + public void test3(){ + + TreeNode root = new TreeNode(1); + TreeNode TreeNode2 = new TreeNode(2); + TreeNode TreeNode3 = new TreeNode(3); + TreeNode TreeNode4 = new TreeNode(4); + TreeNode TreeNode5 = new TreeNode(5); + TreeNode TreeNode6 = new TreeNode(6); + TreeNode TreeNode7 = new TreeNode(7); + + root.setRight(TreeNode2); + root.setLeft(TreeNode3); + TreeNode2.setLeft(TreeNode4); + TreeNode2.setRight(TreeNode5); + TreeNode3.setRight(TreeNode6); + TreeNode3.setLeft(TreeNode7); + System.out.println(preorderTraversal2(root)); + } + + + + + public List preorderTraversal(TreeNode root) { + List list = new ArrayList<>(); + traversal(root, list); + return list; + } + + /** + * 自己的递归法 + * 速度击败100% ,内存击败76.4% + */ + public void traversal(TreeNode root,List list) { + + if(root==null){ + return; + } + list.add(root.val); + traversal(root.left,list); + traversal(root.right,list); + + } + + /** + * 自己的非递归法:使用一个栈记录上次还需要进一步遍历的节点,等现在的遍历完了,就可以出栈到这里,让上一次的继续去遍历 + * 速度击败100%,内存击败18% + * @param root + * @return + */ + public List preorderTraversal1(TreeNode root) { + List list = new ArrayList<>(); + + if(root==null){ + return list; + } + + //使用栈记录需要遍历的root + Stack stack = new Stack<>(); + stack.push(root); + + while (stack.size()>0){ + TreeNode node = stack.pop(); + list.add(node.val); + //如果右子树还需要遍历,等左子树遍历完了再遍历右子树 + if(node.right!=null){ + stack.push(node.right); + } + //如果左子树还需要遍历 + if(node.left!=null){ + stack.push(node.left); + } + } + + return list; + } + + + /** + * Morris 遍历:将空间复杂度降到O(1) + *Morris 遍历的核心思想是利用树的大量空闲指针,实现空间开销的极限缩减。其前序遍历规则总结如下: + * + * 1.新建临时节点,令该节点为 root; + * 2.如果当前节点的左子节点为空,将当前节点加入答案,并遍历当前节点的右子节点; + * 3.如果当前节点的左子节点不为空,在当前节点的左子树中找到当前节点在中序遍历下的前驱节点: + * 如果前驱节点的右子节点为空,将前驱节点的右子节点设置为当前节点。然后将当前节点加入答案,并将前驱节点的右子节点更新为当前节点。当前节点更新为当前节点的左子节点。 + * 如果前驱节点的右子节点为当前节点,将它的右子节点重新设为空。当前节点更新为当前节点的右子节点。 + * 4.重复步骤 2 和步骤 3,直到遍历结束。 + * + * TODO 核心理念是如何回到root节点的: + * 1)传统方法使用stack去回到root + * 2)这种方法利用叶子结点闲置的右指针,因为回到root的前提是左边的遍历完了,那么遍历完了之前的一个节点一定是叶子节点,可以提前找到这个叶子结点,将其右指针置为root,就可以回到root了 + * + * @param root + * @return + */ + public List preorderTraversal2(TreeNode root) { + List res = new ArrayList(); + if (root == null) { + return res; + } + + TreeNode p1 = root, p2 = null; + + while (p1 != null) { + p2 = p1.left; + if (p2 != null) { + //通过这个循环找到回到root的最后一个节点,第二个条件是判断是否遍历过这个节点 + while (p2.right != null && p2.right != p1) { + p2 = p2.right; + } + //从第一个条件出来的,证明这个节点没遍历过且是回到root前的最后一个节点 + if (p2.right == null) { + res.add(p1.val); + //让下次得以回到之前遍历的节点 + p2.right = p1; + //找到了回来的节点,放心的将root左移 + p1 = p1.left; + continue; + } else { + //从第二个条件出来的,证明这个节点遍历过了,那么就把他的右边置空 + p2.right = null; + } + } else { + //左边遍历完了 + res.add(p1.val); + } + p1 = p1.right; + } + return res; + } + + +}