数据结构【树】-题目总结

树的宽度优先遍历(Java)

思路没什么好讲的,主要是用队列去实现。直接看code就可以明白。

class Node {
	Node left;
	Node right;
	int value;
}

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

求二叉树的宽度

宽度就是在二叉树中,如果某层的节点数最多,那么该节点数目就是这棵二叉树的宽度。
实现思路:在宽度优先遍历的基础上,定义一个HashMap,key存Node,value存层数。

import java.util.HashMap;
import java.util.LinkedList;

public class TreeMaxWidth {
    public class Node {
        Node left;
        Node right;
        int value;
    }

    public static int getMaxWidth(Node head) {
        if (head == null) {
            return 0;
        }
        LinkedList<Node> queue = new LinkedList<>();
        HashMap<Node, Integer> levelMap = new HashMap<>();
        queue.add(head);
        levelMap.put(head, 1);

        int curLevel = 0; //当前层数
        int curLevelNodeNumber = 0; //当前层数的节点数
        int max = 0; //最大

        while (!queue.isEmpty()) {
            Node x = queue.poll();
            int xLevel = levelMap.get(x);
            if (xLevel == curLevel) {
                curLevelNodeNumber++;                
            } else {
                //初始化当前层数和当前层个数
                curLevel = xLevel;
                max = Math.max(max, curLevelNodeNumber);
                curLevelNodeNumber = 1;
            }

            System.out.print(x.value);
            if (x.left != null) {
                queue.add(x.left);
                levelMap.put(x.left, curLevel + 1);
            }
            if (x.right != null) {
                queue.add(x.right);
                levelMap.put(x.right, curLevel + 1);
            }
        }
		return max;
    }
}

树的解题套路

1)前提:是否能把判断的流程定义为检查每一个节点的子树符合判断标准,并且答案一定在其中;
2)只要前提符合,就进行可能性分析(以左、右、中为顺序)
3)整合信息,求全集
套路的时间复杂度:O(n)。因为每个节点都给自己的父节点返回信息,而
总共有n个节点。

如何判断一棵二叉树是否为搜索二叉树

套路的思路:可以把判断分解为判断每一颗子树是否是搜索二叉树。所以前提符合,进行可能性分析:
1.左子树为搜索二叉树
2.右子树为搜索二叉树
3.左子树的最大值<节点值
4.右子树的最小值>节点值
最后再把四种可能性合并即可。
基于可能性分析,可以建立相应的类去判断:

public static class ReturnType {
        public boolean isBST; //是否是搜索二叉树
        public int max; //最大值
        public int min; //最小值
        public ReturnType(boolean isBST, int max, int min) {
            this.isBST = isBST;
            this.max = max;
            this.min = min;
        }
    }

整体的code如下:

public class IsBST {
    //节点定义
    public static class Node {
        public int value;
        public Node left;
        public Node right;
    }
	//主函数
    public static boolean isBST(Node head) {
        return process(head).isBST;//
    }

    /**
     * 只要分析可能性,后面的套路都是一样的
     * 四种可能性:左子树为bst,右子树为bst,左子树最大值<节点值,右子树最小值>节点值
     */
    public static class ReturnType {
        public boolean isBST;
        public int max;
        public int min;
        public ReturnType(boolean isBST, int max, int min) {
            this.isBST = isBST;
            this.max = max;
            this.min = min;
        }
    }

    public static ReturnType process(Node x) {
        if (x == null) {
            //防止被干扰
            return new ReturnType(true, Integer.MIN_VALUE, Integer.MAX_VALUE);
        }
        //加工黑盒
        ReturnType leftData = process(x.left);
        ReturnType rightData = process(x.right);
		//拆分黑盒
        int max = Math.max(x.value, Math.max(leftData.max, rightData.max));
        int min = Math.min(x.value, Math.min(leftData.min, rightData.min));
        boolean isBST = leftData.isBST 
                & rightData.isBST 
                & leftData.max < x.value 
                & rightData.min > x.value;

        return new ReturnType(isBST, max, min);
    }
}

