目录
一、二叉树的前序遍历
1、递归求法
public void preOrder(Node root){
if(root==null){
return;
}
System.out.print(root.val+" ");
preOrder(root.left);
preOrder(root.right);
}
2.非递归求法
通过栈和链表实现,先将根节点入栈,然后再循环弹出栈顶元素并加入到链表,同时判断栈顶元素的右孩子和左孩子是否为空(注意一定是先让右孩子入栈再左孩子!!!因为栈是先进后出,而先序遍历是根左右,需要先打印左孩子,所以让左孩子后入栈就可以先打印左孩子),如果不为空就入栈,为空就不入栈,以此循环知道栈为空结束。
import java.util.LinkedList;
import java.util.List;
import java.util.Stack;
public class Num144 {
//先序遍历的非递归实现
List<Integer> ret=new LinkedList<>();
public List<Integer> preorderTraversal(TreeNode root) {
if(root==null){
return ret;
}
Stack<TreeNode> stack=new Stack<>();
stack.push(root);
while (!stack.isEmpty()) {
TreeNode treeNode = stack.pop();
ret.add(treeNode.val);
//先入右孩子,因为栈是先入后出,先序遍历要后打印右孩子,所以让右孩子先入
if (treeNode.right != null) {
stack.push(treeNode.right);
}
if(treeNode.left!=null){
stack.push(treeNode.left);
}
}
return ret;
}
}
二、二叉树的中序遍历
1.递归求法
public void inOrder(Node root){
if(root==null){
return;
}
inOrder(root.left);
System.out.print(root.val+" ");
inOrder(root.right);
}
2.非递归求法
通过栈和链表来实现,引入cur引用,cur表示当前要处理的节点,让cur先指向root,然后开始在cur不为空的情况下循环将cur入栈,并让cur不断指向cur.left,直到cur.left为空(左处理完毕)就将栈顶元素弹出并加入到链表中(根节点处理完毕),再让cur指向cur.right(处理cur.right),如果cur.right为空,则再次弹出栈顶元素,并加入链表,如果不为空,就开始对cur,right进行处理,以此循环,直到栈为空。
import java.util.LinkedList;
import java.util.List;
import java.util.Stack;
public class Num94 {
List<Integer> ret=new LinkedList<>();
public List<Integer> inorderTraversal(TreeNode root) {
if (root == null) {
return ret;
}
Stack<TreeNode> stack=new Stack<>();
TreeNode cur=new TreeNode();
cur=root;
while (cur!=null || !stack.isEmpty()){
while (cur!=null) {
stack.push(cur);
cur=cur.left;
}
TreeNode node = stack.pop();
ret.add(node.val);
cur = node.right;
}
return ret;
}
}
三、二叉树的后序遍历
1.递归求法
public void postOrder(Node root){
if(root==null){
return;
}
postOrder(root.left);
postOrder(root.right);
System.out.print(root.val+" ");
}
2.非递归求法
通过栈和链表来实现,引入cur和prev引用,cur表示当前要处理的节点,prev表示最近一次已经访问过的节点。先将cur指向root,prev指向空,然后开始在cur不为空的情况下将cur循环入栈,并让cur=cur.left,直到cur.left为空,(左子树处理完毕)然后将栈顶元素暂时出栈,判断栈顶元素的右子树是否为空或者是刚刚最近一次处理过的节点,若是,就栈顶元素的右子树就不需要再处理,将栈顶元素加入到链表中,(右子树处理完毕),并且将prev置为当前的栈顶元素也就是cur,将cur置为空,使其继续处理现在的栈顶元素,若并不是,则将刚刚暂时出栈的栈顶元素再压入栈,并将cur=cur.right,使其循环处理右节点。
import java.util.LinkedList;
import java.util.List;
import java.util.Stack;
public class Num145 {
public List<Integer> postorderTraversal(TreeNode root) {
List<Integer> ret=new LinkedList<>();
if(root==null){
return ret;
}
Stack<TreeNode> stack=new Stack<>();
//当前需要处理的节点
TreeNode cur=root;
//最近一次已经访问过的节点
TreeNode prev=null;
while (cur!=null || !stack.isEmpty()){
while (cur!=null){
stack.push(cur);
cur=cur.left;
}
cur=stack.pop();
if(cur.right==null || prev==cur.right){
ret.add(cur.val);
prev=cur;
cur=null;
}else {
stack.push(cur);
cur=cur.right;
}
}
return ret;
}
}
四、二叉树的层序遍历
1.迭代求法
思路:使用队列,将根节点先入队列,然后在队列不为空的前提下开始循环,需要每一层中所有元素的左右节点都入队,因此每次出队一个元素,将他存入这一层的链表中并将他的左右节点在不为空的情况下入队,这一层的循环结束后,将这一层的链表存入总的大链表中,最终队列为空大的循环结束,返回这个大的链表,就得到了二叉树层序遍历的结果。
import java.util.ArrayList;
import java.util.LinkedList;
import java.util.List;
import java.util.Queue;
public class Num102 {
public List<List<Integer>> levelOrder(TreeNode root) {
List<List<Integer>> ret=new LinkedList<>();
if(root==null){
return ret;
}
Queue<TreeNode> queue=new LinkedList<>();//使用LinkedList由于我们要频繁的进行插入和删除操作
queue.offer(root);
while (!queue.isEmpty()) {
List level=new LinkedList();
int size=queue.size();
for (int i = 0; i < size; i++) {
TreeNode cur=queue.poll();
level.add(cur.val);
if(cur.left!=null){
queue.offer(cur.left);
}
if(cur.right!=null){
queue.offer(cur.right);
}
}
ret.add(level);
}
return ret;
}
}