二叉树是每个结点最多有两个子树的树结构。遍历二叉树就是按一定的规则和顺序走遍二叉树的所有结点,使每一个结点都被访问一次,而且只被访问一次。而二叉树的遍历有三种遍历方法:先序遍历(Preorder Traversal),中序遍历(Inorder Traversal),后序遍历(Postorder Traversal)。
设L、D、R分别表示左子树、根结点和右子树。则DLR(先根次序遍历),LDR(中根次序遍历),LRD(后根次序遍历)。
代码实现:
public class BinaryTreeNode{ int value; BinaryTreeNode left; BinaryTreeNode right; public BinaryTreeNode(int data,BinaryTreeNode leftNode,BinaryTreeNode rightNode){ this.value=data; this.left=leftNode; this.right=rightNode; } }
采用递归实现遍历
public class Solution{ //前序遍历 Preorder Traversal public static void preorderTraversal(BinaryTreeNode node){ if(node!=null){ System.out.print(node.value); preorderTraversal(node.left); preorderTraversal(node.right); } } //中序遍历 Inorder Traversal public static void inorderTraversal(BinaryTreeNode node){ if(node!=null){ inorderTraversal(node.left); System.out.print(node.value); inorderTraversal(node.right); } } //后序遍历 Postorder Traversal public static void postorderTraversal(BinaryTreeNode node){ if(node!=null){ postorderTraversal(node.left); postorderTraversal(node.right); System.out.print(node.value); } } public static void main(String[] args){ BinaryTreeNode node4=new BinaryTreeNode (4,null,null); BinaryTreeNode node5=new BinaryTreeNode (5,null,null); BinaryTreeNode node6=new BinaryTreeNode (6,null,null); BinaryTreeNode node7=new BinaryTreeNode (7,null,null); BinaryTreeNode node2=new BinaryTreeNode (2,node4,node5); BinaryTreeNode node3=new BinaryTreeNode (3,node6,node7); BinaryTreeNode node1=new BinaryTreeNode (1,node2,node3); System.out.println("前序遍历"); preorderTraversal(node1); System.out.println(); System.out.println("中序遍历"); inorderTraversal(node1); System.out.println(); System.out.println("后序遍历"); postorderTraversal(node1); } }
采用非递归实现遍历(使用栈来保存需要返回后处理的结点)
前序遍历:
1)如果当前结点存在,则处理当前结点的值(先处理根结点的值),然后将当前结点入栈,当前结点指向左子结点,并对该左子结点(此时的当前结点)进行相同处理。重复1的操作。
2)当前结点不存在,当前结点指向栈顶元素,栈顶元素出栈,当前结点指向右子结点,并对该右子结点(此时的当前结点)进行相同的处理。重复1的操作。
代码实现:
public void preorderTraversal(BinaryTreeNode node){ //定义一个栈,存放结点,栈顶元素是当前结点 Stack stack=new Stack(); BinaryTreeNode curNode=node; //当前结点不为null或栈不为空时,一直循环 while(curNode!=null||!stack.empty()){ //该结点不为null if(curNode!=null){ //显示该结点的值 System.out.print(curNode.value); //将该结点入栈 stack.push(curNode); //将当前结点指向下一个左子结点 curNode=curNode.left; }else{ //如果curNode==null 则从stack中获取栈顶元素,即当前结点 curNode=(BinaryTreeNode)stack.peek(); //当前结点出栈 stack.pop(); //将当前结点指向下一个右子结点 curNode=curNode.right; } } }
中序遍历:
1)如果当前结点存在,则将当前结点入栈,指向左子结点,并将该左子结点(此时的当前结点)进行相同处理。重复1的操作。
2)如果当前结点不存在,当前结点指向栈顶元素,栈顶元素出栈,处理当前结点值(因为左子结点不存在或者已经处理完了),指向右子结点,并对该右子结点(此时的当前结点)进行相同处理。重复1的操作。
代码实现:
public void inorderTraversal(BinaryTreeNode node){ //定义一个栈,存放结点 Stack stack=new Stack(); BinaryTreeNode curNode=node; //如果curNode不为null或者stack不为空,则一直循环 while(curNode!=null||!stack.empty()){ if(curNode!=null){ //将该结点入栈 stack.push(curNode); //将当前结点指向下一左子结点 curNode=curNode.left(); }else{ //当前结点为null,则将当前结点指向栈顶元素 curNode=(BinaryTreeNode)stack.peek(); //处理当前结点的值 System.out.print(curNode.value); //出栈 statck.pop(); //将当前结点指向下一右子结点 curNode=curNode.right; } } }
后序遍历:
1)如果当前结点存在,则当前结点入栈,当前结点指向下一左子结点,标识0入栈,并对该左子结点(此时的当前结点)进行相同处理。重复1的操作。
2)当前结点不存在,当前结点指向栈顶元素,栈顶元素出栈,标识位出栈。如果标识位为0,则当前结点入栈,指向右子结点,标识1入栈。并对该右子结点(此时的当前结点)进行步骤1的处理,重复1的操作;如果标识位为1,则说明处理过了左右子结点,此时处理当前结点的value,继续对栈顶元素进行相同处理(当前结点置空,重复步骤2,重复2的操作)。
代码实现:
public void postorderTraversal(BinaryTreeNode){ //保存需要返回处理的结点 Stack sTree=new Stack(); //保存返回的路径标识 Stack sFlag=new Stack(); BinaryTreeNode curNode=node; while(curNode!=null||!sTree.empty()){ if(curNode!=null){ //当前结点入栈 sTree.push(curNode); //下一步处理左子结点,返回时从左子结点返回,保存标识为0 sFlag.push(0); //指向左子结点,进行步骤1操作 curNode=curNode.left; }else{ //当前结点指向栈顶元素 curNode=(BinaryTreeNode)sTree.peek(); //结点出栈 sTree.pop(); //获取返回路径 int flag=((Integer)sFlag.peek()).intValue(); //标识出栈 sFlag.pop(); if(flag==0){ //从左子结点返回,此时应该处理右子结点 //当前结点入栈 sTree.push(curNode); //下一步处理右子结点,保存标识1 sFlag.push(1); //指向右子结点,进行步骤1的处理 curNode=curNode.right; }else{ //从右子结点返回,此时应该处理根结点的值 System.out.print(curNode.value); //为了进行步骤2,根据循环逻辑,这里将当前结点置空 curNode=null; } } } }
posted on
浙公网安备 33010602011771号