码迷,mamicode.com
首页 > 其他好文 > 详细

二叉树遍历和延伸

时间:2021-05-24 14:38:57      阅读:0      评论:0      收藏:0      [点我收藏+]

标签:-o   现在   his   toc   tle   数组   int   set   思考   

之前为了求快,认为递归和动态规划是一类的,导致做了不少递归的题只能想到思路,但就是没法代码实现出来!!!

现在学习二叉树,我觉得对学习递归真的很有帮助!

二叉树的基础:遍历二叉树

二叉树遍历是基础,如果我们不能遍历二叉树,又如何对二叉树的节点进行操作呢?

二叉树的节点:

/**
 * @author keboom
 * @date 2021/4/30
 */
public class Node {
    public int value;
    public Node left;
    public Node right;

    public Node(int data) {
        this.value = data;
    }

    /**
     *          10
     *     12        15
     *  4     7    5    18
     * @return
     */
    public static Node getTestTree() {
        Node node10 = new Node(10);
        Node node5 = new Node(5);
        Node node15 = new Node(15);
        Node node4 = new Node(4);
        Node node7 = new Node(7);
        Node node12 = new Node(12);
        Node node18 = new Node(18);

        node10.left = node12;
        node10.right = node15;
        node12.left = node4;
        node12.right = node7;
        node15.left = node5;
        node15.right = node18;

        return node10;
    }
}

getTestTree此方法为了方便测试,不用理会。

递归遍历

    public void preOrderRecur(Node head) {
        if (head == null) {
            return;
        }
        System.out.println(head.value + " ");
        preOrderRecur(head.left);
        preOrderRecur(head.right);
    }

    public void inOrderRecur(Node head) {
        if (head == null) {
            return;
        }
        inOrderRecur(head.left);
        System.out.println(head.value + " ");
        inOrderRecur(head.right);
    }

    public void posOrderRecur(Node head) {
        if (head == null) {
            return;
        }
        posOrderRecur(head.left);
        posOrderRecur(head.right);
        System.out.println(head.value + " ");
    }

以上分别为先序,中序和后序遍历。

我认为这三种遍历的区别:

  • 先序遍历:先打印,再向下递归

  • 中序和后序:先递归到最下面,再打印

只看简单的遍历太简单不直观,请看下面的几道题

接下里的几道题目在求解过程中我会跟二叉树的遍历做一些联系,我认为做这些联系是有助于解题的??

非递归遍历

    public void preOrderUnRecur(Node head) {
        System.out.println("pre-order: ");
        if (head != null) {
            Stack<Node> stack = new Stack<>();
            stack.add(head);
            while (!stack.isEmpty()) {
                head = stack.pop();
                System.out.print(head.value + " ");
                if (head.right != null) {
                    stack.push(head.right);
                }
                if (head.left != null) {
                    stack.push(head.left);
                }
            }
        }
        System.out.println();
    }

    public void inOrderUnRecur(Node head) {
        System.out.println("in-order: ");
        if (head != null) {
            Stack<Node> stack = new Stack<>();
            while (!stack.isEmpty() || head != null) {
                if (head != null) {
                    stack.push(head);
                    head = head.left;
                } else {
                    head = stack.pop();
                    System.out.print(head.value + " ");
                    head = head.right;
                }
            }
        }
        System.out.println();
    }

	/**
	* 先将头放入s2,然后将右子树放入s2,最后将左子树放入s2
	*/
    public void posOrderUnRecur1(Node head) {
        System.out.println("pos-order: ");
        if (head != null) {
            Stack<Node> s1 = new Stack<>();
            Stack<Node> s2 = new Stack<>();
            s1.push(head);
            while (!s1.isEmpty()) {
                head = s1.pop();
                s2.push(head);
                if (head.left != null) {
                    s1.push(head.left);
                }
                if (head.right != null) {
                    s1.push(head.right);
                }
            }
            while (!s2.isEmpty()) {
                System.out.print(s2.pop().value + " ");
            }
        }
        System.out.println();
    }

