算法学习笔记----二叉树

目录

二叉树前中后序遍历

递归

非递归

层序遍历

求二叉树层中最大元素的个数:

额外空间(哈希表)

不用额外空间

判断一棵树是否是二叉搜索树

判断一棵树是否是完全二叉树

判断一棵树是否是平衡二叉树

判断一棵树是否是满二叉树

最低公共祖先

后继节点

序列化与反序列化

折纸


二叉树前中后序遍历
递归
public static void preOrder(Node root) {
        
        if(root == null) {
            return;
        }
        System.out.println(root.value);
        preOrder(root.left);
        preOrder(root.right);
    }
    
    public static void inOrder(Node root) {
        
        if(root == null) {
            return;
        }
        preOrder(root.left);
        System.out.println(root.value);
        preOrder(root.right);
    }
​
    public static void postOrder(Node root) {
    
        if(root == null) {
            return;
        }
        preOrder(root.left);
        preOrder(root.right);
        System.out.println(root.value);
    }
非递归

二叉树非递归前序遍历: 准备一个栈,将头节点压栈,栈不为空时弹出打印当前节点,先压右再压左(弹出时就是左右)

非递归后序遍历: 准备两个栈,将头节点压栈,栈不为空时弹出,加入收集栈,先压左再压右(收集栈中加入顺序就是先右再左,弹出就是左右)

非递归中序遍历: 准备一个栈,如果当前节点不为null将当前节点压入栈,该节点更新为该节点的左孩子,如果为null,弹出一个节点(父节点)赋给当前并打印,将当前节点设为右孩子,遍历当前节点的右子树。

    public static void pre(Node root) {
        if(root == null) {
            return;
        }
        Stack<Node> stack = new Stack<>();
        stack.push(root);
        while(!stack.isEmpty()) {
            Node node = stack.pop();
            System.out.println(node.value);
            if(node.right != null) {
                stack.push(node.right);
            }
            if(node.left != null) {
                stack.push(node.left);
            }
        }
    }
    
    public static void in(Node root) {
        if(root == null) {
            return;
        }
        Stack<Node> stack = new Stack<>();        
        while(!stack.isEmpty() || root != null) {   
            if(root != null) {
                stack.push(root);
                root = root.left;
            }else {
                root = stack.pop();
                System.out.println(root.value);//整棵树被分解为左头 左头打印
                root = root.right;
            }
        }
    }
    
    public static void post(Node root) {
        if(root == null) {
            return;
        }
        Stack<Node> stack = new Stack<>();
        Stack<Node> temp = new Stack<>();
        
        stack.push(root);
        while(!stack.isEmpty()) {
            Node node = stack.pop();
            temp.push(node);
            if(node.left != null) {
                stack.push(node.left);
            }
            if(node.right != null) {
                stack.push(node.right);
            }
        }
        
        while(!temp.isEmpty()) {
            System.out.println(temp.pop().value);
        }
    }

层序遍历

准备一个队列,先将根节点加入到队列中,循环弹出打印,依次将左右孩子加入队列

求二叉树层中最大元素的个数:

1、用哈希表记录每个节点的层数,如果从队列中弹出的不是当前层就更新,循环结束后再更新一下最后一层

2、准备三个变量curend(当前层的最后一个节点)初始置为根节点, nextend(下一层最后一个节点)初始置为null,num = 0记录个数。 每次弹出队列时与当前curend作比较,若不是最后一个将左右孩子加入队列并更新nextend值,若是最后一个就将nextend的值赋给curend,nextend置为空,更新最大节点数。

额外空间(哈希表)
public static int process(Node root) {
        
        if(root == null) {
            return 0;
        }
        Queue<Node> queue = new LinkedList<>();
        queue.add(root);
        
        //记录节点在那一层
        Map<Node,Integer> map = new HashMap<>();
        int curlevel = 1;
        int max = Integer.MIN_VALUE;
        int count = 0;//记录当前层有几个节点
        
        map.put(root, 1);
        while(!queue.isEmpty()) {
            root = queue.remove();
            int curNodeLevel = map.get(root);
            if(curlevel != curNodeLevel) {
                curlevel++;
                max = Math.max(max, count);
                count = 0; 
            }else count++;
            
            if(root.left != null) {
                queue.add(root.left);
                map.put(root.left,curNodeLevel + 1);
            }
            if(root.right != null) {
                queue.add(root.right);
                map.put(root.right,curN odeLevel + 1);
            }
        }
        
        return Math.max(max, count);
    }
不用额外空间
public static int process2(Node root) {
        
        if(root == null) {
            return 0;
        }
        int max = Integer.MIN_VALUE;
        int count = 1;
        Node curend = root;//当前层的最后节点
        Node nextend = null;//下一层的最后节点
        
        Queue<Node> queue = new LinkedList<>();
        while(!queue.isEmpty()) {
            
            root = queue.remove();
            
            if(root.left != null) {
                queue.add(root.left);
                nextend = root.left;
            }
            if(root.right != null) {
                queue.add(root.right);
                nextend = root.right;
            }
            
            //如果当前节点为最后节点就结算
            if(root == curend) {
                curend = nextend;//滚动更新
                nextend = null;
                max = Math.max(max, count);
                count = 0;
            }else count++;
        }
        return max;
    }
