我要进大厂-算法-第六天(二叉树所有问题,拿来吧你)

阅读该文章预计60分钟

一:二叉树的遍历

1.1:题目描述

实现二叉树的先序、中序、后序遍历,包括递归方式和非递归方式

1.2:思路分析

递归

递归遍历二叉树是相对来说比较容易的

如果当前节点为空,则返回
将节点的左右孩子递归

如果打印语句放在第一次来到递归函数,也就是左孩子递归的前面,就是前序
如果打印语句放在第二次来到递归函数,也就是左孩子递归的后面,右孩子的前面,就是中序
如果打印语句放在第三次来到递归函数,也就是右孩子递归的后面,就是前序

非递归

前序非递归遍历二叉树

前序非递归遍历二叉树

递归过程用到了系统的栈帮我们实现的
如果非递归过程就需要我们申请额外空间来记录元素

我们可以用栈来记录我们的元素
由于是前序,我们遵循打印顺序:父节点-左孩子-右孩子
故,如果我们使用栈,需将右孩子放入栈,左孩子再放入栈
依次递归
详细请看代码!

中序非递归遍历二叉树

QAQ	~~~~~~~~~~~~~~呜呜呜搞了好久才搞出来
中序非递归遍历二叉树

递归过程用到了系统栈,我们不递归,就需要一个队列或者栈来实现
这里我们使用栈

如果我们的栈不为空或者我们的处理节点不为空,
我们从栈中消费一个元素
一直遍历他的左孩子,并放到栈中,并且当前左孩子当作处理节点(这样才能一直找到左边界)
如果左孩子为空了,那么弹出当前元素,把右孩子当作当前节点,继续遍历。

你品,每个节点,先处理左节点,然后再弹出自己,然后再处理右节点。
详细看代码!

后续非递归遍历二叉树

啊  这个 反正不简单  看看吧  我debug好久才调整好边界
后序非递归二叉树

递归过程用到了系统栈,我们不递归,就需要一个队列或者栈
我们用一个栈
将头节点压栈
如果当前栈不为空,则消费一个数据
如果该数据的右孩子不为空则压入右孩子
如果该数据的左孩子不为空则压入左孩子
记录上一个被弹出的节点,
如果上一个弹出的节点是左孩子,或者右孩子,则左孩子不压栈了
如果上一个弹出的节点是右孩子,则右孩子不压栈了
如果都不满足,开始弹栈
详细请看代码

1.3:Java代码

package xyz.fudongyang.basic.class_04.my;

import java.util.Stack;

public class Code_01_PreInPosTraversal {

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

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

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

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

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

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

    // 非递归中序
    public static void inOrderUnRecur(Node head) {
        if (head == null) {
            return;
        }
        System.out.print("inOrderUnRecur:");
        // 准备一个栈,用于保存数据以及先后顺序
        Stack<Node> stack = new Stack<>();
        // 把每个节点都当作头节点,榨干他的左孩子
        while (!stack.isEmpty() || head != null) {
            if (head != null) {
                // 把当前节点压入栈,继续榨干他的左孩子
                stack.push(head);
                head = head.left;
            } else {
                // 已经没有左孩子了,那么终于可以打印自己了,打印完后让右孩子继续榨干它的左孩子
                Node pop = stack.pop();
                System.out.print(pop.value + " ");
                head = pop.right;
            }
        }
        System.out.println();
    }

    // 非递归后续
    public static void posOrderUnRecur1(Node head) {
        if (head == null) {
            return;
        }
        System.out.print("posOrderUnRecur1: ");
        Stack<Node> stack = new Stack<>();
        stack.push(head);
        Node peek;
        while (!stack.isEmpty()) {
            peek = stack.peek();
            // 左孩子,右孩子回来的都不能再执行
            if (peek.left != null && peek.left != head && peek.right != head) {
                stack.push(peek.left);
            } else if (peek.right != null && peek.right != head) { // 我的右孩子加过,不用再加
                stack.push(peek.right);
            } else {
                Node pop = stack.pop();
                System.out.print(pop.value + " ");
                head = pop;
            }
        }
        System.out.println();
    }

