目录

《树》知识点:

二叉查找,搜索,排序树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);// recursiveSystem.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();// unrecursiveSystem.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 nullSystem.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 treepublic 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 treepublic 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){//头节点是空,就是0return 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){//若递归到了最后一层,子节点,返回节点数为1return 1;}if(mostLeftLevel(node.right,l+1)==h){//判断右子树最左边界的函数,返回值为最左边界到了第几层,判断等不等于hreturn (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));}
}

算法笔记:二叉树,红黑树相关推荐

  1. 【数据结构和算法05】 红-黑树(转发)

    2019独角兽企业重金招聘Python工程师标准>>> [数据结构和算法05] 红-黑树(看完包懂~) 置顶 2016年04月13日 15:50:25 eson_15 阅读数:526 ...

  2. B-Tree/B+-Tree/二叉树/红黑树/Hash表/MySQL底层到底用哪个数据表建立索引做快速查找?

    B-Tree/B+-Tree/二叉树/红黑树/Hash表/MySQL底层到底用哪个数据表建立索引做快速查找? ~~B-Tree~~ ==B+Tree== ~~二叉树(Binary Search Tre ...

  3. 算法导论 之 红黑树 - 添加[C语言]

    作者:邹奇峰 邮箱:Qifeng.zou.job@hotmail.com 博客:http://blog.csdn.net/qifengzou 日期:2013.12.24 21:00 转载请注明来自&q ...

  4. 《算法导论》红黑树详解(一):概念

    在学习红黑树之前,读者应先掌握二叉查找树的相关知识.学习红黑树或者二叉查找树,推荐大家看<算法导论>.<算法导论>原书第3版 高清PDF 带详细书签目录下载 密码:acis & ...

  5. 算法-查找(红黑树)

    查找 符号表 最主要的目的是将一个键和一个值联系起来.用例能够将一个键值对插入符号表并希望在之后能够从符号表的所有键值对中按照键直接找到对应的值,即以键值对为单元的数据结构. 无序链表顺序查找 性能: ...

  6. 算法手札二:红黑树的插入原理,原理与实现篇

    红黑树的五大性质(性质四与性质五特别重要) 1. 节点必须是红色或者是黑色 2. 根节点是黑色的 3. 所有的叶子节点是黑色的. 4. 每个红色节点的两个子节点是黑色的,也就是不能存在父子两个节点全是 ...

  7. java 二叉树 红黑树_常见数据结构(二)-树(二叉树,红黑树,B树)

    常见数据结构(二)-树(二叉树,红黑树,B树) 标签: algorithms [TOC] 本文介绍数据结构中几种常见的树:二分查找树,2-3树,红黑树,B树 写在前面 本文所有图片均截图自course ...

  8. 算法导论之红黑树的学习

    最近学习了二叉搜索树中的红黑树,感觉收获颇丰,在此写一篇文章小结一下学到的知识,顺便手写一下Java代码. 1.引言 先来讲讲什么是二叉搜索树,二叉搜索树有如下特点:他是以一颗二叉树(最多有两个子结点 ...

  9. 数据结构算法学习 之 红黑树

    1.红黑树的特性 (1)每个节点或者是黑色,或者是红色. (2)根节点是黑色. (3)每个叶子节点(NIL)是黑色. [注意:这里叶子节点,是指为空(NIL或NULL)的叶子节点!] (4)如果一个节 ...

  10. 二叉树 红黑树 B树 B+树的优缺点

    前言 在MySQL中,无论是Innodb还是MyIsam,都使用了B+树作索引结构(这里不考虑hash等其他索引).本文将从最普通的二叉查找树开始,逐步说明各种树解决的问题以及面临的新问题,从而说明M ...

最新文章

  1. cmder里ls、pwd、自定义的alias等一系列命令都无法使用
  2. c++ 回调函数_Java中的回调机制,这篇给你整的明明白白的
  3. python ConfigParser 小试
  4. java中string的方法_java中String的常用方法
  5. Okhttp3用法案例:查询小车余额
  6. SpringSecurity系列(四) Spring Security 实现权限树形菜单
  7. python中str如何使用_python中str函数的使用方法
  8. Java八大算法:归并排序
  9. 数据结构自学笔记(郝斌)
  10. oracle数据库三大日志,Oracle 数据库日志和用户日志位置
  11. 面试官:如何查看/etc目录下包含abc字符串的文件?
  12. Linux Wps 缺少字体
  13. 字节云数据库未来方向的探索与实践
  14. D - Sleepy Game
  15. 计蒜客 联想专卖店大促销
  16. 安全性设计之-ip白名单设计
  17. js判断是否是数字——isNaN()函数
  18. NBIOT模块连接巴法云实践(SIM7020)
  19. 桌面背单词,单词图片做背景
  20. 你需要知道的那些go语言json技巧

热门文章

  1. 公司注册流程需要哪些步骤
  2. obd 与服务器 通讯协议,经典   OBD-2是什么及接口针脚定义和通信协议
  3. 洛克希德马丁可安装在卡车的小型核聚变反应堆10年内诞生
  4. 【python】pymysql
  5. 游戏角色模型怎么做?3D建模小白学习从什么软件开始?
  6. 硬件学习(一)电容作用
  7. php 7.0 nts,PHP最新版本7.0.1-nts-Win32-VC14-x86
  8. python 默认参数后接可变参数_Python可变参数会自动填充前面的默认同名参数实例...
  9. 大一上學期學習生活情況總結
  10. 如何低成本挖掘App商店的免费资源