二叉树的各种遍历以及写循环体的感想

关于如何写出正确的循环体

今天实现二叉树的时候,虽然是可以写出来,但是明显感到自己的循环体的设计并不熟练。马克思主义中说做事情都有方法论,虽然具体的事要具体分析,我觉得自己从二叉树的中序遍历的非递归算法设计的过程中,有了点关于循环体确定的方法。

  • 首先是一定要很清楚你要完成这件事,每一步是怎么走的。我们的逻辑的正确性,保持正确和清晰是重要条件。

  • 从我们的逻辑中提取有重复相同步骤的部分,可以考虑设计成一个循环结构,提取判断重复判断部分,也可以考虑设计成循环。

最好每次访问一个新数据的时候,先判断一下。这个判断往往会成为循环的判断条件。

二叉树各种遍历逻辑的代码实现

import java.io.BufferedReader;
import java.io.InputStreamReader;
import java.util.LinkedList;
import java.util.Queue;
import java.util.Scanner;
import java.util.Stack;
class TreeNode{
private String data;
private TreeNode leftNode;
private TreeNode rightNode;
public boolean hasVisited=false;//是否已经打印
public String getData() {
return data;
}
public void setData(String data) {
this.data = data;
}
public TreeNode getLeftNode() {
return leftNode;
}
public void setLeftNode(TreeNode leftNode) {
this.leftNode = leftNode;
}
public TreeNode getRightNode() {
return rightNode;
}
public void setRightNode(TreeNode rightNode) {
this.rightNode = rightNode;
}
}
public class Tree {
public static TreeNode root=new TreeNode();
/**
* 先序序列构造树,中序后序同理
* @param node
*/
public TreeNode createTree(TreeNode node){
String ch = new Scanner(System.in).nextLine();
if (ch.equals("#")) {
return null;
}
node = new TreeNode();
node.setData(ch);
node.setLeftNode(createTree(node.getLeftNode()));
node.setRightNode(createTree(node.getRightNode()));
return node;
}
//层次非递归建立二叉树,利用队列的先进先出特点。当然一定要用栈也可以,就要借助另外一个存储空间保留好节点,比较复杂。
public TreeNode createT(TreeNode node){
Queue queue = new LinkedList<>();//linkedList实现了队列的接口
TreeNode root;
String ch = new Scanner(System.in).nextLine();
if (ch.equals("#")) {
return null;
}
node = new TreeNode();
root = node;//保留下树根。
node.setData(ch);
queue.offer(node);//第一个根节点入队,因为循环里是不断地把左孩子和右孩子入队,根节点不是任何节点的左孩子右孩子,所以单独入队。
TreeNode currentNode;
while((queue.size()>0)&&(currentNode = (TreeNode)queue.poll())!=null){//队列的弹出操作,就是返回最开始的那个节点。(就是这样通过队列记录节点的)
System.out.println("输入左孩子");
ch = new Scanner(System.in).nextLine();
if (!ch.equals("#")) {
node = new TreeNode();
node.setData(ch);
currentNode.setLeftNode(node);
queue.offer(node);
}
System.out.println("输入右孩子");
ch = new Scanner(System.in).nextLine();
if (!ch.equals("#")) {
node = new TreeNode();
node.setData(ch);
currentNode.setRightNode(node);
queue.offer(node);
}
}
return root;//返回树根
}
/**
* 先序递归遍历树,中序后序同理
* @param node
*/
public void readTree1(TreeNode root){
if(root==null){
return;
}
System.out.println(root.getData());
readTree1(root.getLeftNode());
readTree1(root.getRightNode());
}
/**
* 中序列非递归实现。主要是要明白使用什么数据结构实现回来上一步(栈的特点),然后弄懂循环体究竟是什么。
* @param root
*/
public void readTree2(TreeNode node){
Stack stack = new Stack<>();
TreeNode currentNode= node;
while(currentNode!=null||stack.size()>0){
while(currentNode!=null){
stack.push(currentNode);
currentNode = currentNode.getLeftNode();
}
currentNode = (TreeNode)stack.pop();
System.out.println(currentNode.getData());
currentNode = currentNode.getRightNode();
}
}
/**
* 后序非递归遍历二叉树。
*/
public void readTree3(TreeNode node){
Stack stack = new Stack<>();
TreeNode currentNode= node;
while(currentNode!=null||stack.size()>0){
while(currentNode!=null){
stack.push(currentNode);
currentNode = currentNode.getLeftNode();
}
currentNode = (TreeNode)stack.pop();//弹出栈顶元素。
if(currentNode.hasVisited == false){
currentNode.hasVisited=true;
stack.push(currentNode);
currentNode = currentNode.getRightNode();
}else{
System.out.println(currentNode.getData());
currentNode = null;//为了能够pop();
}
}
}
public static void main(String[] args) {
Tree tree = new Tree();
root = tree.createT(root);
tree.readTree3(root);
}
}