題目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); }