二叉树的实现以及遍历——递归以及非递归(栈实现)
二叉树的定义
二叉树是一种特殊的树形结构,其特点为每个节点最后两个子节点(即在二叉树中不存在度>2的结点,其中度即节点的子节点数)。且二叉树具有左右之分,次序不可颠倒。
二叉树的链式实现
public class Node {
// 存放数据
private int data;
// 左子节点
private Node left;
// 右子结点
private Node right;
private Node() {
}
private Node(int data) {
this.data = data;
}
private Node(Node left, Node right) {
this.left = left;
this.right = right;
}
}
print(Queue q)方法:
输出访问的结点,用于测试是否完整
public static void print(Queue<Node> queue) {
while (!queue.isEmpty()) {
System.out.print(queue.poll().data + " ");
}
}
二叉树的遍历
1、先序遍历
二叉树先序遍历操作如下:
若二叉树为空,则退出;否则做以下操作:
- 访问根节点
- 先序遍历左子树
- 先序遍历右子树
即简单记为:根-左-右。
使用递归实现如下:
public static void preOrder(Node node) {
if (null == node) {
return;
}
System.out.print(node.data + " ");
if (null != node.left) {
preOrder(node.left);
}
if (null != node.right) {
preOrder(node.right);
}
}
使用非递归:
使用栈的方式,则入队顺序需要为根左右,那么入栈顺序为根右左,先弹出父结点元素,再入栈右子结点,然后入栈左子节点。如此访问栈的弹出顺序即为先序遍历的根左右顺序
public static void preStack(Node root) {
if (null == root) {
return;
}
Stack<Node> st = new Stack<>();
Queue<Node> outQueue = new ArrayDeque<>();
st.push(root);
while (!st.isEmpty()) {
Node node = st.pop();
// 访问根节点
outQueue.add(node);
// 入栈右子结点,后访问右子树
if (null != node.right) {
st.push(node.right);
}
// 入栈左子节点,先访问左子树
if (null != node.left) {
st.push(node.left);
}
}
// 打印队列
print(outQueue);
}
2、中序遍历
二叉树中序遍历操作如下:
若二叉树为空则退出;否则执行如下操作:
- 中序遍历左子树
- 访问根节点
- 中序遍历右子树
即简单记为:左-根-右。
使用递归实现如下:
public static void midOrder(Node node) {
if (null == node){
return;
}
if (null != node.left) {
midOrder(node.left);
}
System.out.print(node.data + " ");
if (null != node.right) {
midOrder(node.right);
}
}
非递归实现如下:
public static void midStack(Node root) {
if (null == root) {
return;
}
Stack<Node> st = new Stack<>();
Queue<Node> outQueue = new ArrayDeque<>();
Node node = root;
while (!st.isEmpty() || node != null) {
if (node != null) {
// 上一次循环中的结点不为空,即上一个节点的左子节点非空
// 循环找到左子树的最左子节点
st.push(node);
// 循环找左子节点 直到左节点为空
node = node.left;
} else {
// 左节点为空,弹出栈顶元素,访问结点
node = st.pop();
outQueue.add(node);
// 访问右子树
node = node.right;
}
}
print(outQueue);
}
3、后序遍历
二叉树的后序遍历操作如下:
若二叉树为空则退出;否则执行:
- 后序遍历左子树
- 后序遍历右子树
- 访问根节点
即简单记为:左-右-根。
使用递归实现如下:
public static void postOrder(Node node) {
if (null == node) {
return;
}
if (null != node.left) {
postOrder(node.left);
}
if (null != node.right) {
postOrder(node.right);
}
System.out.print(node.data + " ");
}
非递归实现:
使用非递归方式实现后序遍历,首先需要访问根节点,将根节点压入输出栈里面,从访问栈中弹出的结点显示右子树,再是左子树。然后将右子树压入输出栈,再将左子树压入输出栈。如此输出栈的入栈顺序为根右左,则出战顺序即为后序遍历顺序。
public static void postStack(Node root) {
if (null == root) {
return;
}
// 访问栈
Stack<Node> st = new Stack<>();
// 使用栈存储访问的数据 输出栈
Stack<Node> out = new Stack<>();
st.push(root);
while (!st.isEmpty()) {
Node node = st.pop();
// 访问根节点
out.push(node);
// 入栈左子树,后访问左节点
if (null != node.left) {
st.push(node.left);
}
// 入栈右子树,先访问右节点子树
if (null != node.right) {
st.push(node.right);
}
}
// 打印栈
while (!out.isEmpty()) {
System.out.print(out.pop().data + " ");
}
}