第四课:二叉树

1.二叉树递归遍历
前序:

	public static void preOrderRecur(Node head) {
		if(head==null){
			return;
		}
		System.out.println(head.value);
		preOrderRecur(head.left);
		preOrderRecur(head.right);
	}

中序:

	public static void inOrderRecur(Node head) {
		if(head==null){
			return;
		}
		inOrderRecur(head.left);
		System.out.println(head.value);
		inOrderRecur(head.right);
	}

后序:

	public static void posOrderRecur(Node head) {
		if(head==null){
			return;
		}
		posOrderRecur(head.left);
		posOrderRecur(head.right);
		System.out.println(head.value);
	}

2.二叉树非递归遍历
前序:

	public static void preOrderUnRecur(Node head) {
		Stack<Node> stack = new Stack<>();
		stack.push(head);
		while(!stack.isEmpty()){
			Node h=stack.pop();
			System.out.println(h.value);
			if(h.right!=null){
				stack.push(h.right);
			}
			if(h.left!=null){
				stack.push(h.left);
			}
		}
	

中序:需要注意:第一次没写出来

	public static void inOrderUnRecur(Node head) {
		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.println(head.value);
				head=head.right;
			}
		}
	}

后序:

	public static void posOrderUnRecur1(Node head) {
		if(head!=null){
			Stack<Node> stack1=new Stack<>();
			Stack<Node> stack2=new Stack<>();
			stack1.push(head);
			while(!stack1.isEmpty()){
				head=stack1.pop();
				stack2.push(head);
				if(head.left!=null){
					stack1.push(head.left);
				}
				if(head.right!=null){
					stack1.push(head.right);
				}
			}
			while(!stack2.isEmpty()){
				System.out.println(stack2.pop().value);
			}
		}
	}

3.求二叉树的宽度
方法一:hashmap存当前节点的层数

	public static int getMaxWidth(Node head) {
		Queue<Node> queue=new LinkedList<>();
		queue.add(head);
		int maxWidth=Integer.MIN_VALUE;
		int curLevel=1;
		int curLevelNode=0;
		HashMap<Node,Integer> hashMap=new HashMap<>();
		hashMap.put(head,1);
		while(!queue.isEmpty()){
			head=queue.poll();
			if(hashMap.get(head)==curLevel){
				curLevelNode++;
			}else{
				maxWidth=Math.max(curLevelNode,maxWidth);
				curLevel++;
				curLevelNode=1;
			}
			if(head.left!=null){
				queue.add(head.left);
				hashMap.put(head.left,curLevel+1);
			}
			if(head.right!=null){
				queue.add(head.right);
				hashMap.put(head.right,curLevel+1);
			}
		}
		return maxWidth;
	}

方法二:

public static int getMaxWidth1(Node head){
		Queue<Node> queue=new LinkedList<>();
		Node curEnd=head;
		Node nextEnd=null;
		int curLevelNode=0;
		int max=0;
		queue.add(head);
		while(!queue.isEmpty()){
			head=queue.poll();
			curLevelNode++;
			if(head.left!=null){
				queue.add(head.left);
				nextEnd=head.left;
			}
			if(head.right!=null){
				queue.add(head.right);
				nextEnd=head.right;
			}
			if(head==curEnd){
				max=Math.max(max,curLevelNode);
				curEnd=nextEnd;
				curLevelNode=0;
			}
		}
		return max;
	}

4.判断一棵二叉树是否为搜索二叉树(左子树的值小于根,右子树的值大于根)
法一:中序遍历,拿list集合存,最终看是否为升序

	public static class Node {
		public int value;
		public Node left;
		public Node right;
		public Node(int data) {
			this.value = data;
		}
	}
	public static boolean isBST(Node head) {
		if(head==null){
			return true;
		}
		List<Node> inOrderList = new ArrayList<>();
		process(head,inOrderList);
		for (int i = 0; i < inOrderList.size()-1; i++) {
			if(inOrderList.get(i).value>inOrderList.get(i+1).value){
				return false;
			}
		}
		return true;
	}
	public static void process(Node node, List<Node> inOrderList) {
		if(node==null){
			return;
		}
		process(node.left,inOrderList);
		inOrderList.add(node);
		process(node.right,inOrderList);
	}