    public static void main(String[] args) {
        /**
         * 			  5
         * 		3			8
         * 	 2	  4	     7		10
         *  1		   6     9	  11
         *
         */
        Node head = new Node(5);
        head.left = new Node(3);
        head.right = new Node(8);
        head.left.left = new Node(2);
        head.left.right = new Node(4);
        head.left.left.left = new Node(1);
        head.right.left = new Node(7);
        head.right.left.left = new Node(6);
        head.right.right = new Node(10);
        head.right.right.left = new Node(9);
        head.right.right.right = new Node(11);

        // recursive
        System.out.println("==============recursive==============");
        System.out.print("pre-order: ");
        preOrderRecur(head);
        System.out.println();
        System.out.print("in-order: ");
        inOrderRecur(head);
        System.out.println();
        System.out.print("pos-order: ");
        posOrderRecur(head);
        System.out.println();

        // unrecursive
        System.out.println("============unrecursive=============");
        preOrderUnRecur(head);
        inOrderUnRecur(head);
        posOrderUnRecur1(head);
//		posOrderUnRecur2(head);

    }

}

二:找到二叉树的后继节点

2.1:题目描述

在二叉树中找到一个节点的后继节点
【题目】 现在有一种新的二叉树节点类型如下:

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

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

该结构比普通二叉树节点结构多了一个指向父节点的parent指针。假设有一 棵Node类型的节点组成的二叉树,树中每个节点的parent指针都正确地指向 自己的父节点,头节点的parent指向null。只给一个在二叉树中的某个节点 node,请实现返回node的后继节点的函数。在二叉树的中序遍历的序列中, node的下一个节点叫作node的后继节点。

2.2:思路讲解

在二叉树中找到下一个节点  并且有parent指针

我们拿一个普通节点来判断

如果它有右孩子,那么我只需要找到它的右孩子的最左孩子就行
这样它的后续节点就是它右孩子的最左节点

如果它没有右孩子并且它是它父亲的左孩子,那么它的下一个节点就是父亲

如果它没有右孩子并且它是它父亲的右孩子,那么一直找他的父亲,知道它的父亲是祖先的左孩子位置
详细代码如下

2.3:Java代码

package xyz.fudongyang.basic.class_04.my;

public class Code_03_SuccessorNode {

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

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



	public static Node getSuccessorNode(Node node) {
		if (node == null){
			return null;
		}
		if (node.right != null){
			return getLeftMost(node.right);
		}else {
			Node parent = node.parent;
			while (parent != null && parent.left != node){
				node = parent;
				parent = parent.parent;
			}
			return parent;
		}
	}

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



	public static void main(String[] args) {
		Node head = new Node(6);
		head.parent = null;
		head.left = new Node(3);
		head.left.parent = head;
		head.left.left = new Node(1);
		head.left.left.parent = head.left;
		head.left.left.right = new Node(2);
		head.left.left.right.parent = head.left.left;
		head.left.right = new Node(4);
		head.left.right.parent = head.left;
		head.left.right.right = new Node(5);
		head.left.right.right.parent = head.left.right;
		head.right = new Node(9);
		head.right.parent = head;
		head.right.left = new Node(8);
		head.right.left.parent = head.right;
		head.right.left.left = new Node(7);
		head.right.left.left.parent = head.right.left;
		head.right.right = new Node(10);
		head.right.right.parent = head.right;

		Node test = head.left.left;
		System.out.println(test.value + " next: " + getSuccessorNode(test).value);
		test = head.left.left.right;
		System.out.println(test.value + " next: " + getSuccessorNode(test).value);
		test = head.left;
		System.out.println(test.value + " next: " + getSuccessorNode(test).value);
		test = head.left.right;
		System.out.println(test.value + " next: " + getSuccessorNode(test).value);
		test = head.left.right.right;
		System.out.println(test.value + " next: " + getSuccessorNode(test).value);
		test = head;
		System.out.println(test.value + " next: " + getSuccessorNode(test).value);
		test = head.right.left.left;
		System.out.println(test.value + " next: " + getSuccessorNode(test).value);
		test = head.right.left;
		System.out.println(test.value + " next: " + getSuccessorNode(test).value);
		test = head.right;
		System.out.println(test.value + " next: " + getSuccessorNode(test).value);
		test = head.right.right; // 10's next is null
		System.out.println(test.value + " next: " + getSuccessorNode(test));
	}

}

