在写剑指offer和LeetCode算法时,遇到了有关二叉树前中后序遍历的题目,之前一直使用递归写法,导致对非递归写法有点生疏了,在此记录一下。对于非递归写法,通常都是借助栈或队列等数据结构,在实现过程中一定要时刻牢记栈(先进后出)、队列(先进先出)等特性。再就是前(根左右)中(左根右)后(左右根)序遍历。
题目解答中用到的TreeNode类,定义如下:
public class TreeNode {
int val = 0;
TreeNode left = null;
TreeNode right = null;
public TreeNode(int val) {
this.val = val;
}
}
递归实现二叉树的前-中-后序遍历
//前序
public void preOrder(TreeNode node)
{
if (node != null)
{
System.out.print(node.element + " ");
preOrder(node.left);
preOrder(node.right);
}
}
//中序
public void inOrder(TreeNode node)
{
if (node != null)
{
preOrder(node.left);
System.out.print(node.element + " ");
preOrder(node.right);
}
}
//后序:
public void posOrder(TreeNode node)
{
if (node != null)
{
preOrder(node.left);
preOrder(node.right);
System.out.print(node.element + " ");
}
}
非递归实现二叉树的前-中-后序遍历
//前序:借助一个栈
public List<Integer> preorderTraversal(TreeNode root) {
List<Integer> res = new ArrayList<>();
if (root == null){
return res;
}
Stack<TreeNode> s = new Stack<>();
s.push(root);
while (!s.empty()){
TreeNode node = s.pop();
res.add(node.val);
if (node.right != null){
s.push(node.right);
}
if (node.left != null){
s.push(node.left);
}
}
return res;
}
//=========================================
//前序遍历2
public List<Integer> preorderTraversal(TreeNode root) {
List<Integer> res = new ArrayList<>();
if (root == null){
return res;
}
Stack<TreeNode> s = new Stack<>();
while (root != null || !s.empty()){
while(root != null){
res.add(root.val);
s.push(root);
root = root.left;
}
if(!s.empty()){
TreeNode t = s.pop();
root = t.right;
}
}
return res;
}
//中序:借助一个栈
public List<Integer> inorderTraversal(TreeNode root) {
List<Integer> res = new ArrayList<>();
if (root == null){
return res;
}
Stack<TreeNode> s = new Stack<>();
//循环1 2步骤直至栈为空且指针也为空
while (root != null || !s.empty()){
//1.不断往左子树深入并不断入栈
while (root != null){
s.push(root);
root = root.left;
}
//2.弹出栈顶元素,将值加入res,并将指针指向它的右孩子
if (!s.empty()){
root = s.pop();
res.add(root.val);
root = root.right;
}
}
return res;
}
//后序:后序遍历是 左右根,从右往左依次是根右左,先序遍历是根左右,考虑修改先序遍历之后再调整顺序。
public List<Integer> postorderTraversal(TreeNode root) {
LinkedList<Integer> res = new LinkedList<>();
if (root == null){
return res;
}
Stack<TreeNode> s = new Stack<>();
s.push(root);
TreeNode node = null;
while (!s.isEmpty()){
node = s.pop();
//注意使用的是头插法,这样的话实现逆序的过程
res.addFirst(node.val);
//根据栈 先进后出的特点,根右左,那么入栈的时候用先左再右
if (node.left != null){
s.push(node.left);
}
if (node.right != null){
s.push(node.right);
}
}
return res;
}
N叉树的定义
class Node {
public int val;
public List<Node> children;
public Node() {}
public Node(int _val) {
val = _val;
}
public Node(int _val, List<Node> _children) {
val = _val;
children = _children;
}
}
N叉树前、后序遍历的递归实现
//前序
public List<Integer> preorder(Node root) {
List<Integer> res = new ArrayList<>();
preOrderNT(root,res);
return res;
}
private void preOrderNT(Node node, List<Integer> res) {
if (node == null){
return;
}
res.add(node.val);
if (node.children.size() >0){
for (Node _node:node.children) {
preOrderNT(_node,res);
}
}
}
//后序
public List<Integer> postorder(Node root) {
List<Integer> res = new ArrayList<>();
postOrderNT(root,res);
return res;
}
private void postOrderNT(Node node, List<Integer> res) {
if (node == null){
return;
}
if (node.children != null && node.children.size() > 0){
for (Node _node:node.children) {
postOrderNT(_node,res);
}
}
res.add(node.val);
}
N叉树前、后序遍历的非递归实现
//前序
public List<Integer> preorder(Node root) {
List<Integer> res = new ArrayList<>();
if (root == null){
return res;
}
Stack<Node> s = new Stack<>();
s.push(root);
Node temp = null;
while (!s.isEmpty()){
temp = s.pop();
res.add(temp.val);
if (temp.children.size() >0){
for (int i = temp.children.size() -1;i>=0;i--){
//从右往左依次入栈
if (temp.children != null){
s.push(temp.children.get(i));
}
}
}
}
return res;
}
//后序
public List<Integer> postorder(Node root) {
List<Integer> res = new ArrayList<>();
if (root == null){
return res;
}
Stack<Node> s = new Stack<>();
s.push(root);
Node temp = null;
while (!s.isEmpty()){
temp = s.pop();
res.add(temp.val);
if (temp.children.size() >0){
for (Node _node:temp.children) {
s.push(_node);
}
}
}
//将res求逆,得到最后的结果
Collections.reverse(res);
return res;
}
java.util.Collections类中的reverse方法
private static final int REVERSE_THRESHOLD = 18;
public static void reverse(List<?> list) {
int size = list.size();
if (size < REVERSE_THRESHOLD || list instanceof RandomAccess) {
for (int i=0, mid=size>>1, j=size-1; i<mid; i++, j--)
swap(list, i, j);
} else {
// instead of using a raw type here, it's possible to capture
// the wildcard but it will require a call to a supplementary
// private method
ListIterator fwd = list.listIterator();
ListIterator rev = list.listIterator(size);
for (int i=0, mid=list.size()>>1; i<mid; i++) {
Object tmp = fwd.next();
fwd.set(rev.previous());
rev.set(tmp);
}
}
}
public static void swap(List<?> list, int i, int j) {
// instead of using a raw type here, it's possible to capture
// the wildcard but it will require a call to a supplementary
// private method
final List l = list;
l.set(i, l.set(j, l.get(i)));
}
java.util.List接口
interface List<E> extends Collection<E>
E set(int index, E element);