算法笔记:二叉树,红黑树

目录

 

《树》知识点:

二叉查找,搜索,排序树BST:

平衡二叉树:AVL树:

平衡二叉树的目的:

平衡二叉树的常用方法:

红黑树:RB Tree

红黑树性质:

旋转和颜色变化的规律:

红黑树和平衡二叉树的比较:

二叉树题:

题目一:二叉树的前中后序遍历:

题目二:如何直观的打印一颗二叉树

 题目三:在二叉树中找到一个节点的后继节点

题目四:介绍二叉树的序列化和反序列化

题目六:判断一棵二叉树是否是平衡二叉

题目七:判断一棵树是否是搜索二叉树、判断一棵树是否是完全二叉树

题目八:已知一棵完全二叉树,求其节点的个数


《树》知识点:

二叉查找,搜索,排序树BST:

1.空树

2.或具有以下性质的二叉树:

(1)左子树不空的话,左子树上所有结点值均小于它的根结点值

(2)右子树结点值均大于它的根结点

(3)它的左右子书也都是二叉树

对二叉树进行中序排列,得到的结果是一个升序集合。

平衡二叉树:AVL树:

1.空树

2.左右子树高度差(平衡因子)的绝对值不超过1

3.左右子树都是平衡二叉树

4.平衡二叉树一定是二叉搜索树,但二叉搜索树不一定是平衡二叉树,区别在于平衡二叉树拥有二叉搜索树的所有性质之外加了一条平衡因子不超过1 的性质,可以说是平衡二叉树是左右子树高度差不超过1的二叉搜索树。

5.插入,查找,删除的时间复杂度最好情况和最坏情况都维持在O(logN)

平衡二叉树的目的:

减少二叉查找树的高度,提高查找速度

平衡二叉树的常用方法:

AVL算法,红黑树,替罪羊树,Treap,伸展树

红黑树:RB Tree

红黑树本身是一种平衡二叉树,每个节点都带有颜色(红色或者黑色)

红黑树性质:

1.每个节点都带有颜色,黑色或者红色

2.根结点是黑色

3.每个叶子节点(NIL)是黑色的空节点

4.如果一个节点是红色,那么它的叶子节点必须是黑色,每个叶子节点道根的所有路径不能出现两个红色节点的情况

5.从任意一个节点到其每个叶子的所有路径都包含形同数量的黑色节点

这些性质约束体现了:红黑树从根到叶子节点的任何一条路径不能比其他的路径长出两倍

旋转和颜色变化的规律:

1.添加的节点为红色

2.变色的情况:当前节点的父亲是红色,叔结点也是红色

(1)父节点--》黑色

(2)叔节点--》黑色

(3)祖父节点--》红色

(4)当前指针定义到祖父节点,设置为当前待操作

3.左旋:当前节点的父节点是红色,叔节点是黑色,且当前节点是右子树

以父节点作为左旋

4.右旋:当前节点的父节点是红色,叔节点是黑色,且当前节点是左子树

(1)父节点--》黑色

(2)祖父节点--》红色

(3)以祖父节点右旋

红黑树和平衡二叉树的比较:

此处转载:https://www.cnblogs.com/cuiqq/p/13280191.html