三:二叉树的序列化和反序列化

3.1:题目介绍

先序序列、反序列化二叉树

层序序列、反序列化二叉树

3.2:思路讲解

先序序列化、反序列化

先序序列二叉树:
递归遍历二叉树,如果碰到null,就填充特殊字符,例如“#”
每个指针的结尾都需要一个结尾符号,例如“!”
返回一个字符串

先序反序列化二叉树:
拿到字符串后,按照我们的结尾符号进行分割
因为是先序遍历,所以我们先把它放入一个队列里面,方便处理

这里需要一个递归函数,功能如下
从队列取一个值,进行封装这个值,如果这个值不等于null(#),那就new一个node,并把value传进去
它需要它的左孩子
它需要它的右孩子
它的左孩子就是左孩子去递归,丰富自己
它的右孩子就是右孩子去递归,丰富自己

详细看代码

层序序列化、反序列化

层序序列化:
首先要知道如何层序遍历二叉树
很简单,把头节点放入队列中
消费队列的值,当队列不为空的时候,如果左孩子、右孩子不为空,分别放入
我们这样序列化我们二叉树,遇到null序列化为“#!”,其他值为“{value}!”

层序反序列化:
首先将字符串按照结尾符分割,得到所有节点数值
将头节点放入队列中
遍历字符串数组,从队列中拿到值,
将数组的下一个当作值的左孩子,当数组的下第二个当作值的右孩子
把左孩子,右孩子放入队列中。
直到队列为空或者数组为空

3.3:Java代码

package xyz.fudongyang.basic.class_04.my;

import java.util.LinkedList;
import java.util.Queue;

public class Code_04_SerializeAndReconstructTree {

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

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

	public static String serialByPre(Node head) {
		// base case
		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[] split = preStr.split("!");
		// 因为是先序遍历,需要用队列
		Queue<String> queue = new LinkedList<>();
		for (String s : split) {
			// 如果插入失败返回false
			queue.offer(s);
		}
		return reconPreOrder(queue);
	}

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

	public static String serialByLevel(Node head) {
		if (head == null){
			return "#!";
		}
		StringBuilder res = new StringBuilder();
		res.append(head.value).append("!");
		Queue<Node> queue = new LinkedList<>();
		queue.add(head);
		while (!queue.isEmpty()){
			Node poll = queue.poll();
			if (poll.left!= null){
				res.append(poll.left.value).append("!");
				queue.add(poll.left);
			}else {
				res.append("#!");
			}
			if (poll.right!=null){
				res.append(poll.right.value).append("!");
				queue.add(poll.right);
			}else {
				res.append("#!");
			}
		}
		return res.toString();
	}

	public static Node reconByLevelString(String levelStr) {
		if(levelStr == null){
			return null;
		}
		String[] split = levelStr.split("!");
		int i = 0;
		if ("#".equals(split[i])){
			return null;
		}
		Node node = new Node(Integer.parseInt(split[i++]));
		Queue<Node> queue = new LinkedList<>();
		queue.add(node);
		while (!queue.isEmpty()){
			Node poll = queue.poll();
			String split1 = split[i];
			Node left = null;
			if (!"#".equals(split1)){
				left = new Node(Integer.parseInt(split[i]));
			}
			i++;
			String split2 = split[i];
			Node right = null;
			if (!"#".equals(split2)){
				right = new Node(Integer.parseInt(split[i]));
			}
			i++;
			poll.left = left;
			poll.right = right;
			if (left!= null){
				queue.add(left);
			}
			if (right != null){
				queue.add(right);
			}
		}
		return node;
	}

	public static Node generateNodeByString(String val) {
		if (val.equals("#")) {
			return null;
		}
		return new Node(Integer.valueOf(val));
	}

	// for test -- print tree
	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 = null;
		printTree(head);

		String pre = serialByPre(head);
		System.out.println("serialize tree by pre-order: " + pre);
		head = reconByPreString(pre);
		System.out.print("reconstruct tree by pre-order, ");
		printTree(head);

		String level = serialByLevel(head);
		System.out.println("serialize tree by level: " + level);
		head = reconByLevelString(level);
		System.out.print("reconstruct tree by level, ");
		printTree(head);

		System.out.println("====================================");

		head = new Node(1);
		printTree(head);

		pre = serialByPre(head);
		System.out.println("serialize tree by pre-order: " + pre);
		head = reconByPreString(pre);
		System.out.print("reconstruct tree by pre-order, ");
		printTree(head);

		level = serialByLevel(head);
		System.out.println("serialize tree by level: " + level);
		head = reconByLevelString(level);
		System.out.print("reconstruct tree by level, ");
		printTree(head);

		System.out.println("====================================");

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

		pre = serialByPre(head);
		System.out.println("serialize tree by pre-order: " + pre);
		head = reconByPreString(pre);
		System.out.print("reconstruct tree by pre-order, ");
		printTree(head);

		level = serialByLevel(head);
		System.out.println("serialize tree by level: " + level);
		head = reconByLevelString(level);
		System.out.print("reconstruct tree by level, ");
		printTree(head);

		System.out.println("====================================");

		head = new Node(100);
		head.left = new Node(21);
		head.left.left = new Node(37);
		head.right = new Node(-42);
		head.right.left = new Node(0);
		head.right.right = new Node(666);
		printTree(head);

		pre = serialByPre(head);
		System.out.println("serialize tree by pre-order: " + pre);
		head = reconByPreString(pre);
		System.out.print("reconstruct tree by pre-order, ");
		printTree(head);

		level = serialByLevel(head);
		System.out.println("serialize tree by level: " + level);
		head = reconByLevelString(level);
		System.out.print("reconstruct tree by level, ");
		printTree(head);

		System.out.println("====================================");

	}
}

