目录
二叉树非递归先序遍历
先序遍历:二叉树中每个子树都以头-左-右的顺序打印。
思路:
1.头节点入栈;
2.弹出栈中节点,同时将子节点从右至左入栈;
3.继续弹出节点,每弹出一个节点执行第二步操作。
//实体类
public static class Node {
public int value;
public Node left;
public Node right;
public Node(int data){
this.value = data;
}
}
public static void preOrderUnRecur(Node head) {
System.out.println("pre-order:");
if (head != null) {
Stack<Node> stack = new Stack<Node>();
stack.add(head);
while (!stack.isEmpty()) {
head = stack.pop();
System.out.println(head.value + " ");
if (head.right != null){
stack.push(head.right);
}
if (head.left != null) {
stack.push(head.left);
}
}
}
System.out.println();
}
二叉树非递归后序遍历
后序遍历:二叉树中每个子树都以右-左-头的顺序打印。
利用栈的特性,将上一题的结果入栈后依次弹出即可。
public static void posOrderUnRecur1(Node head) {
System.out.println("poe-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.right);
}
if (head.right != null) {
s1.push(head.left);
}
}
while (s2 != null) {
System.out.println(s2.pop().value + " ");
}
}
System.out.println();
}
二叉树非递归中序遍历
中序遍历:二叉树每个子树都以左-头-右的顺序打印。
思路:
1.将二叉树左边界从头节点开始依次入栈。
2.弹出栈中节点,每弹出一个节点时查看其是否存在子节点,如果有,入栈。
3.每个节点入栈时都将以该节点为头的二叉树左边界依次入栈。
4.重复执行2、3步骤,周而复始,直至栈空。
public static void inOrderUnRecur(Node head) {
System.out.println("in-order:");
if (head != null) {
Stack<Node> stack = new Stack<Node>();
stack.push(head);
while (!stack.isEmpty() || head != null) {
if (head != null) {
stack.push(head);
head = head.left;
}else {
head = stack.pop();
System.out.println(head.value + " ");
head = head.right;
}
}
}
System.out.println();
}
二叉树层序遍历
层序遍历(宽度优先遍历):二叉树遍历完一层再遍历下一层。
思路:
1.头节点入队列。
2.弹出节点,每弹出一个节点,将其子节点入栈。
3.重复第二部操作。
public static void levelOrder(Node head) {
if (head == null) {
return;
}
Queue<Node> queue = new LinkedList<>();
queue.add(head);
while (!queue.isEmpty()) {
Node cur = queue.poll();
System.out.println(cur.value);
if (head.left != null) {
queue.add(head.left);
}
if (cur.right != null) {
queue.add(cur.right);
}
}
}
求二叉树的最大宽度
在层序遍历的基础上记录每一层的节点数取最大值。
public static void maxWidth(Node head) {
if (head == null) {
return;
}
Queue<Node> queue = new LinkedList<>();
queue.add(head);
HashMap<Node, Integer> levelMap = new HashMap<>();
levelMap.put(head, 1);
int curLevel = 1;
int curlevelNodes = 0;
int max = Integer.MIN_VALUE;
while (!queue.isEmpty()) {
Node cur = queue.poll();
int curNodeLevel = levelMap.get(cur);
if (curNodeLevel == curLevel) {
curlevelNodes++;
}else {
max = Math.max(curlevelNodes, max);
curLevel++;
curlevelNodes = 1;
}
System.out.println(cur.value);
if (head.left != null) {
levelMap.put(cur.left, curNodeLevel+1);
queue.add(head.left);
}
if (cur.right != null) {
levelMap.put(cur.right, curNodeLevel+1);
queue.add(cur.right);
}
}
}
判断当前二叉树是否搜索二叉树
搜索二叉树:对于每一颗子树来说,它的左树都比它小,右树都比它大。
解法一
中序遍历,遍历时比较当前节点值是否大于上一节点值,如果不大于,则不为搜索二叉树。
private static int preValue = Integer.MIN_VALUE;
public static boolean isBst(Node head) {
if (head == null) {
return true;
}
boolean isLeftBst = isBst(head.left);
if (!isLeftBst) {
return false;
}
if (head.value <= preValue) {
return false;
}else {
preValue = head.value;
}
return isBst(head.right);
}
解法二
递归解法(树形DP)
public static boolean isBstRecu(Node head) {
if (head == null) {
return true;
}
return processBst(head).isBst;
}
public static class ReturnTypeBst {
public boolean isBst;
public int min;
public int max;
public ReturnTypeBst(boolean isBst, int min, int max) {
this.isBst = isBst;
this.min = min;
this.max = max;
}
}
private static ReturnTypeBst processBst(Node x) {
if (x == null) {
return null;
}
ReturnTypeBst leftData = processBst(x.left);
ReturnTypeBst rightData = processBst(x.right);
int max = x.value;
int min = x.value;
if (leftData != null) {
min = Math.min(min, leftData.min);
max = Math.max(max, leftData.max);
}
if (rightData != null) {
min = Math.min(min, rightData.min);
max = Math.max(max, rightData.max);
}
boolean isBst = true;
if ((leftData != null && (!leftData.isBst || leftData.max >= x.value)) ||
(rightData != null && (!rightData.isBst || rightData.min <= x.value))) {
isBst = false;
}
return new ReturnTypeBst(isBst, min, max);
}
判断当前二叉树是否完全二叉树
完全二叉树:将二叉树各节点按顺序编号,若其每个节点的编号与满二叉树的编号相同,则为完全二叉树。
思路:
1.层序遍历。
2.是否存在有右无左的节点,若存在,false。
3.当发现某一结点左右子节点不双全时,层序遍历中的后续节点必须为叶子节点,若不是,false。
public static boolean isCbt(Node head) {
if (head == null) {
return true;
}
LinkedList<Node> queue = new LinkedList<>();
//是否遇到过左右两个孩子不双全的节点
boolean leaf = false;
Node left = null;
Node right = null;
queue.add(head);
while (!queue.isEmpty()) {
head = queue.poll();
left = head.left;
right = head.right;
if (
(leaf && (left != null || right != null))
|| (left == null && right != null)
) {
return false;
}
if (left != null) {
queue.add(left);
}
if (right != null) {
queue.add(right);
}
if (left == null || right == null) {
leaf = true;
}
}
return true;
判断当前二叉树是否平衡二叉树
平衡二叉树:每个节点的左树与右树高度差不超过1。
public static boolean isBalanced(Node head) {
return process(head).isBalanced;
}
public static class ReturnType {
public boolean isBalanced;
public int height;
public ReturnType(boolean isBalanced, int height) {
this.isBalanced = isBalanced;
this.height = height;
}
}
private static ReturnType process(Node x) {
if (x == null) {
return new ReturnType(true, 0);
}
ReturnType leftDate = process(x.left);
ReturnType rightDate = process(x.right);
int height = Math.max(leftDate.height,rightDate.height) + 1;
boolean isBalanced = leftDate.isBalanced && rightDate.isBalanced
&& Math.abs(leftDate.height - rightDate.height) < 2;
return new ReturnType(isBalanced, height);
}
判断当前二叉树是否满二叉树
public static boolean isFullRecu(Node head) {
if (head == null) {
return true;
}
ReturnTypeFull res = processFull(head);
//深度为k,节点数为n的满二叉树满足 2的k次方-1 == n
return res.nodes == (1 << res.height - 1);
}
public static class ReturnTypeFull {
public int height;
public int nodes;
public ReturnTypeFull(int height, int nodes) {
this.height = height;
this.nodes = nodes;
}
}
private static ReturnTypeFull processFull(Node x) {
if (x == null) {
return new ReturnTypeFull(0,0);
}
ReturnTypeFull leftData = processFull(x.left);
ReturnTypeFull rightData = processFull(x.right);
int height = Math.max(leftData.height, rightData.height) + 1;
int nodes = leftData.nodes + rightData.nodes + 1;
return new ReturnTypeFull(height, nodes);
}
给定二叉树的头节点与两个节点,返回最低公共节点
public static Node lca(Node head, Node o1, Node o2) {
if (head == null || head == o1 || head == o2) {
return head;
}
Node left = lca(head.left, o1, o2);
Node right = lca(head.right, o1, o2);
if (left != null && right != null) {
return head;
}
return left != null ? left : right;
}
折纸问题
- 准备一个纸条,从纸条的下边向上方对折一次,压出折痕后展开。
- 此时折痕时凹下去的,即折痕突起的方向指向纸条的背面。
- 给定一个输入参数N,代表纸条都从下边向上方连续对着N次。
- 要求从上到下打印所有折痕的方向。
思路:
- 将折痕视为一颗二叉树,对折次数为二叉树深度。
- 每个节点的左子节点为凹痕节点,右子节点为凸痕节点。
public static void printAllFolds(int n) {
printProcess(1, n, true);
}
private static void printProcess(int i, int n, boolean down) {
if (i > n) {
return;
}
printProcess(i + 1, n, true);
System.out.println(down ? "凹" : "凸");
printProcess(i + 1, n, false);
}