RB-Tree和AVL树作为BBST,其实现的算法时间复杂度相同,AVL作为最先提出的BBST,貌似RB-tree实现的功能都可以用AVL树是代替,那么为什么还需要引入RB-Tree呢?

  1. 红黑树不追求"完全平衡",即不像AVL那样要求节点的 |balFact| <= 1,它只要求部分达到平衡,但是提出了为节点增加颜色,红黑是用非严格的平衡来换取增删节点时候旋转次数的降低,任何不平衡都会在三次旋转之内解决,而AVL是严格平衡树,因此在增加或者删除节点的时候,根据不同情况,旋转的次数比红黑树要多。
  2. 就插入节点导致树失衡的情况,AVL和RB-Tree都是最多两次树旋转来实现复衡rebalance,旋转的量级是O(1)
    删除节点导致失衡,AVL需要维护从被删除节点到根节点root这条路径上所有节点的平衡,旋转的量级为O(logN),而RB-Tree最多只需要旋转3次实现复衡,只需O(1),所以说RB-Tree删除节点的rebalance的效率更高,开销更小!
  3. AVL的结构相较于RB-Tree更为平衡,插入和删除引起失衡,如2所述,RB-Tree复衡效率更高;当然,由于AVL高度平衡,因此AVL的Search效率更高啦。
  4. 针对插入和删除节点导致失衡后的rebalance操作,红黑树能够提供一个比较"便宜"的解决方案,降低开销,是对search,insert ,以及delete效率的折衷,总体来说,RB-Tree的统计性能高于AVL.
  5. 故引入RB-Tree是功能、性能、空间开销的折中结果。
    5.1 AVL更平衡,结构上更加直观,时间效能针对读取而言更高;维护稍慢,空间开销较大。
    5.2 红黑树,读取略逊于AVL,维护强于AVL,空间开销与AVL类似,内容极多时略优于AVL,维护优于AVL。
    基本上主要的几种平衡树看来,红黑树有着良好的稳定性和完整的功能,性能表现也很不错,综合实力强,在诸如STL的场景中需要稳定表现。
  6. 红黑树的查询性能略微逊色于AVL树,因为其比AVL树会稍微不平衡最多一层,也就是说红黑树的查询性能只比相同内容的AVL树最多多一次比较,但是,红黑树在插入和删除上优于AVL树,AVL树每次插入删除会进行大量的平衡度计算,而红黑树为了维持红黑性质所做的红黑变换和旋转的开销,相较于AVL树为了维持平衡的开销要小得多
  7. 总结:实际应用中,若搜索的次数远远大于插入和删除,那么选择AVL,如果搜索,插入删除次数几乎差不多,应该选择RB
  8. 再总结: 

    1、红黑树放弃了追求完全平衡,追求大致平衡,在与平衡二叉树的时间复杂度相差不大的情况下,保证每次插入最多只需要三次旋转就能达到平衡,实现起来也更为简单。

    2、平衡二叉树追求绝对平衡,条件比较苛刻,实现起来比较麻烦,每次插入新节点之后需要旋转的次数不能预知。

二叉树题:

题目一:二叉树的前中后序遍历:

以上是节点的访问顺序:每个节点回来到三次

1.前序遍历:节点第一次出现的时候打印;前-左-右

2.中序遍历:节点第二次出现的时候打印;左-前-右

3.后序遍历:节点第三次出现的时候打印;左-右-前

代码:(递归方法+非递归方法):

package zuoshen4;

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;
        }
        inOrderRecur(head.left);
        System.out.print(head.value);
        inOrderRecur(head.right);
    }
    public static void posOrderRecur(Node head){
        if(head==null){
            return;
        }
        posOrderRecur(head.left);
        posOrderRecur(head.right);
        System.out.print(head.value);
    }
    //非递归前序遍历:先把头放进去,然后pop出头,打印头,然后压入右,再压入左
    public static void preOrderUnRecur(Node head){
        System.out.println("preOrderUnRecur:");
        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();
    }
    //非递归中序遍历:先头进去,判断如果栈不是空的或者head不是空的,就判断head是不是空,如果不是空的,压入,之后head往左;
    //如果head是空的,弹出一个打印,之后head往右
    public static void inOrderUnRecur(Node head){
        System.out.println("inOrderUnRecur:");
        if(head !=null){
            Stack<Node>stack=new Stack<Node>();
            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();
    }
    //非递归后序遍历:需要两个栈,在第一个栈里,放入顺序为中右左,然后导入到第二个栈里,出来就变成左右中了。
    public static void posOrderUnRecur1(Node head){
        System.out.println("posOrderUnRecur:");
        if(head!=null){
            Stack<Node>stack1=new Stack<Node>();
            Stack<Node>stack2=new Stack<Node>();
            stack1.add(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+" ");
            }
        }
        System.out.println();
    }
    public static void posOrderUnRecur2(Node h) {
        System.out.print("pos-order: ");
        if (h != null) {
            Stack<Node> stack = new Stack<Node>();
            stack.push(h);
            Node c = null;
            while (!stack.isEmpty()) {
                c = stack.peek();
                if (c.left != null && h != c.left && h != c.right) {
                    stack.push(c.left);
                } else if (c.right != null && h != c.right) {
                    stack.push(c.right);
                } else {
                    System.out.print(stack.pop().value + " ");
                    h = c;
                }
            }
        }
        System.out.println();
    }
    public static void main(String[] args) {
        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);

    }

}

题目二:如何直观的打印一颗二叉树

package zuoshen4;

public class Code_02_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);

    }

}

 题目三:在二叉树中找到一个节点的后继节点