法二:二叉树的套路:看左树右树能提供什么信息(不熟练,需注意)

	public static class Information{
		public boolean isBst;
		public int max;
		public int min;

		public Information(boolean isBst, int max, int min) {
			this.isBst = isBst;
			this.max = max;
			this.min = min;
		}
	}
	
	public static boolean isBST1(Node head){
		if(head==null){
			return true;
		}
		Information infor=process1(head);
        return infor.isBst;
	}
	
	public static Information process1(Node node){
		if(node==null){
			return null;
		}
		Information inforLeft=process1(node.left);
		Information inforRight=process1(node.right);
		int max=node.value;
		int min=node.value;
		if(inforLeft!=null){
		    max=Math.max(max,inforLeft.max);
		    min=Math.min(min,inforLeft.min);
        }
        if(inforRight!=null){
            max=Math.max(max,inforRight.max);
            min=Math.min(min,inforRight.min);
        }
        boolean isBst=true;
		if(inforLeft!=null&&(inforLeft.isBst==false||inforLeft.max>=max)){
		    isBst=false;
		}
		if(inforRight!=null&&(inforRight.isBst==false||inforRight.min<=min)){
		    isBst=false;
        }
        return new Information(isBst,max,min);
	}

5.判断是否是完全二叉树
(1)任一节点,有右无左,false
(2)在(1)符合的条件下,遇到第一个左右孩子不双全,后续节点都为叶子节点

	public static boolean isCBT(Node head) {
		if(head==null){
			return true;
		}
		Queue<Node> queue=new LinkedList<>();
		queue.add(head);
		boolean isZi=false;//遇到第一个左右孩子不双全的节点变为true
		while(!queue.isEmpty()){
			Node poll = queue.poll();
			if (poll.left==null&&poll.right!=null){
				return false;
			}
			if(isZi==true){
				if (poll.left!=null||poll.right!=null){
					return false;
				}
			}
			if(poll.left!=null){
				Node left=poll.left;
				queue.add(left);
			}else{
				isZi=true;
			}
			if(poll.right!=null){
				Node right=poll.right;
				queue.add(right);
			}else{
				isZi=true;
			}
		}
		return true;
	}

6.判断是否是满二叉树
法一:求深度,求节点个数,满足nodeNum=2^depth-1

	public static boolean isFullTree(Node head){
		int depth = depth(head);
		int count = count(head);
		if(count==Math.pow(2,depth)-1){
			return true;
		}
		return false;
	}

	private static int depth(Node head) {
		int depth=1;
		while(head.left!=null){
			head=head.left;
			depth++;
		}
		return depth;
	}

	private static int count(Node head) {
		List<Node> list=new ArrayList<>();
		process(head, list);
		return list.size();
	}
	
	public static void process(Node head, List<Node> list){
		if(head==null){
			return;
		}
		list.add(head);
		process(head.left,list);
		process(head.right,list);
	}

法二:套路:管左子树要信息(左子树的节点个数,深度),管右子树要信息,判断自身

	public static class Info{
		public int depth;
		public int nodeNum;
		public Info(int depth,int nodeNum){
			this.depth=depth;
			this.nodeNum=nodeNum;
		}
	}
	public static boolean isFull(Node head){
		Info info=process(head);
		if(Math.pow(2,info.depth)-1==info.nodeNum){
			return true;
		}
		return false;
	}
	public static Info process(Node head){
		if(head==null){
			return new Info(0,0);
		}
		Info infoLeft=process(head.left);
		Info infoRight=process(head.right);
		int depth=Math.max(infoLeft.depth,infoRight.depth)+1;
		int num=infoLeft.nodeNum+infoRight.nodeNum+1;
		return new Info(depth,num);
	}