四:判断是否是平衡二叉树

4.1:思路讲解

判断一个二叉树是否是平衡二叉树
啥是平衡二叉树?
就是任意一个节点的左子树和右子树的高度差不超过1

拿一个普通的节点来说
我需要我左孩子的高度
我需要我右孩子的高度
然后如果我两个孩子的高度差超过1那就不用判断了,肯定是不平衡的
如果高度差不超过1,找到最高的那一个,加上1(本节点),就是本节点的高度。嘻嘻

看代码把~

4.2:Java代码

package xyz.fudongyang.basic.class_04.my;

public class Code_06_IsBalancedTree {

    public static class TreeNode {
        private int value;
        private TreeNode left;
        private TreeNode right;

        public TreeNode(int value) {
            this.value = value;
        }
    }

    public static class Result{
        private final boolean isBalanced;
        private int level;
        public Result(boolean isBalanced,int level){
            this.isBalanced = isBalanced;
            this.level = level;
        }
    }

    private static boolean isBalancedTree(TreeNode head){
        Result result = isBalancedTree(head, new Result(true,1));
        return result.isBalanced;
    }

    private static Result isBalancedTree(TreeNode head,Result result){
        /**
         * 我的左边是否是平衡二叉树
         * 我的右边是否是平衡二叉树
         * 我左边的层高
         * 我右边的层高
         * 我左右的层高决定我这一层是不是平衡二叉树
         *
         */
        if (head == null){
            result.level = result.level - 1;
            return result;
        }
        Result resultLeft = new Result(result.isBalanced,result.level+1);
        Result resultRight = new Result(result.isBalanced,result.level+1);
        Result lTreeNode = isBalancedTree(head.left,resultLeft);
        if (!lTreeNode.isBalanced){
            return lTreeNode;
        }

        Result rTreeNode = isBalancedTree(head.right,resultRight);
        if (!rTreeNode.isBalanced){
            return rTreeNode;
        }
        if (Math.abs(rTreeNode.level - lTreeNode.level) > 1){
            return new Result(false,Math.max(rTreeNode.level,lTreeNode.level));
        }
        return new Result(true,Math.max(rTreeNode.level,lTreeNode.level));
    }