【题目】 现在有一种新的二叉树节点类型如下:

public 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的后继节点。

分析:

如果n节点有右子树,那么它的后继节点就是他的右子树的最左边的节点,

如果n节点没有右子数,那就往上找他的parent,一直到当前节点是它父节点的左孩子为止,就是n节点的后继节点

package zuoshen4;

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 node;
        }
        if(node.right!=null){
            return getLeftMost(node.right);
        }else {
            Node parent=node.parent;
            while(node.parent!=null&&parent.left!=node){
                node=parent;
                parent=node.parent;
            }
            return parent;
        }
    }

    private static Node getLeftMost(Node node) {
        if(node==null){
            return node;
        }
        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));
    }
}

题目四:介绍二叉树的序列化和反序列化

序列化:就是将一棵树存储到字符串结构中,每个值存储之后加一个‘——’,无左右子树的情况下加‘#’,为了便于反序列化

反序列化:将存储起来的树还原;怎么序列化的,就怎么反序列化

package zuoshen4;

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

/**
 * 这里简单对其重复的方法做点简单的区分。
 * offer,add区别:
 * 一些队列有大小限制,因此如果想在一个满的队列中加入一个新项,多出的项就会被拒绝。
 * 这时新的 offer 方法就可以起作用了。它不是对调用 add() 方法抛出一个 unchecked 异常,而只是得到由 offer() 返回的 false。
 *
 * poll,remove区别:
 * remove() 和 poll() 方法都是从队列中删除第一个元素。remove() 的行为与 Collection 接口的版本相似,
 * 但是新的 poll() 方法在用空集合调用时不是抛出异常,只是返回 null。因此新的方法更适合容易出现异常条件的情况。
 *
 * peek,element区别:
 * element() 和 peek() 用于在队列的头部查询元素。与 remove() 方法类似,在队列为空时, element() 抛出一个异常,而 peek() 返回 null
 */

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) {
        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<String>();
        for (int i = 0; i != values.length; i++) {
            queue.offer(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;
    }

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

    public static Node reconByLevelString(String levelStr) {
        String[] values = levelStr.split("!");
        int index = 0;
        Node head = generateNodeByString(values[index++]);
        Queue<Node> queue = new LinkedList<Node>();
        if (head != null) {
            queue.offer(head);
        }
        Node node = null;
        while (!queue.isEmpty()) {
            node = queue.poll();
            node.left = generateNodeByString(values[index++]);
            node.right = generateNodeByString(values[index++]);
            if (node.left != null) {
                queue.offer(node.left);
            }
            if (node.right != null) {
                queue.offer(node.right);
            }
        }
        return head;
    }

    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("====================================");

    }
}

题目五:折纸问题

【题目】 请把一段纸条竖着放在桌子上,然后从纸条的下边向上方对折1次,压出折痕后展开。此时折痕是凹下去的,即折痕突起的方向指向纸条的背面。如果从纸条的下边向上方连续对折 2 次,压出折痕后展开,此时有三条折痕,从上到下依次是下折 痕、下折痕和上折痕。 给定一 个输入参数N,代表纸条都从下边向上方连续对折N次, 请从上到下打印所有折痕的方向。 例如:N=1时,打印: down N=2时,打印: down down up 

package zuoshen4;

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

    private static void printProcess(int i, int n, boolean down) {//i:对折第i次产生的折痕;n:折纸次数
        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=4;
        printAllFolds(N);
    }
}

题目六:判断一棵二叉树是否是平衡二叉

1.左子树是否平衡

2.右子树是否平衡‘

3.左子树高度

4.右子树高度

package zuoshen4;

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

    public static boolean isBalance(Node head){
        boolean[]res=new boolean[1];
        res[0]=true;
        getheight(head,1,res);
        return res[0];
    }

    private static int getheight(Node head, int level, boolean[] res) {
        if(head==null){
            return level;
        }
        int lH=getheight(head.left,level+1,res);
        if(!res[0]){
            return level;
        }
        int rH=getheight(head.right,level+1,res);
            if(!res[0]){
                return level;
            }
        if(Math.abs(lH-rH)>1){
            res[0]=false;
        }
        return Math.max(lH,rH);
    }
    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);
        head.right.right = new Node(7);

        System.out.println(isBalance(head));

    }
}

题目七:判断一棵树是否是搜索二叉树、判断一棵树是否是完全二叉树

