五、二叉树

 

 1. 递归序

每个节点都遍历三遍

public static void f(Node head){
    if(head == null){
        return;
    }
    //1 先序
    f(head.left);
    //2 中序
    f(head.right);  
    //3 后序
}

1)先序遍历(头左右)在第一次遍历到节点的时候打印

2)中序遍历(左头右)在第二次遍历到节点的时候打印

3)后序遍历(左右头)在第三次遍历到节点的时候打印

2. 先序遍历流程

1)从栈中弹出一个节点

2)打印(处理)弹出的节点

3)先右在左放入栈中

    public static void preOrderUnRecur(Node head){
        System.out.print("pre-order:");
        if(head != null){
            Stack<Node> stack = new Stack<Node>();
            stack.add(head);
            while(!stack.isEmpty()) {
                head = stack.pop();
                System.out.print(head.value+ " ");
                if (head.right != null){
                    stack.push(head.right);
                }
                if (head.left!=null){
                    stack.push(head.left);
                }
            }
        }
        System.out.println();
    }

3.后序遍历

后序遍历是左右头,先序遍历是头左右->根据上面压栈方式是先右后左

那么如果我们先左后右,先序遍历就会变成头右左,在通过栈的处理就变成了左右头,也就是后序遍历

    public static void posOrderUnRecur1(Node head){
        System.out.print("pos-order: ");
        if(head!=null){
            Stack<Node> s1 = new Stack<Node>();
            Stack<Node> s2 = new Stack<>();
            s1.push(head);
            while(!s1.isEmpty()){
                head = s1.pop();
                s2.push(head);
                if (head.left!=null){
                    s1.push(head.left);
                }
                if (head.right!=null){
                    s1.push(head.right);
                }
            }
            while(!s2.isEmpty()){
                System.out.print(s2.pop().value+" ");
            }
        }
        System.out.println();
    }

4. 中序遍历

1)每颗子树,整颗树左边界进站

2)弹出打印、处理

3)弹出的右边界进站

    public static void inOrderUnRecur(Node head){
        System.out.print("in-order: ");
        if(head!=null){
            Stack<Node> stack = new Stack<>();
            while(!stack.isEmpty()|| head!=null){
                if(head!=null){
                    stack.push(head);
                    head = head.left;
                }else{
                    head = stack.pop();
                    System.out.print(head.value+" ");
                    head = head.right;
                }
            }
        }
        System.out.println();
    }

整棵树都是可以被左边界分解掉

 左头右(左头)

5. 直观的打印一颗二叉树

调用下面的函数可以图形化显示你的二叉树

public class Code04_PrintBinaryTree {

	public static class Node {
		public int value;
		public Node left;
		public Node right;

		public Node(int data) {
			this.value = data;
		}
	}

	public static void printTree(Node head) {
		System.out.println("Binary Tree:");
		printInOrder(head, 0, "H", 17);
		System.out.println();
	}

	public static void printInOrder(Node head, int height, String to, int len) {
		if (head == null) {
			return;
		}
		printInOrder(head.right, height + 1, "v", len);
		String val = to + head.value + to;
		int lenM = val.length();
		int lenL = (len - lenM) / 2;
		int lenR = len - lenM - lenL;
		val = getSpace(lenL) + val + getSpace(lenR);
		System.out.println(getSpace(height * len) + val);
		printInOrder(head.left, height + 1, "^", len);
	}

	public static String getSpace(int num) {
		String space = " ";
		StringBuffer buf = new StringBuffer("");
		for (int i = 0; i < num; i++) {
			buf.append(space);
		}
		return buf.toString();
	}

	public static void main(String[] args) {
		Node head = new Node(1);
		head.left = new Node(-222222222);
		head.right = new Node(3);
		head.left.left = new Node(Integer.MIN_VALUE);
		head.right.left = new Node(55555555);
		head.right.right = new Node(66);
		head.left.left.right = new Node(777);
		printTree(head);

		head = new Node(1);
		head.left = new Node(2);
		head.right = new Node(3);
		head.left.left = new Node(4);
		head.right.left = new Node(5);
		head.right.right = new Node(6);
		head.left.left.right = new Node(7);
		printTree(head);

		head = new Node(1);
		head.left = new Node(1);
		head.right = new Node(1);
		head.left.left = new Node(1);
		head.right.left = new Node(1);
		head.right.right = new Node(1);
		head.left.left.right = new Node(1);
		printTree(head);

	}

}