判断一棵树是否是二叉搜索树

中序遍历,肯定有序,若后遍历的小于前个节点的value就不是

package com.wtp.二叉树;
​
import java.util.Stack;
​
public class 判断一棵树是否是搜索二叉树 {
​
    public static void main(String[] args) {
        
    }
    
    static int preValue = Integer.MIN_VALUE;
    public static boolean is1(Node root) {
        if(root == null){
            return true;
        }
        //左树不是则整体不是
        boolean left = is1(root.left);
        if(!left) return false;
        
        if(root.value >= preValue) {
            preValue = root.value;
        }else return false;//当前节点小于左子树也不是
        
        return is1(root.right);
    }
    
    public static boolean is2(Node root) {
        if(root == null) {
            return true;
        }
        int preValue = Integer.MIN_VALUE;
        Stack<Node> stack = new Stack<>();
        boolean is = true;
        while(root != null || !stack.isEmpty()) {
            
            if(root != null) {
                stack.push(root);
                root = root.left;
            }else {
                root = stack.pop();
                
                if(root.value >= preValue) {
                    preValue = root.value;
                }else return false;
                
                root = root.right;
            }
        }
        return true;
    }
    
    public static boolean is3(Node root) {
        return process1(root).is;
    }
    
    public static class Info{
        int max;
        int min;
        boolean is;
        
        public Info(boolean is,int min,int max) {
            this.min = min;
            this.max = max;
            this.is = is;
        }
    }
    
    public static Info process1(Node root) {
        if(root == null) {
            return null;
        }
        Info left = process1(root.left);
        Info right = process1(root.right);
        
        
        boolean is = true;
        int min = root.value;
        int max = root.value;
        
        if(left != null) {
            min = Math.min(min,left.min);
            max = Math.max(max,left.max);
        }
        if(right != null) {
            min = Math.min(min,right.min);
            max = Math.max(max,right.max);
        }
        if(left != null && (left.max > root.value || !left.is)){
            is = false;
        }
        if(right != null && (right.min < root.value || !right.is)){
            is = false;
        }
        
        return new Info(is,min,max);
        
    }
}
​
判断一棵树是否是完全二叉树

层序遍历,如果有右孩子没左孩子则不是,如果都有继续判断,如果有左没右则判断剩余节点是不是叶子节点,不是则不是

package com.wtp.二叉树;
​
import java.util.LinkedList;
import java.util.Queue;
​
public class 判断一棵树是否是完全二叉树 {
​
    public static void main(String[] args) {
        
    }
    
    
    public static boolean is1(Node root) {
        
        if(root == null) {
            return true;
        }
        
        Queue<Node> queue = new LinkedList<>();
        boolean is = false;
        queue.add(root);
        
        while(!queue.isEmpty()) {
            root = queue.remove();
            //如果有右孩子无左孩子 则一定不是完全二叉树
            if(root.left == null && root.right != null) {
                return false;
            }
            
            //如果遇到左右孩子不双全的节点后 有节点不是叶子节点就不是完全二叉树
            if(is && (root.right != null || root.left != null)) {
                return false;
            }
            
            if(root.left != null) {
                queue.add(root.left);
            }
            if(root.right != null) {
                queue.add(root.right);
            }
            
            //左右孩子不双全
            if(root.left == null || root.right == null) {
                //遇到该事件后 后面的所有节点都应为叶子节点
                is = true;
            }
            
        }
        
        return true;
    }
}
​
​
​
判断一棵树是否是平衡二叉树

递归遍历左右子树,返回类型自定义为树高和是否平衡的对象

package com.wtp.二叉树;
​
public class 判断一棵树是否是平衡二叉树 {
​
    public static void main(String[] args) {
​
    }
​
    public static boolean is1(Node root) {
        return process1(root).isAVL;
    }
​
    public static class Info {
        int height;
        boolean isAVL;
        
        public Info(int height, boolean isAVL) {
            this.height = height;
            this.isAVL = isAVL;
        }
​
    }
​
    public static Info process1(Node root) {
        if(root == null) {
            return new Info(0,true);
        }
        
        Info left = process1(root.left);
        Info right = process1(root.right);
        
        int height = Math.max(left.height, left.height) + 1;
        boolean is = Math.abs(left.height - right.height) < 2 
                        && left.isAVL && right.isAVL;
        
        return new Info(height,is);
    }
}
​
判断一棵树是否是满二叉树

求树深l 节点个数N 是否满足关系:N = 2^l - 1

package com.wtp.二叉树;
​
public class 判断一棵树是否是满二叉树 {
​
    public static void main(String[] args) {
        
    }
    
    public static class info{
        int nodeCount;
        int shen;
        
        public info(int count,int s) {
            shen = s;
            nodeCount = count;
        }
    }
    
    public static boolean is1(Node root) {
        if(root == null) {
            return true;
        }
        info info = process1(root);
        return  (1 << info.shen) - 1 == info.nodeCount;
    }
    
