1.二叉树递归遍历
前序:
public static void preOrderRecur(Node head) {
if(head==null){
return;
}
System.out.println(head.value);
preOrderRecur(head.left);
preOrderRecur(head.right);
}
中序:
public static void inOrderRecur(Node head) {
if(head==null){
return;
}
inOrderRecur(head.left);
System.out.println(head.value);
inOrderRecur(head.right);
}
后序:
public static void posOrderRecur(Node head) {
if(head==null){
return;
}
posOrderRecur(head.left);
posOrderRecur(head.right);
System.out.println(head.value);
}
2.二叉树非递归遍历
前序:
public static void preOrderUnRecur(Node head) {
Stack<Node> stack = new Stack<>();
stack.push(head);
while(!stack.isEmpty()){
Node h=stack.pop();
System.out.println(h.value);
if(h.right!=null){
stack.push(h.right);
}
if(h.left!=null){
stack.push(h.left);
}
}
中序:需要注意:第一次没写出来
public static void inOrderUnRecur(Node head) {
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;
}
}
}
后序:
public static void posOrderUnRecur1(Node head) {
if(head!=null){
Stack<Node> stack1=new Stack<>();
Stack<Node> stack2=new Stack<>();
stack1.push(head);
while(!stack1.isEmpty()){
head=stack1.pop();
stack2.push(head);
if(head.left!=null){
stack1.push(head.left);
}
if(head.right!=null){
stack1.push(head.right);
}
}
while(!stack2.isEmpty()){
System.out.println(stack2.pop().value);
}
}
}
3.求二叉树的宽度
方法一:hashmap存当前节点的层数
public static int getMaxWidth(Node head) {
Queue<Node> queue=new LinkedList<>();
queue.add(head);
int maxWidth=Integer.MIN_VALUE;
int curLevel=1;
int curLevelNode=0;
HashMap<Node,Integer> hashMap=new HashMap<>();
hashMap.put(head,1);
while(!queue.isEmpty()){
head=queue.poll();
if(hashMap.get(head)==curLevel){
curLevelNode++;
}else{
maxWidth=Math.max(curLevelNode,maxWidth);
curLevel++;
curLevelNode=1;
}
if(head.left!=null){
queue.add(head.left);
hashMap.put(head.left,curLevel+1);
}
if(head.right!=null){
queue.add(head.right);
hashMap.put(head.right,curLevel+1);
}
}
return maxWidth;
}
方法二:
public static int getMaxWidth1(Node head){
Queue<Node> queue=new LinkedList<>();
Node curEnd=head;
Node nextEnd=null;
int curLevelNode=0;
int max=0;
queue.add(head);
while(!queue.isEmpty()){
head=queue.poll();
curLevelNode++;
if(head.left!=null){
queue.add(head.left);
nextEnd=head.left;
}
if(head.right!=null){
queue.add(head.right);
nextEnd=head.right;
}
if(head==curEnd){
max=Math.max(max,curLevelNode);
curEnd=nextEnd;
curLevelNode=0;
}
}
return max;
}
4.判断一棵二叉树是否为搜索二叉树(左子树的值小于根,右子树的值大于根)
法一:中序遍历,拿list集合存,最终看是否为升序
public static class Node {
public int value;
public Node left;
public Node right;
public Node(int data) {
this.value = data;
}
}
public static boolean isBST(Node head) {
if(head==null){
return true;
}
List<Node> inOrderList = new ArrayList<>();
process(head,inOrderList);
for (int i = 0; i < inOrderList.size()-1; i++) {
if(inOrderList.get(i).value>inOrderList.get(i+1).value){
return false;
}
}
return true;
}
public static void process(Node node, List<Node> inOrderList) {
if(node==null){
return;
}
process(node.left,inOrderList);
inOrderList.add(node);
process(node.right,inOrderList);
}
法二:二叉树的套路:看左树右树能提供什么信息(不熟练,需注意)
public static class Information{
public boolean isBst;
public int max;
public int min;
public Information(boolean isBst, int max, int min) {
this.isBst = isBst;
this.max = max;
this.min = min;
}
}
public static boolean isBST1(Node head){
if(head==null){
return true;
}
Information infor=process1(head);
return infor.isBst;
}
public static Information process1(Node node){
if(node==null){
return null;
}
Information inforLeft=process1(node.left);
Information inforRight=process1(node.right);
int max=node.value;
int min=node.value;
if(inforLeft!=null){
max=Math.max(max,inforLeft.max);
min=Math.min(min,inforLeft.min);
}
if(inforRight!=null){
max=Math.max(max,inforRight.max);
min=Math.min(min,inforRight.min);
}
boolean isBst=true;
if(inforLeft!=null&&(inforLeft.isBst==false||inforLeft.max>=max)){
isBst=false;
}
if(inforRight!=null&&(inforRight.isBst==false||inforRight.min<=min)){
isBst=false;
}
return new Information(isBst,max,min);
}
5.判断是否是完全二叉树
(1)任一节点,有右无左,false
(2)在(1)符合的条件下,遇到第一个左右孩子不双全,后续节点都为叶子节点
public static boolean isCBT(Node head) {
if(head==null){
return true;
}
Queue<Node> queue=new LinkedList<>();
queue.add(head);
boolean isZi=false;//遇到第一个左右孩子不双全的节点变为true
while(!queue.isEmpty()){
Node poll = queue.poll();
if (poll.left==null&&poll.right!=null){
return false;
}
if(isZi==true){
if (poll.left!=null||poll.right!=null){
return false;
}
}
if(poll.left!=null){
Node left=poll.left;
queue.add(left);
}else{
isZi=true;
}
if(poll.right!=null){
Node right=poll.right;
queue.add(right);
}else{
isZi=true;
}
}
return true;
}
6.判断是否是满二叉树
法一:求深度,求节点个数,满足nodeNum=2^depth-1
public static boolean isFullTree(Node head){
int depth = depth(head);
int count = count(head);
if(count==Math.pow(2,depth)-1){
return true;
}
return false;
}
private static int depth(Node head) {
int depth=1;
while(head.left!=null){
head=head.left;
depth++;
}
return depth;
}
private static int count(Node head) {
List<Node> list=new ArrayList<>();
process(head, list);
return list.size();
}
public static void process(Node head, List<Node> list){
if(head==null){
return;
}
list.add(head);
process(head.left,list);
process(head.right,list);
}
法二:套路:管左子树要信息(左子树的节点个数,深度),管右子树要信息,判断自身
public static class Info{
public int depth;
public int nodeNum;
public Info(int depth,int nodeNum){
this.depth=depth;
this.nodeNum=nodeNum;
}
}
public static boolean isFull(Node head){
Info info=process(head);
if(Math.pow(2,info.depth)-1==info.nodeNum){
return true;
}
return false;
}
public static Info process(Node head){
if(head==null){
return new Info(0,0);
}
Info infoLeft=process(head.left);
Info infoRight=process(head.right);
int depth=Math.max(infoLeft.depth,infoRight.depth)+1;
int num=infoLeft.nodeNum+infoRight.nodeNum+1;
return new Info(depth,num);
}
7.判断是否是平衡二叉树
public static boolean isBalanced(Node head) {
return process(head).isBalanced;
}
public static class Info{
boolean isBalanced;
int height;
public Info(boolean isBalanced, int height) {
this.isBalanced = isBalanced;
this.height = height;
}
}
public static Info process(Node x) {
if(x==null){
return new Info(true,0);
}
Info infoLeft = process(x.left);
Info infoRight=process(x.right);
// boolean isBalanced=false;
// int height=0;
// if(infoLeft.isBalanced&&infoRight.isBalanced){
// if(Math.abs(infoLeft.height-infoRight.height)<=1){
// isBalanced=true;
// height=Math.max(infoLeft.height,infoRight.height)+1;
// }
// }
//两种写法都可,下面的更简洁
int height=Math.max(infoLeft.height,infoRight.height)+1;
boolean isBalanced=(infoLeft.isBalanced&&infoRight.isBalanced)&&(Math.abs(infoLeft.height-infoRight.height)<=1);
return new Info(isBalanced,height);
}
7.寻找公共祖先节点
法一:Map保存所有节点的父节点
node1往上的链存入set
node2再往上走,看节点是否在set中
public static Node lowestAncestor(Node head, Node o1, Node o2) {
HashMap<Node ,Node > hashMap=new HashMap<>();
Node h=head;
hashMap.put(head,head);
Queue<Node> queue = new LinkedList<>();
queue.add(head);
//层序遍历存节点
while(!queue.isEmpty()){
Node poll=queue.poll();
if(poll.left!=null){
hashMap.put(poll.left,poll);
queue.add(poll.left);
}
if(poll.right!=null){
hashMap.put(poll.right,poll);
queue.add(poll.right);
}
}
HashSet<Node> hashSet=new HashSet<>();
while(o1!=hashMap.get(o1)){
hashSet.add(o1);
o1=hashMap.get(o1);
}
while(o2!=hashMap.get(o2)){
if(hashSet.contains(o2)){
return o2;
}
o2=hashMap.get(o2);
}
return h;
}
法二:(很模糊)
public static Node lowestAncestor1(Node head, Node o1, Node o2){
if(head==null||head==o1||head==o2){
return head;
}
Node left=lowestAncestor1(head.left,o1,o2);
Node right=lowestAncestor1(head.right,o1,o2);
if(left!=null&&right!=null){
return head;
}
return left!=null?left:right;
}
8.二叉树中找一个节点的后继节点
法一:拿list存中序遍历顺序,直接找该节点的下一个节点(这种情况必须把头节点传进来)
public static Node getSuccessorNode(Node head, Node x) {
List<Node> list = new ArrayList<>();
process(head, list);
Node node = null;
for (int i = 0; i < list.size(); i++) {
if (list.get(i) == x) {
if ((i + 1) < list.size()) {
node = list.get(i + 1);
} else {
node = null;
}
}
}
return node;
}
public static void process(Node head, List<Node> list) {
if (head == null) {
return;
}
process(head.left, list);
list.add(head);
process(head.right, list);
}
法二:(1)x有右树–右树上的最左节点
(2)x无右树–是父节点的左孩子吗?不是,往上,是返回父节点
public static Node getSuccessorNode(Node node) {
if (node == null) {
return null;
}
if (node.right != null) {
node = getLeft(node);
} else {
while (node.parent != null && node != node.parent.left) {//注意node.parent != null这个条件,第一次没写陷入了窘境
node = node.parent;
}
node = node.parent;
}
return node;
}
//获取最左边的节点
public static Node getLeft(Node node) {
if (node == null) {
return node;
}
node = node.right;
while (node.left != null) {
node = node.left;
}
return node;
}
9.二叉树的序列化与反序列化
序列化:
public static String serialByPre(Node head) {
if (head == null) {
return "#_";
}
String str = head.value + "_";
String left = serialByPre(head.left);
str = str+left;
String right = serialByPre(head.right);
str += right;
return str;
}
反序列化:(模糊)
public static Node reconByPreString(String preStr) {
String [] strs= preStr.split("_");
Queue<String> queue=new LinkedList<>();
for (int i = 0; i < strs.length; i++) {
queue.add(strs[i]);
}
return null;
}
public static Node reconPreOrder(Queue<String> queue) {
String str=queue.poll();
if(str=="#"){
return null;
}
Node head=new Node(Integer.valueOf(str));
head.left=reconPreOrder(queue);
head.right=reconPreOrder(queue);
return head;
}
10.折纸问题(模糊)
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?"down":"up");
printProcess(i+1,N,false);
}
public static void main(String[] args) {
int N = 1;
printAllFolds(N);
}