6.二叉树的宽度优先遍历

    public static void w(Node head){
        if (head==null){
            return;
        }
        Queue<Node> queue = new LinkedList<>();
        queue.add(head);
        while(!queue.isEmpty()){
            Node cur = queue.poll();
            System.out.println(cur.value);
            if (cur.left!=null){
                queue.add(cur.left);
            }
            if (cur.right!=null){
                queue.add(cur.right);
            }
        }
    }

题目:求一颗二叉树的最大宽度

问题拆分,需要知道遍历的节点处于第几层

    //获取二叉树的最大宽度
    public static int findMaxWidth(Node head){
        if (head==null){
            return 0;
        }
        Queue<Node> queue = new LinkedList<>();
        queue.add(head);
        HashMap<Node,Integer> levelMap = new HashMap<>();
        levelMap.put(head,1);
        int curlevel = 1;
        int count = 0;
        int max = Integer.MIN_VALUE;
        while(!queue.isEmpty()){
            Node cur = queue.poll();
            int curNodeLevel = levelMap.get(cur);//获得节点在第几层
            if(curNodeLevel == curlevel){
                count++;
            } else {
                max = Math.max(max,count);
                curlevel++;
                count = 1;//如果走到这已经有一个节点弹出了,所以初始值为1
            }
            if(cur.left!=null){
                levelMap.put(cur.left,curNodeLevel+1);
                queue.add(cur.left);
            }
            if (cur.right!=null){
                levelMap.put(cur.right,curNodeLevel+1);
                queue.add(cur.right);
            }
        }
        max = Math.max(max,count);//左神没这行会导致最后一层没加入到max中
        return max;
    }

不用hashmap

//不会写

7.二叉树的相关概念及其实现判断

题目:如何判断一颗二叉树是否是搜索二叉树?

左树小,右树大

中序遍历,一定都是升序

//递归
//非递归

题目:如何判断一颗二叉树是完全二叉树?

满的,最后一层从左到右是满的

宽搜

1)任何一个节点只有右侧没有左侧,直接false。

2)在1)条件下,如果遇到了第一个左右子不全,后续皆为叶子节点。

	public static boolean isCBT1(Node head) {
		if (head == null) {
			return true;
		}
		LinkedList<Node> queue = new LinkedList<>();
		// 是否遇到过左右两个孩子不双全的节点
		boolean leaf = false;
		Node l = null;
		Node r = null;
		queue.add(head);
		while (!queue.isEmpty()) {
			head = queue.poll();
			l = head.left;
			r = head.right;
			// 如果遇到了不双全的节点之后,又发现当前节点不是叶节点
			if ((leaf && (l != null || r != null)) || (l == null && r != null)) {
				return false;
			}
			if (l != null) {
				queue.add(l);
			}
			if (r != null) {
				queue.add(r);
			}
			if (l == null || r == null) {
				leaf = true;
			}
		}
		return true;
	}

题目:如何判断一颗二叉树是满二叉树?

第一种麻烦的方法:获得最大深度,节点个数,根据关系判断是否是满二叉树

题目:如何判断一颗二叉树是否是平衡二叉树?(二叉树题目套路)

平衡二叉树:左、右高度差为1

整理左右树的信息:平衡?高度?

	public static boolean isBalanced2(Node head) {
		return process(head).isBalanced;
	}
	
	public static class Info{
		public boolean isBalanced;
		public int height;
		
		public Info(boolean i, int h) {
			isBalanced = i;
			height = h;
		}
	}
	
	public static Info process(Node x) {
		if(x == null) {
			return new Info(true, 0);
		}
		Info leftInfo = process(x.left);
		Info rightInfo = process(x.right);
		int height = Math.max(leftInfo.height, rightInfo.height)  + 1;
		boolean isBalanced = true;
		if(!leftInfo.isBalanced) {
			isBalanced = false;
		}
		if(!rightInfo.isBalanced) {
			isBalanced = false;
		}
		if(Math.abs(leftInfo.height - rightInfo.height) > 1) {
			isBalanced = false;
		}
		return new Info(isBalanced, height);
	}

