他们都是一种深度遍历方式
一:前序遍历
遍历方式为:根+左子树的前序+右子树的前序
递归方法:利用递归方法,先打印根节点,再递归遍历左子树的前序,最后递归调用有右子树的前序,如果它的根节点为空时,直接返回null
//前序遍历,法1
public static void preOrderTraversal(Node root){
if(root==null){
return;
}
System.out.print(root.value);
preOrderTraversal(root.left);
preOrderTraversal(root.right);
}
//前序遍历,法2
public static List<Character> preorder(Node root){
if(root==null){
return new ArrayList<>();
}
List<Character> list=new ArrayList<>();
List<Character> leftOrder=preorder(root.left);
List<Character> rightOrder=preorder(root.right);
list.add(root.value);
list.addAll(leftOrder);
list.addAll(rightOrder);
return list;
}
非递归实现:利用栈来实现,利用栈的先进后出实现。
1.当栈不为空或者结点不为空时进行循环,再当结点不为空时,先找到根节点打印出来,再放到栈里面,
2.找它的左节点进行打印并放进栈里面去,直到左节点为空时,跳出结点不为空的循环,弹出栈顶元素,找它的右结点,在进行循环
3.当栈为空时,并且没有接点时,循环结束
//非递归先序遍历
public static void preorder(Node root){
Stack<Node> stack=new Stack<>();
Node cur=root;
while(!stack.isEmpty()||cur!=null){
while(cur!=null){
System.out.print(cur.value);
stack.push(cur);
cur=cur.left;
}
Node top=stack.pop();
cur=top.right;
}
}
二:中序遍历
遍历方式为:左子树的中序+ 根 + 右子树的中序
递归方法:利用递归方法,先递归遍历左子树的中序,再打印根节点,最后递归调用右子树的中序,如果它的根节点为空时,直接返回null
//中序遍历,法1
public static void inOrderTraversal(Node root){
if(root==null){
return;
}
inOrderTraversal(root.left);
System.out.print(root.value);
inOrderTraversal(root.right);
}
//中序遍历,法2
public static List<Character> inorder(Node root){
if(root==null){
return new ArrayList<>();
}
List<Character> list=new ArrayList<>();
List<Character> leftOrder=inorder(root.left);
List<Character> rightOrder=inorder(root.right);
list.addAll(leftOrder);
list.add(root.value);
list.addAll(rightOrder);
return list;
}
非递归方法:和前序遍历相似
//非递归中序遍历
public static void inorder(Node root){
Stack<Node> stack=new Stack<>();
Node cur=root;
while(!stack.isEmpty()||cur!=null){
while(cur!=null){
stack.push(cur);
cur=cur.left;
}
Node top=stack.pop();
System.out.print(top.value);
cur=top.right;
}
}
三:后序遍历
遍历方式为:左子树的后序+ 右子树的后序+根
递归方法:利用递归方法,先递归遍历左子树的后序,再递归调用右子树的后序,再打印根节点如果它的根节点为空时,直接返回null
//后序遍历,法1
public static void postOrderTraversal(Node root){
if(root==null){
return;
}
postOrderTraversal(root.left);
postOrderTraversal(root.right);
System.out.print(root.value);
}
//后序遍历,法2
public static List<Character> postorder(Node root){
if(root==null){
return new ArrayList<>();
}
List<Character> list=new ArrayList<>();
List<Character> leftOrder=postorder(root.left);
List<Character> rightOrder=postorder(root.right);
list.addAll(leftOrder);
list.addAll(rightOrder);
list.add(root.value);
return list;
}
非递归方法:和前序相似,但是要设一个last记录弹出栈的最后一个元素,还要判断结点的右节点是否为空或者已经访问过右节点了,才能将该节点弹出栈并进行打印,可根据代码进行理解
//非递归后序遍历
public static void postorder(Node root){
Stack<Node> stack=new Stack<>();
Node cur=root;
Node last=null;
while(!stack.isEmpty()||cur!=null){
while(cur!=null){
stack.push(cur);
cur=cur.left;
}
Node top=stack.peek();
if(top.right==null||top.right==last){
stack.pop();
System.out.print(top.value);
last=top;
}
else{
cur=top.right;
}
}
}
最后补充:前、中、后序的遍历方法都很相似,具体也可自己构建一棵树进行遍历,理解方法。
同时:一定要理解递归方法
递推方法的一些诀窍:
1.不要写方法的就做递归展开,站在自己的角度思考,先不用管其他结点
2.找终止条件,在变化的因素中确定,也就是形参
3.找向下的递推公式
4.理解递归方法的调用过程中,会被调用很多次
5.理解调用过程中,局部变量会有多份,只是名字一样