java 树的遍历非递归实现
public class TreeToSequence {
public int[][] convert(Node root) {
//特殊输入
if (root == null) {
return null;
}
//由于树的结点数目不知道,因此遍历过的结点只能存放在集合list中,之后再转存到数组中
List<Node> preOrderList = new ArrayList<Node>();
List<Node> inOrderList = new ArrayList<Node>();
List<Node> afterOrderList = new ArrayList<Node>();
//对以root为根结点的二叉树进行遍历,将遍历过的结点依次放入到preOrderList中
this.preOrder(root, preOrderList);
this.inOrder(root, inOrderList);
this.afterOrder(root, afterOrderList);
//创建一个二维数组用于返回结果
int[][] results = new int[3][preOrderList.size()];
//集合list不能直接转化为int[]数组,因此要遍历集合取出元素放入到数组中
//注意细节:get(i)得到的是结点对象,而返回的是节点的值
for (int i = 0; i < preOrderList.size(); i++) {
results[0][i] = preOrderList.get(i).getDate();
results[1][i] = inOrderList.get(i).getDate();
results[2][i] = afterOrderList.get(i).getDate();
}
//不要忘记返回结果
return results;
}
/**
* 对以root为根结点的二叉树进行先序遍历,将遍历过的结点依次放入到preOrderList中
*/
private void preOrder(Node root, List<Node> preOrderList) {
//①创建一个栈,菱形符
Stack<Node> stack = new Stack<>();
//②创建指针cur表示当前正在访问的结点,初始值为root
Node cur = root;
//③将根结点放入栈中
stack.push(cur);
//④循环,弹栈--右左结点入栈--弹栈……
while (!stack.isEmpty()) {
//从栈顶弹出一个结点node
cur = stack.pop();
//弹出的元素就是当前遍历的元素,将其放入到集合中
preOrderList.add(cur);
//如果弹出元素node有右元素,则入栈
if (cur.getRightChild() != null) {
stack.push(cur.getRightChild());
}
//如果弹出元素node有左元素,则入栈
if (cur.getLeftChild() != null) {
stack.push(cur.getLeftChild());
}
}
}
/**
* 对以root为根结点的二叉树进行中序遍历,将遍历过的结点依次放入到inOrderList中
*/
private void inOrder(Node root, List<Node> inOrderList) {
//①创建一个栈用来存放结点
Stack<Node> stack = new Stack<>();
//②创建变量指针cur表示当前正在访问的结点,cur初始值为root
Node cur = root;
//③将根结点放入栈中
stack.push(cur);
//④循环:当stack不为空就继续循环
while (!stack.isEmpty()) {
//⑤循环,如果左结点不为null就将结点放入栈中
while (cur != null) {
//先取左结点再放入栈中
cur = cur.getLeftChild();
//注意这里cur!=null并不表示cur.left!=null,因此要重新判断,只有left不为null才放入栈中,否则结束循环
if (cur != null) {
stack.push(cur);
}
}
//当左结点为null,即左结点遍历完成后
//从栈中弹出结点,这就是当前遍历的结点,放入集合
cur = stack.pop();
inOrderList.add(cur);
//取弹出结点的右结点,判断是否为null,如果不为null则同root一样放入stack中
cur = cur.getRightChild();
if (cur != null) {
stack.push(cur);
}
//如果有结点为null,则通过循环继续弹出结点再取有右结点即可,直到stack为空
}
}
/**
* 对以root为根结点的二叉树进行后序遍历,将遍历过的结点依次放入到afterOrderList中
*/
private void afterOrder(Node root, List<Node> afterOrderList) {
//①创建2个栈用于存放结点
Stack<Node> stack1 = new Stack<>();
Stack<Node> stack2 = new Stack<>();
//②创建临时变量cur表示当前正在变量的结点,初始值为root
Node cur = root;
//③将根结点先放入栈中
stack1.push(cur);
//④循环--逻辑类似先序遍历
while (!stack1.isEmpty()) {
//先弹出栈顶元素,放入stack2
cur = stack1.pop();
stack2.push(cur);
//再将其左、右结点放入栈中
if (cur.getLeftChild() != null) {
stack1.push(cur.getLeftChild());
}
if (cur.getRightChild() != null) {
stack1.push(cur.getRightChild());
}
}
//此时树的结点都在stack2中,将其放入到集合中
while (!stack2.isEmpty()) {
afterOrderList.add(stack2.pop());
}
}
}