    public static void main(String[] args) {
        TreeNode treeNode = new TreeNode(1);
//        TreeNode.left = new TreeNode(2);
//        TreeNode.right = new TreeNode(3);
//        TreeNode.left.left = new TreeNode(4);
//        TreeNode.left.right = new TreeNode(5);
//        TreeNode.right.left = new TreeNode(6);
//        TreeNode.right.right = new TreeNode(7);
//        TreeNode.left.left.left = new TreeNode(10);
//        TreeNode.left.right.left = new TreeNode(10);
//        TreeNode.left.right.right = new TreeNode(10);
//        TreeNode.left.right.left.left = new TreeNode(10);
//        TreeNode.left.right.left.right = new TreeNode(10);
        treeNode.right = new TreeNode(2);
        treeNode.right.right = new TreeNode(3);
        System.out.println(isBalancedTree(treeNode));
    }
}

五:是否是搜索二叉树

5.1:思路讲解

什么是搜索二叉树?
就是一个节点,我的左孩子如果存在,只能比我小
我的右孩子存在,只能比我大
如果不满足就不是搜索二叉树

换言之
二叉树的中序遍历必须是升序的

ok,那么我非递归中序遍历二叉树,记录上一个节点的值
我只需要比较当前节点的值,和我前一个节点的值的大小关系就ok了
如果没有前一个节点大,那么我中序遍历就不是升序的
那么我就不是搜索二叉树
直接返回false
如果一直都是升序的,那就是搜索二叉树
嘻嘻看代码吧~

5.2:Java代码

package xyz.fudongyang.basic.class_04.my;

import java.util.Stack;

public class Code_07_IsBSTAndCBT {

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

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

    public static class ResultBST {
        private int max;
        private int min;
        private boolean isBST;

        public ResultBST(int max, int min, boolean isBST) {
            this.min = min;
            this.max = max;
            this.isBST = isBST;
        }
    }

    public static boolean isBSTree(TreeNode TreeNode) {
        /**
         * 左节点的最大值
         * 左树是否是搜索二叉树
         *
         * 右节点的最小值
         * 右树是否是搜索二叉树
         *
         * 整体记录最小值,最大值,是否是搜索二叉树
         * 记录最小值、最大值同时把自己也算上
         *
         */
        return isBST(TreeNode);
    }


    public static boolean isBST(TreeNode treeNode) {
        boolean result = true;
        // 非递归中序遍历二叉树
        if (treeNode == null) {
            return true;
        }
        Stack<TreeNode> stack = new Stack<>();
        Integer pre = null;
        while (!stack.isEmpty() || treeNode != null) {
            if (treeNode != null) {
                stack.push(treeNode);
                treeNode = treeNode.left;
            } else {
                TreeNode pop = stack.pop();
                if (pre == null) {
                    pre = pop.value;
                } else {
                    if (pop.value <= pre) {
                        return false;
                    }
                }
                treeNode = pop.right;
            }
        }
        return true;
    }


