『數據結構與算法』二叉樹

微信搜索:碼農StayUp
主頁地址:https://gozhuyinglong.github.io
源碼分享:https://github.com/gozhuyinglong/blog-demosjava

1. 二叉樹(Binary Tree)

二叉樹是一棵特殊的,其結構簡單但很重要。二叉樹的特色是每一個節點最多有兩棵子樹,而且有左右之分。node

  • 滿二叉樹
    若是一棵二叉樹的全部葉子節點都在最後一層,稱爲滿二叉樹。滿二叉樹的結點總數 = $2^n-1$ (n爲層數)。以下圖二叉是的層數爲3,其結點總數爲$2^3-1=7$
    滿二叉樹git

  • 徹底二叉樹
    一棵深度爲k的有n個結點的二叉樹,對樹中的節點按從上至下、從左到右的順序進行編號,若是編號爲i(1≤i≤n)的結點與滿二叉樹中編號爲i的結點在二叉樹中的位置相同,則這棵二叉樹稱爲徹底二叉樹。顯示下圖中a和b是徹底二叉樹,而c不是徹底二叉樹(倒數第二層不連續)github

徹底二叉樹

小結:一棵滿二叉樹必定是一棵徹底二叉樹;而一棵徹底二叉樹不必定是滿二叉樹。微信

2. 二叉樹的五種形態

二叉樹是遞歸定義的,其節點有左右子樹之分,邏輯上二叉樹有五種基本形態:app

二叉樹的五種形態

  • 空二叉樹(圖a)
  • 只有一個根節點的二叉樹(圖b)
  • 只有左子樹(圖c)
  • 只有右子樹(圖d)
  • 徹底二叉樹(圖e)

3. 二叉樹的遍歷(前序、中序、後序)

  • 前序遍歷:先輸出父節點,再遍歷左子樹,最後遍歷右子樹。
  • 中序遍歷:先遍歷左子樹,再輸出父節點,最後遍歷右子樹。
  • 後序遍歷:先遍歷左子樹,再遍歷右子樹,最後輸出父節點。

小結:用輸出父節點的順序來判斷是前序、中序仍是後序遍歷post

4. 代碼實現

經過Java代碼實現下圖中二叉樹,並經過三種方式遍歷該二叉樹(前序、中序、後序)。ui

二叉樹

Node類爲節點類,其中element表示節點元素,left爲左子節點,right爲右子節點。this

BinaryTree類實現二叉樹的具體操做,如前序遍歷、中序遍歷、後序遍歷。.net

public class BinaryTreeDemo {

    public static void main(String[] args) {

        BinaryTree tree = new BinaryTree();

        Node a = new Node("A");
        Node b = new Node("B");
        Node c = new Node("C");
        Node d = new Node("D");
        Node e = new Node("E");
        Node f = new Node("F");
        Node g = new Node("G");
        Node h = new Node("H");
        Node i = new Node("I");

        tree.setRoot(a);
        a.left = b;
        a.right = c;
        b.left = d;
        b.right = e;
        d.left = h;
        c.left = f;
        c.right = g;
        g.right = i;

        System.out.println("---------------前序遍歷");
        tree.preOrder();
        System.out.println("---------------中序遍歷");
        tree.inOrder();
        System.out.println("---------------後序遍歷");
        tree.postOrder();

    }

    private static class BinaryTree {

        private Node root; // 根

        public void setRoot(Node root) {
            this.root = root;
        }

        /**
         * 前序遍歷
         */
        public void preOrder() {
            preOrder(root, 0);
        }

        /**
         * 前序遍歷
         *
         * @param node
         * @param depth 層級(用於輔助輸出)
         */
        public void preOrder(Node node, int depth) {

            if (node == null) {
                return;
            }

            // 輸出當前節點
            this.print(node, depth);

            // 遞歸左子節點
            if (node.left != null) {
                preOrder(node.left, depth + 1);
            }

            // 遞歸右子節點
            if (node.right != null) {
                preOrder(node.right, depth + 1);
            }

        }

        /**
         * 中序遍歷
         */
        public void inOrder() {
            inOrder(root, 0);
        }

        /**
         * 中序遍歷
         *
         * @param node
         * @param depth 層級(用於輔助輸出)
         */
        public void inOrder(Node node, int depth) {

            if (node == null) {
                return;
            }

            // 遞歸左子節點
            if (node.left != null) {
                inOrder(node.left, depth + 1);
            }

            // 輸出當前節點
            this.print(node, depth);

            // 遞歸右子節點
            if (node.right != null) {
                inOrder(node.right, depth + 1);
            }

        }

        /**
         * 後序遍歷
         */
        public void postOrder() {
            postOrder(root, 0);
        }

        /**
         * 後序遍歷
         *
         * @param node
         * @param depth 層級(用於輔助輸出)
         */
        public void postOrder(Node node, int depth) {

            if (node == null) {
                return;
            }

            // 遞歸左子節點
            if (node.left != null) {
                postOrder(node.left, depth + 1);
            }

            // 遞歸右子節點
            if (node.right != null) {
                postOrder(node.right, depth + 1);
            }

            // 輸出當前節點
            this.print(node, depth);

        }

        /**
         * 按照層級輸出節點元素
         *
         * @param node
         * @param depth
         */
        private void print(Node node, int depth) {
            StringBuilder t = new StringBuilder();
            for (int i = 0; i < depth; i++) {
                t.append("\t");
            }
            System.out.printf("%s%s\n", t.toString(), node.element);
        }
    }

    private static class Node {
        private final Object element; // 節點元素
        private Node left; // 左子節點
        private Node right; // 右子節點

        public Node(Object element) {
            this.element = element;
        }
    }
}

輸出結果:

---------------前序遍歷
A
	B
		D
			H
		E
	C
		F
		G
			I
---------------中序遍歷
			H
		D
	B
		E
A
		F
	C
		G
			I
---------------後序遍歷
			H
		D
		E
	B
		F
			I
		G
	C
A
相關文章
相關標籤/搜索