2019-08-04-二叉树遍历算法

  • 1,前序遍历
  • 2,中序遍历
  • 3,后序遍历
  • 4,队列层级遍历
  • 5,计算二叉树节点数

一,首先定义一个二叉树的节点

public class Node {
    public String key;
    public Node left;
    public Node right;

    public Node(String key) {
        this.key = key;
    }

    public Node(String key, Node left, Node right) {
        this.key = key;
        this.left = left;
        this.right = right;
    }
}

二,构建一颗树

public class Tree {
    /**
     * 构造树
     */
    public static Node init() {
        Node a = new Node("a");//一个二叉树的节点
        Node b = new Node("b", a, null);//将a节点作为b节点的左节点
        Node c = new Node("c");
        Node d = new Node("d", b, c);
        Node e = new Node("e");
        Node f = new Node("f", e, null);
        Node g = new Node("g", null, f);
        Node h = new Node("h", d, g);
        return h;
    }

}

三,递归的实现遍历

说明:先序遍历,中序遍历和后序遍历都是相对于根节点来说的,而左子树和右子树的遍历顺序一定是先左后右

1,前序遍历

/**
 * 递归实现前序遍历
 * 遍历顺序是根节点-左子树-右子树
 * h, d, b, a, c, g, f, e
 */
public static void leftRecursive(Node node) {
    if (node != null) {
        visit(node);
        leftRecursive(node.left);
        leftRecursive(node.right);
    }
}

2,中序遍历

/**
 * 递归实现中序遍历
 * 遍历顺序是左子树-根节点-右子树
 * d,
 */
public static void centerRecursive(Node node) {
    if (node != null) {
        centerRecursive(node.left);
        visit(node);
        centerRecursive(node.right);
    }
}

3,后序遍历

/**
 * 递归实现后序遍历
 * 遍历顺序是左子树-右子树-根节点
 */
public static void rightRecursive(Node node) {
    if (node != null) {
        rightRecursive(node.left);
        rightRecursive(node.right);
        visit(node);
    }
}

四,非递归的方式

1,前序遍历

/**
 * 栈 特点后进的先出 即先访问的后进栈
 * 对于每一个节点的来说访问的顺序都应该是根左右
 * hdbacgfe
 * @param node
 */
public static void leftUnRecursiveStack(Node node) {
    Stack stack = new Stack();
    if(node != null) {
        stack.push(node);
        while (!stack.empty()) {
            node = stack.pop();
            visit(node);
            if(node.right != null) {
                stack.push(node.right);
            }
            if(node.left != null) {
                stack.push(node.left);
            }
            //为什么p.getLeft() 在后,getRight()在前应为while 循环第一句就是pop visit所以要把left放上,先访问。之中方法是即压即访问法。
            //此处是由于栈的特点决定的
        }
    }
}
public static void leftUnRecursiveStack2(Node node) {
    Stack stack = new Stack();
    while (node != null || stack.size() > 0) {
        while (node != null) {
            visit(node);
            stack.push(node);
            node = node.left;
        }
        if(stack.size() > 0) {
            node = stack.pop();
            node = node.right;
        }
    }
}

2,中序遍历

 /**
 * 栈 特点后进的先出 左根右
 * 因此这里的思路应该是先将右子树的节点放入栈中-根节点-左子树节点
 * 对于每一个节点的来说访问的顺序都应该是左根右
 * a,b,d,c,h,g,e,f
 * feghcdba
 * @param node
 */
public static void centerUnRecursiveStack(Node node) {
    Stack stack = new Stack();
    while (node != null || stack.size() > 0) {
        //左子树入栈
        while (node != null) {
            stack.push(node);
            node = node.left;
        }
        if (stack.size() > 0) {
            node = stack.pop();
            visit(node);
            node = node.right;
        }
    }
}

3,后序遍历

/**
 * 左右根
 * 对于每一个节点的来说访问的顺序都应该是左右根
 * //栈 特点后进的先出
 * abcdefgh
 * @param node
 */
public static void rightUnRecursiveStack(Node node) {
    Stack stack = new Stack();
    Node t = node;
    while (node != null) {
        // 左子树入栈
        while (node.left != null) {
            stack.push(node);
            node = node.left;
        }
        // 当前节点无右子或右子已经输出
        while (node != null && (node.right == null || node.right == t)) {
            visit(node);
            t = node;// 记录上一个已输出节点
            if (stack.empty())
                return;
            node = stack.pop();
        }
        // 处理右子
        stack.push(node);
        node = node.right;
    }
}

五,层序遍历

/**
 * 使用队列进行层次访问
 * @param node
 */
public static void leftUnRecursiveQueue(Node node) {
    Queue queue = new ArrayDeque<>();
    if(node != null) {
        queue.offer(node);
        while (!queue.isEmpty()) {
            node = queue.poll();
            visit(node);
            if(node.left != null) {
                queue.offer(node.left);
            }
            if(node.right != null) {
                queue.offer(node.right);
            }
        }
    }
}

六,求树点的层级

1,递归的实现方式

public static int countTree(Node node) {
    if(node == null) {
        return 0;
    } else {
       return countTree(node.left) + countTree(node.right) + 1;
    }
}

2,非递归的实现方式

/**
 * 求出二叉树深度的递归算法
 * @param root
 * @return
 * 思路:若一一棵二叉树为空,那么它的深度为0,否则它的深度等于左子树和右子树中的最大深度+1
 */
public static int depthBTree(Node root) {
    if(root == null) {
        return 0;
    }else {
        int dep1 = depthBTree(root.left);
        int dep2 = depthBTree(root.right);
        if(dep1 > dep2) {
            return dep1 + 1;
        }else {
            return dep2 + 1;
        }
    }
}

七,查找节点

/**
 * 查找节点
 * @param root
 * @param x
 * @return
 */
public static Node findBTree(Node root, Object x) {
    if(root == null) {
        return null;
    }else {
        if(root.key.equals(x)) {
            return root;
        } else {
            Node o = findBTree(root.left, x);
            if(o != null) {
                return o;
            }
            o = findBTree(root.right, x);
            if(o != null) {
                return o;
            }
        }
        return null;
    }
}

你可能感兴趣的:(2019-08-04-二叉树遍历算法)