    public static void main(String[] args) {
//		TreeNode head = new TreeNode(4);
//		head.left = new TreeNode(2);
//		head.right = new TreeNode(6);
//		head.left.left = new TreeNode(1);
//		head.left.right = new TreeNode(3);
//		head.right.left = new TreeNode(5);


//		TreeNode head1 = new TreeNode(5);
//		head1.left = new TreeNode(1);
//		head1.right = new TreeNode(4);
//		head1.right.left = new TreeNode(3);
//		head1.right.right = new TreeNode(6);
//		System.out.println(isBSTree(head1));
        PreTree.Node head = new PreTree.Node(1);
        head.left = new PreTree.Node(2);
        head.right = new PreTree.Node(3);
        head.left.left = new PreTree.Node(4);
        head.left.right = new PreTree.Node(5);
        head.right.left = new PreTree.Node(6);
        head.right.right = new PreTree.Node(7);
        head.left.left.left = new PreTree.Node(8);

        TreeNode treeNode = new TreeNode(Integer.MAX_VALUE);
        System.out.println(isBSTree(treeNode));
    }
}

六:是否是完全二叉树

6.1:思路讲解

完全二叉树不是满二叉树
完全二叉树就是,如果二叉树的最后一层不是满的,那么除最后一层外,其他层必须是满的
而且,最后一层,之后一个元素必须是它的父亲的左孩子,不能是右孩子。

前提背景:层序遍历二叉树

换言之
如果我有右孩子没有左孩子,不是完全二叉树
如果我有左孩子没有右孩子,那么以后所有的节点都是叶节点
如果我左右孩子都有,那么加入队列,继续层序遍历

看代码吧!

6.2:Java代码

package xyz.fudongyang.basic.class_04.my;

import java.util.LinkedList;
import java.util.Queue;
import java.util.Stack;

public class Code_07_IsBSTAndCBT {

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

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

    public static class ResultBST {
        private int max;
        private int min;
        private boolean isBST;

        public ResultBST(int max, int min, boolean isBST) {
            this.min = min;
            this.max = max;
            this.isBST = isBST;
        }
    }
    


    public static boolean isCBT(TreeNode treeNode) {
        if (treeNode == null) {
            return true;
        }
        /**
         * 前提:层序遍历二叉树
         * 1. 我只有右孩子没有左孩子 直接失败
         * 2. 我有左孩子没有右孩子 则以后层序遍历的所有节点都是叶节点(没有孩子)
         *
         */
        Queue<TreeNode> queue = new LinkedList<>();
        queue.add(treeNode);
        TreeNode leftNode;
        TreeNode rightNode;
        boolean isBegin = false;
        while (!queue.isEmpty()) {
            TreeNode poll = queue.poll();
            leftNode = poll.left;
            rightNode = poll.right;
            if (leftNode == null && rightNode != null || isBegin && leftNode != null) {
                return false;
            }
            if (leftNode != null) {
                queue.add(leftNode);
            }
            if (rightNode != null) {
                queue.add(rightNode);
            }
            if (leftNode != null && rightNode == null) {
                isBegin = true;
            }
        }

        return true;

    }

    public static void main(String[] args) {
//		TreeNode head = new TreeNode(4);
//		head.left = new TreeNode(2);
//		head.right = new TreeNode(6);
//		head.left.left = new TreeNode(1);
//		head.left.right = new TreeNode(3);
//		head.right.left = new TreeNode(5);


//		TreeNode head1 = new TreeNode(5);
//		head1.left = new TreeNode(1);
//		head1.right = new TreeNode(4);
//		head1.right.left = new TreeNode(3);
//		head1.right.right = new TreeNode(6);
//		System.out.println(isBSTree(head1));
        PreTree.Node head = new PreTree.Node(1);
        head.left = new PreTree.Node(2);
        head.right = new PreTree.Node(3);
        head.left.left = new PreTree.Node(4);
        head.left.right = new PreTree.Node(5);
        head.right.left = new PreTree.Node(6);
        head.right.right = new PreTree.Node(7);
        head.left.left.left = new PreTree.Node(8);

        TreeNode treeNode = new TreeNode(Integer.MAX_VALUE);
        System.out.println(isCBT(treeNode));
    }
}

