前序
根左右
需要先压入根,取出,然后依次压入 右节点 ,左节点,再取出。。
package testjvm;
/**
* @Classname 二叉树
* @Description TODO
* @Date 2021/3/13 20:43
* @Created by wangxutao
*/
import java.util.*;
class tree_Node{
//定义 节点
public tree_Node() {
}
int value;
tree_Node left=null;
tree_Node right = null;
public tree_Node(int value, tree_Node left, tree_Node right) {
this.value = value;
this.left = left;
this.right = right;
}
public tree_Node(int value) {
this.value = value;
}
}
public class 二叉树 {
//前序遍历,先压入右边,因为先弹出 左边
public static void main(String[] args) {
//测试
二叉树 er = new 二叉树();
tree_Node n=new tree_Node(100);
n.left=new tree_Node(90);
n.right=new tree_Node(80);
n.left.left = new tree_Node(70);
n.left.right = new tree_Node(60);
er.preOrder(n);
}
void preOrder(tree_Node root) {
Stack<tree_Node> stack = new Stack<>();
if (root != null) {
stack.push(root); //压入根
}
while (!stack.isEmpty()) {
root = stack.pop();
visit(root);
if (root.right != null) {
stack.push(root.right);
}
if (root.left != null) {
stack.push(root.left);
}
}
}
void visit(tree_Node tree_Node) {
System.out.println(tree_Node.value);
}
//后续遍历 那么可以把后序当作:根->右->左,然后再反转一下即可。
// 申请两个栈s1、s2,先将头节点入栈s1。从s1中弹出栈顶节点记为cur,然后依次将cur的左孩子和右孩子压入s1。
// 在这过程中每一个从s1中弹出的节点均压入s2。当s1为空后,从s2中依次弹出的节点便是后序遍历的次序。
// 主要就是利用两个栈来进行“倒腾“,压入s2的顺序为中、右、左,弹出的顺序就变成了左、右、中。
void postOrder(tree_Node tree_Node) {
}
}
中序
void middleOrder(Node node) {
if (node == null) {
return;
}
Node curnode =node;
Stack<Node> stack = new Stack<>();
while (!stack.isEmpty() || curnode!=null) {
//所有左节点入栈
while (curnode != null) {
stack.push(curnode);
curnode = curnode.left;
}
//弹出左节点,入栈右节点
curnode = stack.pop();
visit(curnode);
// 弹出后,指向当前节点的右节点
curnode=curnode.right;
}
}
后序
简单版(两个栈)
申请两个栈s1、s2,先将头节点入栈s1。从s1中弹出栈顶节点记为cur,然后依次将cur的左孩子和右孩子压入s1。在这过程中每一个从s1中弹出的节点均压入s2。当s1为空后,从s2中依次弹出的节点便是后序遍历的次序。
主要就是利用两个栈来进行“倒腾“,压入s2的顺序为中、右、左,弹出的顺序就变成了左、右、中。
void postOrder(Node node) {
if (node == null) {
return;
}
Node curnode =node;
Stack<Node> stack = new Stack<>();
Stack<Node> stack2 = new Stack<>();
stack.push(curnode);
while (!stack.isEmpty() ) {
curnode = stack.pop();
stack2.push(curnode);
if (curnode.left != null) {
stack.push(curnode.left);
}
if (curnode.right != null) {
stack.push(curnode.right);
}
}
while (!stack2.isEmpty()) {
Node pop = stack2.pop();
visit(pop);
}
}
申请一个栈,将头节点压入栈。
现在我们思考一下:当遍历到一个节点时,如何判断这次遍历是打印该点,还是先处理它的孩子呢?
有以下几种情况:
该节点的左右孩子皆为空,即该节点为叶子节点,那么这次遍历就是打印该点。
如果上一次打印的节点为该节点的右孩子,说明该节点的子树处理完毕,这次遍历就是打印该点。
如果上一次打印的节点为该节点的左孩子,且该节点的右孩子为空,说明该节点的子树处理完毕,这次遍历就是打印该点。
否则说明子树没有被访问过,按照右孩子、左孩子的顺序入栈。
void PosOrderUnRecur(Node* head)
{
if (head)
{
stack<Node*> stack;
stack.push(head);
Node* last = nullptr;
Node* top;
while (!stack.empty())
{
top = stack.top();
if ((top->left == nullptr && top->right == nullptr) || // 叶子节点
(top->right == nullptr && last == top->left) || // 上个访问为左孩子,且右孩子为空
last == top->right) // 上个访问为右孩子
{
cout << top->value << " ";
last = top;
stack.pop();
}
else
{
if (top->right)
stack.push(top->right);
if (top->left)
stack.push(top->left);
}
}
}
}