题目1:前序,中序,后序 非递归遍历二叉树node
代码:this
前序:spa
public static void preOrderUnRecur(Node head) { System.out.print("pre-order: "); 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(); }
中序:指针
public static void inOrderUnRecur(Node head) { System.out.print("in-order: "); 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(); }
后序code
最简单的思路:blog
前序的顺序为 中左右 后序的顺序为 左右中,若是前序遍历变为 中右左,那么后序遍历和前序遍历的顺序就会正好相反,如何让前序遍历 变为 中右左呢,就是把left和right入站的顺序递归
改变一下就行,而后在每次打印节点的地方,换成把节点加入到另外一个栈,以后遍历这个站就是 后序遍历的节点顺序队列
public static void posOrderUnRecur1(Node head) { System.out.print("pos-order: "); if (head != null) { Stack<Node> s1 = new Stack<Node>(); Stack<Node> s2 = new Stack<Node>(); s1.push(head); while (!s1.isEmpty()) { head = s1.pop(); s2.push(head); if (head.left != null) { s1.push(head.left); } if (head.right != null) { s1.push(head.right); } } while (!s2.isEmpty()) { System.out.print(s2.pop().value + " "); } } System.out.println(); }
题目二:get
二叉树的序列号和反序列化it
思路一:利用递归方法:
序列化:
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)); }
题目三:求二叉树的后继节点(每一个节点有parent指针,指向父亲节点)
后继节点是指二叉树中序遍历中,某个节点的后面的那个节点
思路:
经过概括总结,可分为两种状况
状况1:节点A的右子树不为空,那么节点A的后继为 右子树的 最左边的孩子
状况2:节点A的右子树为空,那么开始从节点A不断经过parent指针找到他的父节点,直到找到的 当前节点A' 的父亲节点B的左孩子等于A',B就是节点A的后继
特殊状况为 中序遍历的最后一个节点,它没有后继,返回null
代码以下:
public class 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 (parent != null && parent.left != node) { node = parent; parent = node.parent; } return parent; } } public 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)); } }
题目四:判断一个树是否是平衡二叉树?
平衡二叉树是指任何树的左子树和右子树的高度相差不大于1
思路
根据概念能够分析出能够用递归方法:
1 求出节点A的 左子树高度
2 求出节点A的 右子树高度
3 判断高度差是否大于1,更新布尔值
public class 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]; } public 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)); } }
这里经过层级字段求出 高度,和单纯求每层节点的高度是一个道理。
题目五:判断一个树是否是二叉搜索树?
比较好理解的思路:中序遍历 以后的升序序列就是 二叉搜索树
bool isValidBST(TreeNode* root) { stack<TreeNode*>que; TreeNode * p = root; int pre=INT_MIN; int num=0; while (p|| que.empty()==false) { if(p){ que.push(p); p=p->left; } else{ TreeNode * node = que.top(); que.pop(); int val = node->val; printf("%d\n",val); if(num==1){ if(val<=pre){ return false; } } num=1; pre=val; p=node->right; } } return true; }
题目六:判断一个树是否为彻底二叉树?
思路:
能够借助队列
在两种状况下,必定不是彻底二叉树
状况1: 左子树为空,右子树不为空
状况2:开始叶子节点遍历的时候,若是不是叶子节点,就不是彻底二叉树
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.offer(head); while (!queue.isEmpty()) { 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.offer(l); } if (r != null) { queue.offer(r); } else { leaf = true; } } return true; }
题目七:已知一棵彻底二叉树,求其节点的个数 要求:时间复杂度低于O(N),N为这棵树的节点个数
思路1:若是时间复杂度为O(N),那么就能够遍历这棵树,可是没有利用彻底二叉树的特色。
这里咱们每次看当前节点的右子树的是否达到了最底部。
1 若是达到了,那么当前点的左子树必定就是彻底二叉树,能够利用h^2-1求出左子树的节点数目,
而后递归求解右子树的节点个数。
2 若是没达到,那么当前节点的右子树必定是彻底二叉树,节点数为(h-1)^2-1 ,而后递归求解左子树的节点个数
3 递归终止条件为 到达叶节点,返回1
代码:
public class 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) { return 0; } return bs(head, 1, mostLeftLevel(head, 1)); } public static int bs(Node node, int l, int h) { if (l == h) { return 1; } if (mostLeftLevel(node.right, l + 1) == h) { return (1 << (h - l)) + bs(node.right, l + 1, h); } else { return (1 << (h - l - 1)) + bs(node.left, l + 1, h); } } public static int mostLeftLevel(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)); } }
思路2:
一颗树为彻底二叉树就分为两种状况:
一种是左子树和右子树的最大高度同样,另外一种是左子树比右子树高度大1,因此能够根据这两种状况写递归:
第一种状况 左子树必定是彻底二叉树,第二种状况右子树必定是彻底二叉树:
int getDepth(TreeNode *node){ int height = 0; while (node) { node = node->left; height++; } return height; } int getReturn(TreeNode * node){ if(node==nullptr){ return 0; } int h1= getDepth(node->left); int h2= getDepth(node->right); //若是 左右子树 最大高度相等,左边为彻底二叉树 if(h1==h2){ return (1<<h1)+ getReturn(node->right); } //右边为彻底二叉树 else { return (1<<h2)+ getReturn(node->left); } } //彻底二叉树节点个数 int countNodes(TreeNode* root) { return getReturn(root); }