文章目录
遍历
先序
递归法
public static void preOrderRecur(Node head){
if (head == null){
return;
}
System.out.println(head.value + " ");
preOrderRecur(head.left);
preOrderRecur(head.right);
}
非递归
public static void preOrderRecur1(Node head){
if (head == null){
return;
}
Stack<Node> stack = new Stack<>();
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.right);
}
}
System.out.println();
}
中序
递归法
public static void inOrderRecur(Node head){
if (head == null){
return;
}
inOrderRecur(head.left);
System.out.println(head.value + " ");
inOrderRecur(head.right);
}
非递归
public static void inOrderRecur1(Node head){
if (head == null){
return;
}
Stack<Node> stack = new Stack<>();
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();
}
后序
递归法
public static void posOrderRecur(Node head){
if (head == null){
return;
}
posOrderRecur(head.left);
posOrderRecur(head.right);
System.out.println(head.value + " ");
}
非递归
头左右(入栈是 头右左)
(入栈头左右 再放入收集栈,遍历收集栈就是后序遍历)
(入栈头左右 再放入收集栈,遍历收集栈就是后序遍历)
public static void posOrderRecur1(Node head){
if (head == null){
return;
}
Stack<Node> stack = new Stack<>();
Stack<Node> stack1 = new Stack<>();
stack.add(head);
while (! stack.isEmpty()){
head = stack.pop();
stack1.push(head);
if (head.left != null){
stack.push(head.left);
}
if (head.right != null){
stack.push(head.right);
}
}
while (stack1 != null){
System.out.println(stack1.pop().value + " ");
}
System.out.println();
}
深度优先遍历 == 先序遍历
宽度优先遍历
用队列,先进先出
先放头结点,弹出就打印,再放左再放右
public static void wOrder(Node head){
if (head == null){
return;
}
Queue<Node> queue = new LinkedList<>();
queue.add(head);
while (queue != null){
Node cur = queue.poll();
System.out.println(cur.value + " ");
if (cur.left != null){
queue.add(cur.left);
}
if (cur.right != null){
queue.add(cur.right);
}
}
}
求一棵二叉树最大宽度
public static int wmax(Node head){
if (head == null){
return 0;
}
Queue<Node> queue = new LinkedList<>();
queue.add(head);
HashMap<Node, Integer> map = new HashMap<>();
map.put(head,1);
int curLever = 1;
int curLeverNodes = 0;
int max = Integer.MIN_VALUE;
while (queue != null){
Node cur = queue.poll();
int curNodeLevel = map.get(cur);
if (curNodeLevel == curLever){
curLeverNodes++;
}else {
max = Math.max(max,curLeverNodes);
curLever++;
curLeverNodes = 1;
}
System.out.println(cur.value + " ");
if (cur.left != null){
map.put(cur.left,curLever+1);
queue.add(cur.left);
}
if (cur.right != null){
map.put(cur.right,curLever+1);
queue.add(cur.right);
}
}
return max;
}
二叉树的相关概念及其实现判断
如何判断一颗二叉树是否是搜索二叉树?
(每颗子树都是左树比右树小)
中序遍历,如果都是升序就是搜索二叉树
public static boolean chackBST(Node head){
int preValue = Integer.MIN_VALUE;
if (head == null){
return true;
}
boolean isLeftBST = chackBST(head.left);
if (!isLeftBST){
return false;
}
if (head.value <= preValue) {
return false;
} else {
preValue = head.value;
}
return chackBST(head.right);
}
public static boolean checkBST2(Node head){
int preValue = Integer.MIN_VALUE;
if (head == null){
return true;
}
Stack<Node> stack = new Stack<>();
while (! stack.isEmpty() || head != null){
if (head != null){
stack.push(head);
head = head.left;
}else {
head = stack.pop();
if (head.value <= preValue){
return false;
}else {
preValue = head.value;
}
head = head.right;
}
}
return true;
}
套路解法
public static boolean checkBST3(Node head){
return process1(head).isBST;
}
public static class ReturnData{
public boolean isBST;
public int max;
public int min;
public ReturnData(boolean isBST, int max, int min) {
this.isBST = isBST;
this.max = max;
this.min = min;
}
}
public static ReturnData process1(Node x){
if (x == null){
return null;
}
ReturnData leftData = process1(x.left);
ReturnData rightData = process1(x.right);
int min = x.value;
int max = 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)){
isBST = false;
}
if (rightData != null && (!rightData.isBST || rightData.min <= x.value)){
isBST = false;
}
return new ReturnData(isBST,min,max);
}
如何判断一颗二叉树是完全二叉树?
按宽度来遍历
- 有右无左 返回false
- 在1不违规的情况下,如果遇到了第一个左右不全的节点,则后面的都为叶节点。
public static boolean isCBT(Node head){
if (head == null){
return true;
}
LinkedList<Node> queue = new LinkedList<>();
boolean leaf = false;//是否遇到左右不双全的节点,无false,有就为ture
Node l = null;
Node r = null;
queue.add(head);
while (!queue.isEmpty()){
head = queue.poll();
l = head.left;
r = head.right;
if (//第一个是 不双全但还有子节点 第二个是 左无右有 直接false
(leaf && (l != null || r != null)) || (l == null && r != null)
){
return false;
}
if (l != null){
queue.add(l);
}
if (r != null){
queue.add(r);
}
if (l == null || r == null){//如果不双全 leaf = true
leaf = true;
}
}
return true;
}
如何判断一颗二叉树是否是满二叉树?
- 最大深度 L 节点数 N 如果满足 n = 2^L -1 就是满二叉树
套路解法
public static boolean isF(Node head){
if (head == null){
return true;
}
Info data = process3(head);
return data.nodes == (1 << data.height -1);
}
public static class Info{
public int nodes;
public int height;
public Info(int nodes, int height) {
this.nodes = nodes;
this.height = height;
}
}
public static Info process3(Node x){
if (x == null){
return new Info(0,0);
}
Info leftData = process3(x.left);
Info rightData = process3(x.right);
int height = Math.max(leftData.height, rightData.height)+1;
int nodes = leftData.nodes + rightData.nodes +1;
return new Info(height,nodes);
}
如何判断一颗二叉树是否是平衡二叉树? (二叉树题目 套路)
套路解法
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;
}
}
public static ReturnType process(Node x){
if (x == null){
return new ReturnType(true,0);
}
ReturnType leftData = process(x.left);
ReturnType rightData = process(x.right);
int height = Math.max(leftData.height, rightData.height)+1;
boolean isBalanced = leftData.isBalanced && rightData.isBalanced
&& Math.abs(leftData.height- rightData.height) < 2;
return new ReturnType(isBalanced,height);
}
*递归套路 =====》树型DP*
最低公共祖先
public static Node lca(Node head, Node o1, Node o2){
HashMap<Node,Node> fathermap = new HashMap<>();
fathermap.put(head,head);
process4(head,fathermap);
HashSet<Node> set1 = new HashSet<>();
Node cur = o1;
while (cur != fathermap.get(cur)){
set1.add(cur);
cur = fathermap.get(cur);
}
set1.add(head);
Node cur2 = o2;
while (!set1.contains(cur2)){
cur2 = fathermap.get(cur2);
}
return cur2;
}
public static void process4(Node head, HashMap<Node, Node> fathermap) {
if (head == null){
return;
}
fathermap.put(head.left,head);
fathermap.put(head.right,head);
process4(head.left, fathermap);
process4(head.right, fathermap);
}
- o1是o2 / o2是o1 的最低公共祖先
- o1o2不互为公共祖先(向上汇聚找到)
public static Node lowca(Node head, Node o1, Node o2){
if (head == null || head == o1 || head == o2){
return head;
}
Node left = lowca(head.left, o1, o2);
Node right = lowca(head.right, o1, o2);
if (left != null && right != null){
return head;
}
return left != null ? left : right;
}
在二叉树中找到一个节点的后继节点
[题目]现在有 - -种新的二叉树节点类型如下:
public class Node{
public int value;
public Node left;
public Node right;
public Node parent;
public Node(int val) {
value = val ;
}
}
该结构比普通二叉树节点结构多了一个指向父节点的parent指针。
假设有一棵Node类型的节点组成的二叉树,树中每个节点的parent指针都正确地指向自己的父节点,头节点的parent指向null。
只给一个在二叉树中的某个节点node,请实现返回node的后继节点的函数。
(在二叉树的中序遍历的序列中,node的 下一个节点叫作node的后继节点。)
- x有右树,后继是右树的最左边
- x无右树,向上找,是一个节点的左树时这个节点是x的后继
- 向上一直不是左节点,则为最右的节点,后继为null
public static Node1 getSuccessorNode(Node1 node){
if (node == null){
return node;
}
if (node.right != null){
return getLeftMost(node.right);
}else { //无右子树
Node1 parent = node.parent;
while (parent != null && parent.left != node){
node = node.parent;
parent = node.parent;
}
return parent;
}
}
public static Node1 getLeftMost(Node1 node) {
if (node == null){
return node;
}
if (node.left != null){
node = node.left;
}
return node;
}
二叉树的序列化和反序列化
就是内存里的一棵树如何变成字符串形式,又如何从字符串形式变成内存里的树
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<>();
for (int i = 0; i < values.length; i++) {
queue.add(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 void printAllFolds(int N){
printProcess(1,N,true);
}
public 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);
}