7.判断是否是平衡二叉树

	public static boolean isBalanced(Node head) {
		return process(head).isBalanced;
	}
	public static class Info{
		boolean isBalanced;
		int height;

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


	public static Info process(Node x) {
		if(x==null){
			return new Info(true,0);
		}
		Info infoLeft = process(x.left);
		Info infoRight=process(x.right);
//		boolean isBalanced=false;
//		int height=0;
//		if(infoLeft.isBalanced&&infoRight.isBalanced){
//			if(Math.abs(infoLeft.height-infoRight.height)<=1){
//				isBalanced=true;
//				height=Math.max(infoLeft.height,infoRight.height)+1;
//			}
//		}
//两种写法都可,下面的更简洁
		int height=Math.max(infoLeft.height,infoRight.height)+1;
		boolean isBalanced=(infoLeft.isBalanced&&infoRight.isBalanced)&&(Math.abs(infoLeft.height-infoRight.height)<=1);
		return new Info(isBalanced,height);
	}

7.寻找公共祖先节点
法一:Map保存所有节点的父节点
node1往上的链存入set
node2再往上走,看节点是否在set中

	public static Node lowestAncestor(Node head, Node o1, Node o2) {
		HashMap<Node ,Node > hashMap=new HashMap<>();
		Node h=head;
		hashMap.put(head,head);
		Queue<Node> queue = new LinkedList<>();
		queue.add(head);
		//层序遍历存节点
		while(!queue.isEmpty()){
			Node poll=queue.poll();
			if(poll.left!=null){
				hashMap.put(poll.left,poll);
				queue.add(poll.left);
			}
			if(poll.right!=null){
				hashMap.put(poll.right,poll);
				queue.add(poll.right);
			}
		}
		HashSet<Node> hashSet=new HashSet<>();
		while(o1!=hashMap.get(o1)){
			hashSet.add(o1);
			o1=hashMap.get(o1);
		}
		while(o2!=hashMap.get(o2)){
			if(hashSet.contains(o2)){
				return o2;
			}
			o2=hashMap.get(o2);
		}
		return h;
	}

法二:(很模糊)

	public static Node lowestAncestor1(Node head, Node o1, Node o2){
		if(head==null||head==o1||head==o2){
			return head;
		}
		Node left=lowestAncestor1(head.left,o1,o2);
		Node right=lowestAncestor1(head.right,o1,o2);
		if(left!=null&&right!=null){
			return head;
		}
		return left!=null?left:right;
	}

8.二叉树中找一个节点的后继节点
法一:拿list存中序遍历顺序,直接找该节点的下一个节点(这种情况必须把头节点传进来)

    public static Node getSuccessorNode(Node head, Node x) {
        List<Node> list = new ArrayList<>();
        process(head, list);
        Node node = null;
        for (int i = 0; i < list.size(); i++) {
            if (list.get(i) == x) {
                if ((i + 1) < list.size()) {
                    node = list.get(i + 1);
                } else {
                    node = null;
                }
            }
        }
        return node;
    }

    public static void process(Node head, List<Node> list) {
        if (head == null) {
            return;
        }
        process(head.left, list);
        list.add(head);
        process(head.right, list);
    }

法二:(1)x有右树–右树上的最左节点
(2)x无右树–是父节点的左孩子吗?不是,往上,是返回父节点

    public static Node getSuccessorNode(Node node) {
        if (node == null) {
            return null;
        }
        if (node.right != null) {
            node = getLeft(node);
        } else {
            while (node.parent != null && node != node.parent.left) {//注意node.parent != null这个条件,第一次没写陷入了窘境
                node = node.parent;
            }
            node = node.parent;
        }
        return node;
    }
	//获取最左边的节点
    public static Node getLeft(Node node) {
        if (node == null) {
            return node;
        }
        node = node.right;
        while (node.left != null) {
            node = node.left;
        }
        return node;
    }

9.二叉树的序列化与反序列化
序列化:

    public static String serialByPre(Node head) {
        if (head == null) {
            return "#_";
        }
        String str = head.value + "_";
        String left = serialByPre(head.left);
        str = str+left;
        String right = serialByPre(head.right);
        str += right;
        return str;
    }

反序列化:(模糊)

    public static Node reconByPreString(String preStr) {
        String [] strs= preStr.split("_");
        Queue<String> queue=new LinkedList<>();
        for (int i = 0; i < strs.length; i++) {
            queue.add(strs[i]);
        }
        return null;
    }

    public static Node reconPreOrder(Queue<String> queue) {
        String str=queue.poll();
        if(str=="#"){
            return null;
        }
        Node head=new Node(Integer.valueOf(str));
        head.left=reconPreOrder(queue);
        head.right=reconPreOrder(queue);
        return head;
    }

10.折纸问题(模糊)

	public static void printAllFolds(int N) {
		printProcess(1, N, true);
	}

	public static void printProcess(int i, int N, boolean down) {
		if(i>N){
			return;
		}
		printProcess(i+1,N,true);
		System.out.println(down?"down":"up");
		printProcess(i+1,N,false);
	}

	public static void main(String[] args) {
		int N = 1;
		printAllFolds(N);
	}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值