    public static info process1(Node root) {
        
        if(root == null) {
            return new info(0,0);
        }
        info left = process1(root.left);
        info right = process1(root.right);
        
        int count;
        int shen;
        
        count = left.nodeCount + right.nodeCount + 1;
        shen = Math.max(left.shen, right.shen) + 1;
        
        return new info(count,shen);
    }
}
​
最低公共祖先

找同处于一棵树的两节点的最低公共祖先: 1、先遍历树,将每个节点加入到map中,value-为父节点,再让o1往上窜将整个链加入到set中,最后让o2往上窜在set中找共同节点 2、深搜,搜索到o1或者o2直接返回,null就返回null,返回左右节点不为空的点,如果有节点左右都不为null说明就是公共祖先返回这个节点

package com.wtp.二叉树;
​
import java.util.HashMap;
import java.util.HashSet;
import java.util.Map;
​
public class 最低公共祖先 {
​
    public static void main(String[] args) {
        
    }
    
    public static Node lca2(Node root,Node o1,Node o2) {
        
        //在左右遍历时要么返回null 要么返回找到的o1或o2节点
        if(root == null || root == o1 || root == o2) {
            return root;
        }
        Node left = lca2(root.left,o1,o2);
        Node right = lca2(root.right,o1,o2);
        
        //如果左右子树都各自找到了o1及o2节点就返回此节点
        if(left != null && right != null) {
            return root;
        }
        
        //谁不为null就返回谁
        return left == null ? right : left;
    }
    
    
    public static Node lca(Node root,Node o1,Node o2) {
        //key-树中的每个节点 value-各个节点对应的父节点 
        HashMap<Node,Node> fatherMap = new HashMap<>();
        process(root,fatherMap);
        fatherMap.put(root, root);
        
        //记录o1或o2 往上窜的链
        HashSet<Node> set = new HashSet<>();
        Node cur = o1;
        while(cur != fatherMap.get(cur)) {
            set.add(cur);
            cur = fatherMap.get(cur);
        }
        set.add(root);
        
        cur = o2;
        //如果o2在往上窜的过程中遇到o1中的链中的节点 此节点就为最低公共祖先
        while(!set.contains(cur)) {
            cur = fatherMap.get(cur);
        }
        return cur;
    }
    
    //将每个节点及其父节点放入map
    public static void process(Node root,HashMap<Node,Node> map) {
        if(root == null) {
            return ;
        }
        map.put(root.left, root);
        map.put(root.right, root);
        process(root.left,map);
        process(root.right,map);
    }
}
​
后继节点

给定一个节点,返回该节点的后继节点

后继节点:中序遍历中一个节点的下一个节点 前驱节点:中序遍历中一个节点的前一个节点

找一个节点的后继节点: 若该节点有右节点,返回右子树的最左节点,若该节点没右节点判断该节点是否是父节点的左子树,是就返回父节点,否则就往上移动寻找

package com.wtp.二叉树;
​
public class 后继节点 {
​
    public static void main(String[] args) {
        
    }
    
    //后继节点是指 中序遍历的顺序中任一节点的下一个节点
    public static Node process(Node root) {
        
        if(root == null) {
            return null;
        }
        
        //如果有右子树 中序遍历的后继节点为右子树的最左的节点
        if(root.right != null) {
            return getright(root.right);
        }
        Node parent = root.parent;
        //走到这一步时无右子树 看该节点是否为父节点的左孩子
        while(root != parent.left && parent != null) {
            root = parent;
            parent = root.parent; 
        }
        
        return parent;
    }
    
    //返回以root为根的最左边的节点
    public static Node getright(Node root) {
        
        if(root == null) return null;
        
        while(root.left != null) {
            root = root.left;
        }
        return root;
    }
}
​
序列化与反序列化

内存结构=>字符串:序列化 字符串=>内存结构:反序列化

package com.wtp.二叉树;
​
import java.util.LinkedList;
import java.util.Queue;
​
public class 序列化与反序列化 {
​
    public static String xu(Node root) {
        
        if(root == null) return "#_";
        
        String v = root.value + "_";
        v += xu(root.left);
        v += xu(root.right);
        
        return v;
    }
    
    public static Node fan(String str) {
        
        String[] values = str.split("_");
        Queue<String> queue = new LinkedList<>();
        for(String s : values) {
            queue.add(s);
        }
        return f(queue);
    }
    
    public static Node f(Queue<String> queue) {
        String value = queue.poll();
        if(value.equals("#")) {
            return null;
        }
        Node node = new Node(Integer.parseInt(value));
        node.left = f(queue);
        node.right = f(queue);
        
        return node;
    }
}
​
折纸

给一张长条纸,捏住一端,反复折叠n次后打开,打印从捏住端往下的凹凸折痕顺序

package com.wtp.二叉树;
​
public class 折纸 {
    
    public static void main(String[] args) {
        process(1,true);
    }
​
    static int count = 3;
    public static void process(int n,boolean b) {
        
        if(n > count) {
            return;
        }
        process(n + 1,true);
        System.out.println(b ? "凹" : "凸");
        process(n + 1,false);
    }
}
​
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值