七:完全二叉树的节点个数

7.1:思路讲解

已知我是一个完全二叉树

那么求节点个数

拿一个普通节点来说
如果我的右子树已经到达最后一层了那么我的左子树就是满二叉树
如果我的右子树没有到最后一层,那么我的右子树肯定是整棵树的高度减一的满二叉树
然后我让我的左孩子就当作这个普通节点,递归过程!

看代码吧

7.2:Java代码

package xyz.fudongyang.basic.class_04.my;

public class Code_08_CompleteTreeNodeNumber {

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

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

    public static int nodeNum(Node node) {
        if (node == null) {
            return 0;
        }
        return dfs(node, 1,getLeftLevel(node,1));
    }

    public static int dfs(Node node, int level, int high) {
        /**
         * 如果是叶节点就返回
         * 如果右孩子到达最大高度,则说明左孩子是满二叉树
         * 如果右孩子未到最大高度,则说明右孩子是比高度少一层的满二叉树
         */
        if (level == high) {
            return 1;
        }
        if (getLeftLevel(node.right,level+1) == high){
            return (1 << (high - level)) + dfs(node.right,level+1,high);
        }else {
            return (1 << (high - level -1)) + dfs(node.left,level+1,high);
        }

    }

    public static int getLeftLevel(Node node, int level) {
        while (node != null) {
            level++;
            node = node.left;
        }
        return level - 1;
    }

    public static void main(String[] args) {
        Node head = new Node(1);
        head.left = new Node(2);
        head.right = new Node(3);
        head.left.left = new Node(4);
        head.left.right = new Node(5);
        head.right.left = new Node(6);
        System.out.println(nodeNum(head));

    }

}
  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