递归的前中后序遍历看起来挺有规律,但是非递归的就不太一样了,我是找不到啥规律。

非递归的前序遍历和中序遍历都模拟了递归调用栈。

打印边缘节点

题目:

给定一棵二叉树的头节点 head,按照标准实现二叉树的边界节点的逆时针打印。

1.头节点为边界节点。
2.叶节点为边界节点。
3.如果节点在其所在的层中是最左的或最右的,那么该节点也是边界节点。

技术图片

打印结果为:1,2,4,7,11,13,14,15,16,12,10,6,3

思路:

  • 获得树高
  • 依据树高构建Node[][] edgeMap = new Node[height][2]edgeMap是存储二叉树每一层的最左和最右的边缘节点
  • 有了edgeMap后便可以打印左边缘节点
  • 打印如14,15这样的非边缘节点,但为叶结点
  • 从下向上打印右边缘节点

代码

二叉树遍历是基础,以下代码我会跟二叉树的前中后序遍历做一些联系,如果读者觉着这样的联系并不好,那就忽略吧。

获得树高

    /**
     * 获得二叉树的高度
     * 通过不断向下递归查找,找到最大高度
     * @param head
     * @param height
     * @return
     */
    private int getHeight(Node head, int height) {
        if (head == null) {
            return height;
        }
        return Math.max(getHeight(head.left, height + 1), getHeight(head.right, height + 1));
    }

此方法我认为类似后序遍历。向左右递归,得到左右的树高,然后在做比较取大一点的。

符合先左右递归,然后操作。

获得edgeMap

    /**
     * edgeMap是一个二维数组,记录树的每一层最左和最右边缘节点。
     * @param h
     * @param l
     * @param edgeMap
     */
    private void setEdgeMap(Node h, int l, Node[][] edgeMap) {
        if (h == null) {
            return;
        }
        edgeMap[l][0] = edgeMap[l][0] == null ? h : edgeMap[l][0];
        edgeMap[l][1] = h;
        setEdgeMap(h.left, l + 1, edgeMap);
        setEdgeMap(h.right, l + 1, edgeMap);
    }

这个一看就符合先序遍历。

先操作edgeMap,然后递归。

        edgeMap[l][0] = edgeMap[l][0] == null ? h : edgeMap[l][0];
        edgeMap[l][1] = h;

上面两行代码挺巧妙的,仔细思考先序遍历的过程和规律,发现这两行代码正好就能求的左右边缘。

打印非边缘节点的叶结点

    /**
     * 打印不是边缘节点的叶节点
     * @param h
     * @param l
     * @param m
     */
    private void printLeafNotInMap(Node h, int l, Node[][] m) {
        if (h == null) {
            return;
        }
        // 首先要是叶子结点,并且不是左右边缘
        if (h.left == null && h.right == null && h != m[l][0] && h != m[l][1]) {
            System.out.print(h.value + " ");
        }
        printLeafNotInMap(h.left, l + 1, m);
        printLeafNotInMap(h.right, l + 1, m);
    }

这个也是先序遍历了。

符合先操作,后递归。

先序遍历每个节点,判断其是叶结点但不为边缘节点。

主方法

    /**
     * @param head
     */
    public void printEdge1(Node head) {
        if (head == null) {
            return;
        }
        int height = getHeight(head, 0);
        Node[][] edgeMap = new Node[height][2];
        setEdgeMap(head, 0, edgeMap);
        for (int i = 0; i != edgeMap.length; i++) {
            System.out.print(edgeMap[i][0].value + " ");
        }
        printLeafNotInMap(head, 0, edgeMap);
        for (int i = edgeMap.length - 1; i != -1; i--) {
            if (edgeMap[i][0] != edgeMap[i][1]) {
                System.out.print(edgeMap[i][1].value + " ");
            }
        }
        System.out.println();
    }

主方法与思路一致,不多说了。

完整代码:Gitee

(未完待续....)????

二叉树遍历和延伸

标签:-o   现在   his   toc   tle   数组   int   set   思考   

原文地址:https://www.cnblogs.com/keboom/p/14780452.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!