搜索二叉树:二叉树中序遍历结果依次是升序的

完全二叉树:与值没有关系,是结构。二叉树按层遍历,必须从左往右按层放满:

                                                   1.若有右孩子没有左孩子,则false,

                                                   2.若不是左右孩子双全,后面遇到的所有节点都必须是叶子节点

两种情况:1.只有右,没有左,--》false

                  2.当第一次发现一个节点不是左右两个孩子双全的情况,后边的所有节点必须是叶子节点

package zuoshen4;

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

public class Code_07_IsBSTAndCBT {
    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) {
//        System.out.println("inOrderUnRecur:");
//        int pre=Integer.MIN_VALUE;//中序遍历的基础上加一个
//        if(head !=null){
//            Stack<Code_01_PreInPosTraversal.Node> stack=new Stack<Code_01_PreInPosTraversal.Node>();
//            while(!stack.isEmpty()||head!=null){
//                if(head!=null){
//                    stack.push(head);
//                    head=head.left;
//                }else {
//                    head=stack.pop();
//                    System.out.print(head.value+" ");//这行改成比较,之后再加一个return
//                    head=head.right;
//                }
//            }
//        }
//        System.out.println();
//    }
public static boolean isBST(Node head) {//是否是搜索二叉树,要求中序遍历结果是升序
    if (head == null) {
        return true;
    }
    boolean res = true;
    Node pre = null;
    Node cur1 = head;
    Node cur2 = null;
    while (cur1 != null) {
        cur2 = cur1.left;//左树
        if (cur2 != null) {
            while (cur2.right != null && cur2.right != cur1) {
                cur2 = cur2.right;
            }
            if (cur2.right == null) {
                cur2.right = cur1;
                cur1 = cur1.left;
                continue;
            } else {
                cur2.right = null;
            }
        }
        if (pre != null && pre.value > cur1.value) {
            res = false;
        }
        pre = cur1;
        cur1 = cur1.right;//右树
    }
    return res;
}
    public static boolean isCBT(Node head){//是否是完全二叉树
        if(head==null){
            return true;
        }
        Queue<Node>queue=new LinkedList<Node>();
        boolean leaf=false;
        Node l=null;
        Node r=null;
        queue.add(head);
        if(queue!=null){
            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;
    }
    // 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 = new Node(4);
        head.left = new Node(2);
        head.right = new Node(6);
        head.left.left = new Node(1);
        head.left.right = new Node(3);
        head.right.left = new Node(5);

        printTree(head);
        System.out.println(isBST(head));
        System.out.println(isCBT(head));

    }
}

题目八:已知一棵完全二叉树,求其节点的个数

要求:时间复杂度低于O(N),N为这棵树的节点个

利用一个结论来加速这道题:一棵高度为L的满二叉树,它的节点个数是2^L-1

1.先看一棵树的左边界,来确定树的高度H

2.然后看右子树的左边界是不是满的,若是满的,那么树的左子树是满的,将右子树递归判断,子问题和母问题等效

3.若右子数的左边界没到最后一层,那么右子数一定是满二叉树,只是高度为H1,递归左子树

总结:左子树左边界看高度--》右子树左边界看是否到最后一层--》到了?左子树满二叉树,递归右子树:右子树满二叉树,高度改变,递归左子树

复杂度:o(logN)^2
package zuoshen4;

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 head){//总函数
        if(head==null){//头节点是空,就是0
            return 0;
        }
        return bs(head,1,mostLeftLevel(head,1));
    }

    private static int bs(Node node, int l, int h) {//node:当前节点;l:level,到了第几层;h:当前树的高度
        if(l==h){//若递归到了最后一层,子节点,返回节点数为1
            return 1;
        }
        if(mostLeftLevel(node.right,l+1)==h){//判断右子树最左边界的函数,返回值为最左边界到了第几层,判断等不等于h
            return (1<<(h-l))+bs(node.right,l+1,h);//1 << (h - l)为2^(h-1),右子树左边界到了最后一层,返回左子树高度+右子树递归
        }else {
            return (1<<(h-l-1))+bs(node.left,l+1,h);//1 << (h - l-1)为2^(h-1),右子树比左子树少一个节点,右子树左边界到了最后一层,返回左子树高度+右子树递归
        }
    }

    private static int mostLeftLevel(Node head, int level) {//判断右子树左边界
        while(head!=null){
            level++;
            head=head.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));
    }
}

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值