前言
这个博客会列出常见的有关二叉树的面试题目并给出算法思想。总体目录如下:-
DFS(深度优先遍历)
先序遍历
中序遍历
1.判断是否是二叉搜索树
2.根据二叉搜索树构建双向链表
后序遍历
三合一非递归
-
BFS(广度优先遍历)
层序遍历
1.二叉树的深度
2.之字形打印二叉树 -
寻找双亲
1.单个结点的双亲
2.两个结点的公共双亲
3.在二叉搜索树中寻找最近公共祖先
-
其他
1.根据传入数组创建树
2.在二叉树中寻找值
3.判断二叉树是否对称
4.返回二叉树的镜像树
3.判断传入数组是否是某二叉搜索树的后序遍历
DFS的递归写法
前中后序的递归遍历非常简单,如下:
public void preOrder(BtNode cur){
//递归-先序遍历
if(cur == null)return;
System.out.print(cur.data+" ");
preOrder(cur.left);
preOrder(cur.right);
}
public void inOrder(BtNode cur){
//递归-中序遍历
if(cur == null)return;
inOrder(cur.left);
System.out.print(cur.data+" ");
inOrder(cur.right);
}
public void pastOrder(BtNode cur){
//递归-后序遍历
if(cur == null)return;
pastOrder(cur.left);
pastOrder(cur.right);
System.out.print(cur.data+" ");
}
DFS的非递归写法
先序遍历
思想:从栈中弹出一个结点,保存当前结点值,并将其左右子树压入栈中。(注意如果要严格遵从先左后右的规则, 需要先压右孩子再压左孩子,这样现出来的才能是左孩子。)很明显上述过程需要进行迭代,用栈不空作为条件。
public List<Integer> nicePreOrder(){
//非递归-先序遍历
List<Integer> list = new ArrayList<>();
if(root == null)return list;
Stack<BtNode> stack = new Stack<>();
stack.push(root);
while(!stack.isEmpty()){
BtNode cur = stack.pop();
list.add(cur.data);
if(cur.right!= null)stack.push(cur.right);
if(cur.left != null)stack.push(cur.left);
}
return list;
}
中序遍历
思想:将当前结点一直朝左下延伸,将一路的结点放入栈,直到当前结点没有左孩子。这一步完成后将栈顶元素出栈,对其进行操作(打印/放入表等),再对右孩子进行迭代。public List<Integer> niceInOrder(){
//非递归-中序遍历
List<Integer> list = new ArrayList<>();
if(root == null)return list;
BtNode cur = root;
Stack<BtNode> stack = new Stack<>();
while(!stack.isEmpty() || cur != null){
while(cur != null){
stack.push(cur);
cur = cur.left;
}
cur = stack.pop();
list.add(cur.data);
cur = cur.right;
}
return list;
}
后序遍历
思想:同中序遍历,先把一路的左孩子入栈,不同的是需要对右孩子进行标记,操作过右孩子之后才可以操作根节点元素,没有操作过右孩子要把当前结点再次入栈。public List<Integer> nicePastOrder(){
//非递归-后序遍历
List<Integer> list = new ArrayList<>();
if(root == null)return list;
BtNode tag = null;
BtNode ptr = root;
Stack<BtNode> st = new Stack<>();
while (!st.empty() || ptr != null) {
//先把左边的一溜都放进去
while (ptr != null) {
st.push(ptr);
ptr = ptr.left;
}
ptr = st.pop