### 回答1: 算法6-1:二叉链表存储的二叉树的结构定义 二叉链表存储的二叉树是一种常见的二叉树存储方式,其结构定义如下: typedef struct BiTNode{ TElemType data; // 数据域 struct BiTNode *lchild, *rchild; // 左右孩子指针 }BiTNode, *BiTree; 其中,TElemType为二叉树节点的数据类型,可以根据实际情况行定义。 算法6-2:二叉链表存储的二叉树的创建 二叉链表存储的二叉树的创建可以通过递归方式实现,具体算法如下: void CreateBiTree(BiTree *T){ TElemType ch; scanf("%c", &ch); // 输入节点的值 if(ch == '#'){ // 如果输入的是#,表示该节点为空 *T = NULL; }else{ *T = (BiTree)malloc(sizeof(BiTNode)); // 创建新节点 (*T)->data = ch; // 节点赋值 CreateBiTree(&((*T)->lchild)); // 递归创建左子树 CreateBiTree(&((*T)->rchild)); // 递归创建右子树 } } 其中,#表示空节点,输入#时,该节点为空。 算法6-3:二叉链表存储的二叉树的遍历 二叉链表存储的二叉树的遍历可以通过递归方式实现,具体算法如下: void PreOrderTraverse(BiTree T){ // 先序遍历 if(T != NULL){ printf("%c ", T->data); // 访问根节点 PreOrderTraverse(T->lchild); // 遍历左子树 PreOrderTraverse(T->rchild); // 遍历右子树 } } void InOrderTraverse(BiTree T){ // 中序遍历 if(T != NULL){ InOrderTraverse(T->lchild); // 遍历左子树 printf("%c ", T->data); // 访问根节点 InOrderTraverse(T->rchild); // 遍历右子树 } } void PostOrderTraverse(BiTree T){ // 后序遍历 if(T != NULL){ PostOrderTraverse(T->lchild); // 遍历左子树 PostOrderTraverse(T->rchild); // 遍历右子树 printf("%c ", T->data); // 访问根节点 } } 其中,先序遍历是先访问根节点,再遍历左子树和右子树;中序遍历是先遍历左子树,再访问根节点和右子树;后序遍历是先遍历左子树和右子树,再访问根节点。 算法6-4:二叉链表存储的二叉树的销毁 二叉链表存储的二叉树的销毁可以通过递归方式实现,具体算法如下: void DestroyBiTree(BiTree *T){ if(*T != NULL){ DestroyBiTree(&((*T)->lchild)); // 销毁左子树 DestroyBiTree(&((*T)->rchild)); // 销毁右子树 free(*T); // 释放节点空间 *T = NULL; // 节点指针置空 } } 其中,递归销毁左子树和右子树,最后释放节点空间并将节点指针置空。 ### 回答2: 二叉链表存储的二叉树是一种常见的二叉树存储结构,它是由一个节点数组和一个指向根节点的指针组成的。每个节点都包含一个值、一个左孩子指针和一个右孩子指针。这种存储结构可以非常方便地二叉树的遍历和修改操作,是二叉树基本操作的重要实现方式。 算法6-1是建立二叉链表存储结构的算法,它通过前序遍历和中序遍历来构造一棵二叉树。具体而言,算法6-1会先遍历前序序列找到根节点,并在中序序列中找到根节点的位置,然后递归地建立左子树和右子树。该算法时间复杂度为O(n^2),其中n为二叉树的节点数。算法6-1的缺点是在处理大规模的二叉树时效率较低。 算法6-2是先序遍历的递归算法,它通过递归实现先序遍历。具体而言,先访问根节点,然后递归访问左子树和右子树。该算法时间复杂度为O(n),其中n为二叉树的节点数。 算法6-3是中序遍历的递归算法,它通过递归实现中序遍历。具体而言,先递归访问左子树,然后访问根节点,最后递归访问右子树。该算法的时间复杂度为O(n),其中n为二叉树的节点数。 算法6-4是后序遍历的递归算法,它通过递归实现后序遍历。具体而言,先递归访问左子树和右子树,最后访问根节点。该算法的时间复杂度为O(n),其中n为二叉树的节点数。 总之,二叉链表存储的二叉树是一种非常方便实用的数据结构,可以方便地行各种遍历和修改操作。同时,基于递归实现的三种遍历算法也非常简洁高效,应用广泛。 ### 回答3: 算法6-1至6-4描述了二叉链表存储的二叉树。二叉链表存储的二叉树是一种基于线性链式结构存储的二叉树,它通过指针关系将每个结点的左右子树联系起来。下面我们将分别对每个算法行详细解释。 算法6-1:二叉链表存储结构定义。该算法定义了二叉树的结构,主要是通过指针关系分别指向左右子树和父节点。这样的结构便于对二叉树的操作和遍历。 算法6-2:二叉链表存储的建立。该算法通过输入有序序列,依次插入二叉树结点,先从根结点开始比较大小,插入到左右子树中。当插入到空节点时,创建新的结点,通过指针关系连接起来。递归地行插入操作,直到序列中的所有元素插入完毕。 算法6-3:二叉链表存储的遍历。该算法通过对二叉树的先序、中序和后序遍历行递归实现。先序遍历需要先访问根节点,然后再对左右子树行遍历;中序遍历需要先访问左子树,再访问根节点,最后再访问右子树;后序遍历需要先访问左右子树,最后访问根节点。 算法6-4:二叉链表的基本操作。该算法主要包括插入、删除、查找和修改等操作。其中,插入和删除操作需要先定位到相应的结点,然后通过指针关系行连接或删除。查找操作需要按照二叉树的规律行查找,找到目标结点后返回其对应的指针。修改操作类似于删除操作,先找到需要修改的结点,然后行相应的修改操作。 综上所述,二叉链表存储的二叉树是一种便于操作和遍历的数据结构,它通过指针关系将每个结点的左右子树联系起来。该结构的建立、遍历和操作都可以通过递归实现,不仅提高了程序的可读性,还方便了程序员的开发。

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值