题目:如何判断一颗二叉树是否是搜索二叉树?(2)

 整理条件:

	public static boolean isBST2(Node head) {
		if (head == null) {
			return true;
		}
		return process(head).isBST;
	}

	public static class Info {
		public boolean isBST;
		public int max;
		public int min;

		public Info(boolean i, int ma, int mi) {
			isBST = i;
			max = ma;
			min = mi;
		}

	}

	public static Info process(Node x) {
		if (x == null) {
			return null;
		}
		Info leftInfo = process(x.left);
		Info rightInfo = process(x.right);
		int max = x.value;
		if (leftInfo != null) {
			max = Math.max(max, leftInfo.max);
		}
		if (rightInfo != null) {
			max = Math.max(max, rightInfo.max);
		}
		int min = x.value;
		if (leftInfo != null) {
			min = Math.min(min, leftInfo.min);
		}
		if (rightInfo != null) {
			min = Math.min(min, rightInfo.min);
		}
		boolean isBST = true;
		if (leftInfo != null && !leftInfo.isBST) {
			isBST = false;
		}
		if (rightInfo != null && !rightInfo.isBST) {
			isBST = false;
		}
		if (leftInfo != null && leftInfo.max >= x.value) {
			isBST = false;
		}
		if (rightInfo != null && rightInfo.min <= x.value) {
			isBST = false;
		}
		return new Info(isBST, max, min);
	}

树型DP

 题目:如何判断一颗二叉树是满二叉树?(2)

	public static boolean isFull1(Node head) {
		if (head == null) {
			return true;
		}
		int height = h(head);
		int nodes = n(head);
		return (1 << height) - 1 == nodes;
	}

	public static int h(Node head) {
		if (head == null) {
			return 0;
		}
		return Math.max(h(head.left), h(head.right)) + 1;
	}

	public static int n(Node head) {
		if (head == null) {
			return 0;
		}
		return n(head.left) + n(head.right) + 1;
	}

总结:套路是一棵树的节点能够向左右要相同的信息解决的题都可以这样做。应用于各种树形DP

8. 寻找二叉树的最低公共祖先节点

 往上最初汇聚的点


9. 在二叉树中找到一个节点的后继节点

	public static Node getSuccessorNode(Node node) {
		if (node == null) {
			return node;
		}
		if (node.right != null) {
			return getLeftMost(node.right);
		} else { // 无右子树
			Node parent = node.parent;
			while (parent != null && parent.right == node) { // 当前节点是其父亲节点右孩子
				node = parent;
				parent = node.parent;
			}
			return parent;
		}
	}

	public static Node getLeftMost(Node node) {
		if (node == null) {
			return node;
		}
		while (node.left != null) {
			node = node.left;
		}
		return node;
	}

10. 二叉树的序列化和反序列化

    //先序的方式序列化
    public static String serialByPre(Node head){
        if(head==null)return "#_";

        String res = head.value+"_";
        res += serialByPre(head.left);
        res += serialByPre(head.right);
        return res;
    }

    //先序的方法反序列化
    public static Node reconByPreString(String preStr){
        String[] values = preStr.split("_");
        Queue<String> queue = new LinkedList<>();
        for (int i = 0; i !=values.length; i++) {
            queue.add(values[i]);
        }
        return reconPreOrder(queue);
    }
    public static Node reconPreOrder(Queue<String> queue){
        String value = queue.poll();
        if(value.equals("#")){
            return null;
        }
        Node head = new Node(Integer.valueOf(value));
        head.left = reconPreOrder(queue);
        head.right = reconPreOrder(queue);
        return head;
        
    }

11.纸条对折痕迹凹凸问题

本质是二叉树的中序遍历,生成一颗不存在的二叉树

 

	public static void printAllFolds(int N) {
		process(1, N, true);
		System.out.println();
	}

	// 当前你来了一个节点,脑海中想象的!
	// 这个节点在第i层,一共有N层,N固定不变的
	// 这个节点如果是凹的话,down = T
	// 这个节点如果是凸的话,down = F
	// 函数的功能:中序打印以你想象的节点为头的整棵树!
	public static void process(int i, int N, boolean down) {
		if (i > N) {
			return;
		}
		process(i + 1, N, true);
		System.out.print(down ? "凹 " : "凸 ");
		process(i + 1, N, false);
	}

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值