二叉树遍历
二叉树遍历:按照某种规则对二叉树中的每个节点进行操作(例如:打印节点中的内容||给节点中的值域+1),并且每个节点只遍历一次。
*如果要遍历一棵二叉树,实际只需要将根节点+根的左子树+根的右子树
- NLR:前序遍历(Preorder Teaversal也叫先序遍历)——访问根结点的操作发生在遍历其左右子树之前。
根节点——》根的左子树——》根的右子树 - LNR:中序遍历(Inorder Traversal)——访问根结点的操作发生在遍历其左右子树之中(间)。
根的左子树——》根节点——》根的右子树 - LRN:后序遍历(Postorder Traversal)——访问根结点的操作发生在遍历其左右子树之后。
根的左子树——》根的右子树——》根节点
由于被访问的结点必是某子树的根,所以N(Node)、L(Left subtree)和R(Right subtree)又可解释为根、根的左子树和根的右子树。
前序遍历:根节点—> 根的左子树 —>根的右子树
//递归
public void preOrder(BTNode root){
if(null!=root){
System.out.print(root.val+" ");
preOrder(root.left);
preOrder(root.right);
}
}
非递归遍历:
(1)非递归前序遍历需要借助栈,利用栈先进后出的特性
方法:
- 如果是空树,直接返回
- 如果非空
++将根节点入栈
++(1)取栈顶元素——cur peek();
++(2)遍历该元素
++(3)删除栈顶元素
++(4)如果cur的右子树存在,将右子树入栈
++(5)如果cur的左子树存在,将左子树入栈
++(6)重复1到5的操作,直至stack为空,遍历完成
(2)根据前序遍历的规则:根 左 右
方法:
- 如果是空树,则返回空
- 如果非空
++将根节点入栈
++(1)遍历栈顶cur元素
++(2)弹出cur
++(3)如果cur有右子树时,保持右子树
++(4)顺着cur的左侧的路径一直往下遍历
++(5)重复1到4,直至stack为空,遍历完成
//非递归
public void preOrderNor1(){
if(null==root){
return ;
}
Stack<BTNode> s=new Stack<>();
s.push(root);
while(!s.empty()){
BTNode cur=s.peek();
System.out.print(cur.val+" ");
s.pop();
if(null!=cur.right){
s.push(cur.right);
}
if(null!=cur.left){
s.push(cur.left);
}
}
System.out.println();
}
public void preOrderNor2(){
if(null==root){
return ;
}
Stack<BTNode> s=new Stack<>();
s.push(root);
while(!s.empty()){
BTNode cur=s.peek();
s.pop();
while(null!=cur){
//顺着cur左侧的路径一直往下遍历,并保存所经路径中的所有右子树
System.out.print(cur.val+" ");
if(null!=cur.right){
s.push(cur.right);
}
cur=cur.left;
}
}
}
中序遍历:根的左子树 —>根节点—> 根的右子树
//递归
public void inOrder(BTNode root){
if(null!=root){
inOrder(root.left);
System.out.print(root.val+" ");
inOrder(root.right);
}
}
非递归遍历
非递归中序遍历:
- 如果是空树,则返回空。
- 如果非空
++(1)先找以cur为根的二叉树中最左侧的节点,并把途中所有cur压入栈中
++(2)当cur为空时,认为cur对应的树已经遍历。(获取当前栈顶元素,因为cur左子树为空,则认为cur的左子树已经遍历结束)
++(3)遍历当前根节点cur
++(4)遍历cur的右子树:null(不处理),若不为空则把右子树当成一个新的二叉树进行遍历(重复1到4,直至stack为空)
//非递归
public void inOrderNor(){
if(null==root){
return;
}
BTNode cur=root;
Stack<BTNode> s=new Stack<>();
while(null!=cur||!s.empty()){
while(null!=cur){
s.push(cur);
cur=cur.left;
}
cur=s.peek();
System.out.print(cur.val+" ");
s.pop();
cur=cur.right;
}
}
后序遍历:根的左子树 —> 根的右子树—>根节点
//递归
public void postOrder(BTNode root){
if(null!=root){
postOrder(root.left);
postOrder(root.right);
System.out.print(root.val+" ");
}
}
非递归遍历:
非递归后序遍历:
- 如果是空树,则返回null;
- 如果非空
++(1)找以cur为根的二叉树最左侧的节点,并保存途中所有根节点。
++(2)获取栈顶元素peek,拿着栈顶元素去寻找它的右子树
++(3)遍历栈顶元素的右子树,如果右子树为空,则弹出栈顶元素cur,并遍历cur;如果右子树=prev则表示右子树已经被遍历过了,也要弹出栈顶元素cur,并遍历cur;如果右子树不为空且没有遍历过,则把右子树当初一个新二叉树重复1到3进行遍历。
++(4)prev标注上一次遍历过的节点
//非递归
public void inOrderNor(){
Stack <BTNode> s=new Stack<>();
BTNode prev=null;
if(null==root){
return;
}
BTNode cur=root;
while(null!=cur||!s.empty()){
while(null!=cur){
s.push(cur);
cur=cur.right;
}
BTNode top=s.peek();
if(null==top.rigth||top.rigth==prev){
System.out.println(top.val+' ');
prev=top;
s.pop();
}
else {
cur=top.rigth;
}
}
}