题目1:前序,中序,后序 非递归遍历二叉树
代码:
前序:
public static void preOrderUnRecur(Node head) { System.out.print("pre-order: "); if (head != null) { Stackstack = new Stack (); 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) { Stackstack = new Stack (); 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(); }
后序
最简单的思路:
前序的顺序为 中左右 后序的顺序为 左右中,如果前序遍历变为 中右左,那么后序遍历和前序遍历的顺序就会正好相反,如何让前序遍历 变为 中右左呢,就是把left和right入站的顺序
改变一下就行,然后在每次打印节点的地方,换成把节点加入到另一个栈,之后遍历这个站就是 后序遍历的节点顺序
public static void posOrderUnRecur1(Node head) { System.out.print("pos-order: "); if (head != null) { Stacks1 = new Stack (); Stack s2 = new Stack (); 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(); }
题目二:
二叉树的序列号和反序列化
思路一:利用递归方法:
序列化:
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("!"); Queuequeue = new LinkedList (); for (int i = 0; i != values.length; i++) { queue.offer(values[i]); } return reconPreOrder(queue); } public static Node reconPreOrder(Queue 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 + "!"; Queuequeue = new LinkedList (); 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 queue = new LinkedList (); 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) { stackque; 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; } Queuequeue = new LinkedList (); 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<right); } //右边为完全二叉树 else { return (1<
left); } } //完全二叉树节点个数 int countNodes(TreeNode* root) { return getReturn(root); }