- 实现二叉树的先序、中序、后序遍历,包括递归方式和非递归方式
import java.util.Stack;
public class BinaryTree {
public static class Tree{
public int val;
public Tree left;
public Tree right;
public Tree(int x){
this.val = x;
}
}
public static void xianxu(Tree root) {
//递归的方式
if(root == null)
return;
System.out.println(root.val);
xianxu(root.left);
xianxu(root.right);
}
public static void xianxu1(Tree root) {
//先序,非递归的方式
if(root == null)
return;
Stack<Tree> st = new Stack<>();
st.push(root);
while(!st.isEmpty()) {
root = st.pop();
System.out.println(root.val);
if(root.right != null) {
st.push(root.right);
}
if(root.left != null){
st.push(root.left);
}
}
}
public static void zhongxu(Tree root) {
if(root == null)
return;
zhongxu(root.left);
System.out.println(root.val);
zhongxu(root.right);
}
public static void zhongxu1(Tree root) {
//使用非递归的方式实现
Stack<Tree> st = new Stack<>();
while(!st.isEmpty() || root != null) {
if(root != null) {
st.push(root);
root = root.left;
}else {
root = st.pop();
System.out.println(root.val);
root = root.right;
}
}
}
public static void houxu(Tree root) {
if(root == null)
return;
houxu(root.left);
houxu(root.right);
System.out.println(root.val);
}
public static void houxu1(Tree root) {
if(root == null)
return;
//根右左 倒序 左右根
Stack<Tree> s1 = new Stack<>();
Stack<Tree> s2 = new Stack<>();
s1.push(root);
while(!s1.isEmpty()) {
root = s1.pop();
s2.push(root);
if(root.left != null) {
s1.push(root.left);
}
if(root.right != null) {
s1.push(root.right);
}
}
while(!s2.isEmpty()) {
System.out.println(s2.pop().val);
}
}
public static void main(String[] args) {
Tree head = new Tree(5);
head.left = new Tree(3);
head.right = new Tree(8);
head.left.left = new Tree(2);
head.left.right = new Tree(4);
head.left.left.left = new Tree(1);
head.right.left = new Tree(7);
head.right.left.left = new Tree(6);
head.right.right = new Tree(10);
head.right.right.left = new Tree(9);
head.right.right.right = new Tree(11);
// recursive
System.out.println("==============recursive==============");
System.out.print("pre-order: ");
xianxu(head);
System.out.println();
System.out.print("in-order: ");
zhongxu(head);
System.out.println();
System.out.print("pos-order: ");
houxu(head);
System.out.println();
// unrecursive
System.out.println("============unrecursive=============");
xianxu1(head);
zhongxu1(head);
houxu1(head);
//posOrderUnRecur2(head);
}
}
/*
public class TreeLinkNode {
int val;
TreeLinkNode left = null;
TreeLinkNode right = null;
TreeLinkNode next = null;
TreeLinkNode(int val) {
this.val = val;
}
}
*/
public class Solution {
public TreeLinkNode GetNext(TreeLinkNode pNode)
{
if(pNode.right != null){
pNode = pNode.right;
while(pNode.left != null){
pNode = pNode.left;
}
return pNode;
}else{
TreeLinkNode x = pNode.next;
while(x != null){
if(x.left == pNode)
return x;
pNode = x;
x = pNode.next;
}
return null;
}
}
}
这里使用了先序遍历的序列化和反序列化(递归),以及宽度优先遍历的序列化和反序列化(非递归)。递归二叉树能够回到一个二叉树的结点三次。
//package class_04;
import java.util.LinkedList;
import java.util.Queue;
public class TreeSerialization {
public static class Node {
public int value;
public Node left;
public Node right;
public Node(int data) {
this.value = data;
}
}
public static String serialByLevel(Node head) {
//用递归不能做出来,被递归的思路限制了,看了代码才知道是用非递归方法
if(head == null)
return "#!";
Queue<Node> qq = new LinkedList<>();
qq.add(head);
String res = head.value + "!";
while(!qq.isEmpty()) {
head = qq.poll();
if(head.left != null) {
qq.add(head.left);
res = res + head.left.value + "!";
}else {
res += "#!";
}
if(head.right != null) {
qq.add(head.right);
res = res + head.right.value + "!";
}else {
res += "#!";
}
}
return res;
}
public static String serialByPre(Node head) {
//先序遍历
if(head == null){
return "#!";
}
String res = head.value + "!";
res = res + serialByPre(head.left);
res = res + serialByPre(head.right);
return res;
}
public static int id = 0;
public static Node reconByPreString(String preStr) {
id = 0;
String[] strarray = preStr.split("!");
Node root = new Node(0);
return Deserialize(root,strarray);
}
public static Node Deserialize(Node root,String[] astr){
if(id < astr.length){
if(astr[id].equals("#")){
id++;
return null;
}else{
root = new Node(Integer.valueOf(astr[id++]));
root.left = Deserialize(root.left,astr);
root.right = Deserialize(root.right,astr);
return root;
}
}
return null;
}
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 Node reconByLevelString(String levelStr) {
//非递归方式
String[] stra = levelStr.split("!");
if(stra[0].equals("#"))
return null;
Node head = new Node(Integer.valueOf(stra[0]));
Node head1 = head;
Queue<Node> qq = new LinkedList<>();
qq.add(head);
for(int i = 1;i < stra.length;i = i + 2) {
head = qq.poll();
if(!stra[i].equals("#")) {
head.left = new Node(Integer.valueOf(stra[i]));
qq.add(head.left);
}
if(!stra[i+1].equals("#")) {
head.right = new Node(Integer.valueOf(stra[i+1]));
qq.add(head.right);
}
}
return head1;
}
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("serialByPre 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("serialByPre 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("serialByPre tree by pre-order: " + pre);
head = reconByPreString(pre);
System.out.print("reconstruct tree by pre-order, ");
printTree(head);
level = serialByLevel(head);
System.out.println("serialByPre 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("serialByPre tree by pre-order: " + pre);
head = reconByPreString(pre);
System.out.print("reconstruct tree by pre-order, ");
printTree(head);
level = serialByLevel(head);
System.out.println("serialByPre 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("serialByPre tree by pre-order: " + pre);
head = reconByPreString(pre);
System.out.print("reconstruct tree by pre-order, ");
printTree(head);
level = serialByLevel(head);
System.out.println("serialByPre tree by level: " + level);
head = reconByLevelString(level);
System.out.print("reconstruct tree by level, ");
printTree(head);
System.out.println("====================================");
}
}
**平衡二叉树:对于这棵树的任意节点来说左子树和右子树的高度差超过1。**平衡二叉树不是一颗满二叉树。红黑树在面试中不会让你手写,只会让你说它的概念以及和其他平衡树的区别。
思路:就是任意节点的左子树和右子树的高度之差不大于1.
1.左子树是否平衡,并返回左子树的高度
2.右子树是否平衡,并返回右子树的高度
3.左子树和右子树的高度之差是否大于1
public class BalancedTree {
//左神b站 P5
//判断一颗树是否为平衡二叉树
public static class TreeNode{
public int val;
public TreeNode left;
public TreeNode right;
public TreeNode(int x){
this.val = x;
}
}
public static class booint{
public boolean is;
public int high;
public booint(boolean t,int h) {
this.is = t;
this.high = h;
}
}
public static boolean balancetree(TreeNode root) {
if(root == null)
return true;
return btree(root).is;
}
//如果需要一个函数返回不同类型的数据 ,像这道题中的boolean,和int,不如创建一个对象。
public static booint btree(TreeNode root) {
if(root == null) {
return new booint(true,0);
}
booint left = btree(root.left);
if(!left.is)
return new booint(false,0);
booint right = btree(root.right);
if(!right.is)
return new booint(false,0);
if(Math.abs(left.high - right.high) <= 1)
return new booint(true,Math.max(left.high, right.high) + 1);
else
return new booint(false,0);
}
public static void main(String[] args) {
TreeNode head = new TreeNode(1);
//head.left = new TreeNode(2);
head.right = new TreeNode(3);
//head.left.left = new TreeNode(4);
//head.left.right = new TreeNode(5);
head.right.left = new TreeNode(6);
head.right.right = new TreeNode(7);
System.out.println(balancetree(head));
}
}
题目
判断一棵树是否是搜索二叉树、判断一棵树是否是完全二叉树
思路:二叉树中序遍历的节点是依次升序的就是搜索二叉树,通常搜索二叉树中不包含重复结点的。改中序遍历的非递归的代码,打印的时机替换成与前一个节点进行比较
import java.util.Stack;
import java.util.LinkedList;
public class IsSearchTree {
//判断是否是搜索二叉树
public static class Node{
public int val;
public Node left;
public Node right;
public Node(int x) {
this.val = x;
}
}
public static boolean issearchtree(Node root) {
if(root == null)
return true;
Stack<Node> st = new Stack<>();
int num = Integer.MIN_VALUE;
while(!st.isEmpty() || root != null) {
if(root != null) {
st.push(root);
root = root.left;
}else {
root = st.pop();
if(root.val >= num) {//这里和原来中序遍历的地方不一样了
num = root.val;
}else
return false;
root = root.right;
}
}
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.val + 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(issearchtree(head));
//System.out.println(isCBT(head));
}
}
如何判断完全二叉树?
完全二叉树就是该放的结点都怼在上面,不要跳着怼。完全二叉树和值是没有关系的,结构是完全二叉树
思路:分三种情况:
宽度优先遍历这棵树
- 一个结点有右孩子,没有左孩子,那他肯定不是完全二叉树
- 一个结点不是左右两个孩子都全。也就是有左没右或者左右都没有。那么它后面遇到的所有结点都必须是叶节点,否则不是完全二叉树
import java.util.Queue;
//import IsSearchTree.Node;
import java.util.LinkedList;
public class IsAbBinaryTree {
//判断是否为完全二叉树
public static class Node{
public int val;
public Node left;
public Node right;
public Node(int x) {
this.val = x;
}
}
public static boolean isabbinarytree(Node root) {
if(root == null)
return true;
Queue<Node> qq = new LinkedList<>();
qq.add(root);
while(!qq.isEmpty()) {
root = qq.poll();
if(root.right != null && root.left == null) {
return false;
}
if(root.left != null)
qq.add(root.left);
if(root.right != null)
qq.add(root.right);
if(root.left == null || root.right == null) {
while(!qq.isEmpty()) {
root = qq.poll();
if(!(root.left == null&&root.right == null))
return false;
}
}
}
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.val + 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(issearchtree(head));
System.out.println(isabbinarytree(head));
}
}
用数组实现堆有空间浪费和扩容代价。用二叉树实现堆就不会。
有一个满二叉树,高度为L,那么它的节点数是2^L - 1;
思路:如果遍历的话时间复杂度就会是O(n)。
遍历左子树的最左节点,找到树的高度。O(logn)
遍历右子树的左边界,如果这里的高度等于树的高度,说明左子树是满的,左子树的高度就求出来了,然后递归去求右子树的节点数。
如果右子树的左边界没到最后一层,右子树是满的,但是高度是左树的高度减一,剩下的节点递归去求。
public class NodeNumber {
//求完全二叉树的结点数
public static class Node{
public int val;
public Node left;
public Node right;
public Node(int x) {
this.val = x;
}
}
public static int nodenumber(Node root) {
if(root == null)
return 0;
int h = 0;
return nodenumber(root,h);
}
public static int nodenumber(Node root,int h) {
if(root == null) {
return 0;
}
Node tmp = root.left;
int lh = 0;
while(tmp != null) {
tmp = tmp.left;
lh++;
}
tmp = root.right;
int rh = 0;
while(tmp != null) {
tmp = tmp.left;
rh++;
}
if(lh > rh) {
h = (1 << rh) + nodenumber(root.left,h);//位运算的优先级低于加法的优先级!!要加上小括号
}else {
h = (1 << lh) + nodenumber(root.right,h);
}
return h;
}
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(nodenumber(head));
}
}