如何判断一棵二叉树是否为平衡二叉树

平衡二叉树的要求:左子树与右子树的高度差的绝对值不超过1
该题目符合套路的前提,所以直接进行可能性的分析:
1.左子树平衡
2.右子树平衡
3.左子树与右子树的高度差的绝对值不超过1

public class Code06_IsBalancedTree {

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

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

	public static boolean isBalanced(Node head) {
		return process(head).isBalanced;
	}

	/**
	 * 	可能性分析:左子树平衡、右子树平衡、高度差不超过1
	 */
	public static class ReturnType {
		public boolean isBalanced;
		public int height;

		public ReturnType(boolean isBalanced, int height) {
			this.isBalanced = isBalanced;
			this.height = height;
		}
	}

	public static ReturnType process(Node x) {
		if (x == null) {
			return new ReturnType(true, 0);
		}
		ReturnType leftData = process(x.left);
		ReturnType rightData = process(x.right);
		int height = Math.max(leftData.height, rightData.height);
		boolean isBalanced = leftData.isBalanced && rightData.isBalanced
				&& Math.abs(leftData.height - rightData.height) < 2;
		return new ReturnType(isBalanced, height);
	}
}

如何判断一棵二叉树为满二叉树

在二叉树中,高度为height,总节点树为nodes,若满足:
2^height-1 == nodes
则该二叉树为满二叉树。

public class isFullTree {

    public static boolean isFull(Node head) {
        ReturnType all = process(head);
        int height = all.height;
        int allNodes = all.nodes;
        return (1 << height) - 1 == allNodes;
    }    

    public static class ReturnType {
        public int height; //高度
        public int nodes; //节点数
        public ReturnType (int height, int nodes) {
            this.height = height;
            this.nodes = nodes;
        }
    }

    public static ReturnType process(Node x) {
        if (x == null) {
            return ReturnType(0, 0);
        }
        ReturnType left = process(x.left);
        ReturnType right = process(x.right);
        int height =  Math.max(left.height, right.height);
        int nodes = left.nodes + 1 + right.nodes;
        return ReturnType(height, nodes);
    }
}

如何判断一棵二叉树为完全二叉树

该题目可以用宽度优先遍历去解决。
思路分解:
1.如果一个节点有右无左节点,则返回false,否则返回true;
2.再1返回true的情况下,遇到第一个左右不双全的节点时,后继遇到的节点必须是叶子节点,否则false。

import java.util.LinkedList;

public class Code05_IsCBT {

	public static class Node {
		public int value;
		public Node left;
		public Node right;
		public Node(int data) {
			this.value = data;
		}
	}

	public static boolean isCBT(Node head) {
		if (head == null) {
			return true;
		}
		LinkedList<Node> queue = new LinkedList<>();
		boolean leaf = false; //叶子节点阶段是否开启
		Node left = null;
		Node right = null;
		queue.add(head);
		while (!queue.isEmpty()) {
			head = queue.poll();
			left = head.left;
			right = head.right;
			//若叶子结点开启了,但左右还有节点,则false;若左空右不空,也返回false
			if ((leaf && (left != null || right != null)) || (left == null && right != null)) {
				return false;
			}
			//开启叶子节点阶段
			if (left == null || right == null) {
				leaf = true;
			}
			if (left != null) {
				queue.add(l);
			}
			if (right != null) {
				queue.add(r);
			}
		}
		return true;
	}
}

在一棵二叉树中,求两个给定节点的最低、公共祖先节点

实现思路:
将2个给定节点放入树中进行搜索,当碰到给定节点时,将节点向上返回,当两个节点相遇时,这个节点就是最低、公共祖先节点。

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

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

public static Node lowestAncestor(Node head, Node o1, Node o2) {
	if (head == null || head == o1 || head == o2) {
		return head;
	}
	Node left = lowestAncestor(head.left, o1, o2);
	Node right = lowestAncestor(head.right, o1, o2);
	if (left != null && right != null) {
		return head;
	}
	return left != null ? left : right;
}
  • 3
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值