树与二叉树(概念,特性,操作)

一、树的基本使用

1、树的概念

在这里插入图片描述

2、结点的度与树的度

结点的度为:结点拥有子树的个数为结点的度。例如 A 的度为 3;K 的度为 0。

度为 0 的结点称为叶子结点,或终端结点。度不为0的结点称为非终端结点,或分支结点,除根之外的分支结点还可称为内部结点。

树的度为:此树中结点的最大度为树的度。

在这里插入图片描述

3、结点的层次和树的深度

其中还有父亲、儿子、兄弟、祖先、子孙、堂兄弟等概念。

在这里插入图片描述

4、有序树、N叉树、森林

  • 有序树:如果将一颗树看出是从左到右是有次序的,那么称为有序树。

    无序树:将一颗树从左到右看出是无序的,称为无序树。

在这里插入图片描述

  • N叉树:树的度为N的树称为N叉树

  • 森林:是有多个不相交的树组成。

在这里插入图片描述

二、二叉树

1、二叉树概念

二叉树中每个节点的孩子树只能为0、1、2,并且是有序的。

以左边孩子为根的树称为左子树,以右孩子为根的子树称为右子树。
在这里插入图片描述

2、满二叉树和完全二叉树

满二叉树:高度为 k 并且右2^(k+1) -1 节点。

完全二叉树:在一颗满二叉树中,在最下层从最右侧起去掉若干个相邻的叶子结点,得到是树就是完全二叉树。

简单来说就是最下层叶子结点从左到右必须连续。

在这里插入图片描述

3、二叉树的性质

(1) 在非空二叉树

2^(i-1) , i>=1;

(2) 深度为h的二叉树最多有

2^h -1 个结点(h>=1),最少有h个结点;

(3) 对于任意一棵二叉树,如果其叶结点数为N0,而度数为2的结点总数为N2,则N0=N2+1;

(4) 具有n个结点的完全二叉树
[log2^n] + 1
(注:[ ]表示向下取整)

(5) 有N个结点的完全二叉树各结点如果用顺序方式存储,则结点之间有如下关系:

若I为结点编号则 如果I>1,则其父结点的编号为I/2;

如果2I<=N,则其左孩子(即左子树的根结点)的编号为2I;若2*I>N,则无左孩子;

如果2I+1<=N,则其右孩子的结点编号为2I+1;若2*I+1>N,则无右孩子。

(6) 给定N个结点,能构成h(N)种不同的二叉树。

h(N)为卡特兰数的第N项。h(n)=C(2*n,n)/(n+1)。

(7) 设有i个枝点,I为所有枝点的道路长度总和,J为叶的道路长度总和J=I+2i

三、二叉树代码实现。

1、存储结构

  • 顺序存储:顺序存储适合满二叉树和完全二叉树。不浪费空间。

在这里插入图片描述

  • 链式存储:不同的结构,可以使用不同的链式存储结构。

  • 一般我们在实践中使用链式存储,设计三个域,一个用来存储数据,另外两个用来存储指向左右孩子的指针域。
    在这里插入图片描述

2、二叉树遍历

概念:遍历就是按照某种策略访问树中的所有结点,且每个结点恰好只访问一次。

遍历可分为先序,中序,后序,层次遍历,除了层次遍历,先,中,后都可以使用递归遍历,也是我们平常实践中使用的最多的。

1、先序遍历

首先访问根,再先序遍历左(右)子树,最后先序遍历右(左)子树 。

2、中序遍历

首先中序遍历左(右)子树,再访问根,最后中序遍历右(左)子树 。

3、后序遍历

首先后序遍历左(右)子树,再后序遍历右(左)子树,最后访问根 。

3、二叉树接口

package com.gwz.datastructure.btree;

/**
 * 二叉树结构
 * 可以有不同的实现类,并且每个类可以使用不用的存储结构
 * 顺序、链式存储都可以。
 */
public interface BinaryTree {

    /**
     * 是否是空树
     * @return
     */
    boolean isEmpty();

    /**
     * 树中结点数量
     * @return
     */
    int size();

    /**
     * 获取树的高度
     * @return
     */
    int getHeight();

    /**
     * 查询指定值的结点
     * @param value
     * @return
     */
    Node findKey(int value);

    /**
     * 前序遍历
     */
    void preOrderTraverse();

    /**
     * 中序遍历
     */
    void inOrderTraverse();

    /**
     * 后序遍历
     */
    void nextOrderTraverse();

    /**
     * 后序遍历
     */
    void nextOrderTraverse(Node node);

    /**
     * 前序遍历,非递归操作
     */
    void preOrderByStack();

    /**
     * 中序遍历,非递归操作
     */
    void inOrderByStack();

    /**
     * 后序遍历,非递归操作
     */
    void nextOrderByStack();

    /**
     * 后序遍历非递归
     */
    void nextOrderByStack(Node node);

    /**
     * 层次遍历,非递归。
     */
    void levelOrderByQueue();
}

4、二叉树实现类

package com.gwz.datastructure.btree;

import java.util.Deque;
import java.util.LinkedList;
import java.util.Queue;

public class LinkedBinaryTree implements BinaryTree{

    private Node root; // 根结点。

    public LinkedBinaryTree() {
    }

    public LinkedBinaryTree(Node root) {
        this.root = root;
    }

    @Override
    public boolean isEmpty() {
        return root == null;
    }

    @Override
    public int size() {
        System.out.print("二叉树结点个数:");
        return this.size(root);
    }

    private int size(Node root) {
        if (root == null) {
            return 0;
        } else {
            // 左、右子树之和 + 1;
            int l = size(root.leftChild);
            int r = size(root.rightChild);
            return l + r + 1;
        }
    }

    @Override
    public int getHeight() {
        System.out.println("\n二叉树的高度:");
        return getHeight(root);
    }

    private int getHeight(Node node) {
        if(node == null) {
           return 0;
        } else {
            // 获取左子树高度
            int l = getHeight(node.leftChild);
            // 获取右子树高度
            int r = getHeight(node.rightChild);
            // 返回左、右子树中最大值 + 1
            return r > l ? r+1 : l+1;
        }
    }

    @Override
    public Node findKey(int value) {
        return this.findKey(value, root);
    }

    private Node findKey(Object value, Node root) {
        if (root == null) {
            return null;
        } else if (root != null && root.value != value) {
            return root;
        } else {
            Node node1 = this.findKey(value, root.leftChild);
            Node node2 = this.findKey(value, root.rightChild);
            if (node1 != null && node1.value == value) {
                 return node1;
            } else if (node2 != null && node2.value == value){
                return node2;
            } else {
                return node2;
            }
        }
    }
    // 先序递归遍历  根、左、右
    @Override
    public void preOrderTraverse() {
        // 输出根结点
        if (root != null) {
            // 输出根节点
            System.out.print(root.value+" | ");
            // 遍历左子树,先创建左子树
            BinaryTree leftTree = new LinkedBinaryTree(root.leftChild);
            leftTree.preOrderTraverse();
            // 遍历右子树、先创建右子树
            BinaryTree rightTree = new LinkedBinaryTree(root.rightChild);
            rightTree.preOrderTraverse();
        }
    }
    // 这里相对先序遍历做了改进,为了不让用用户单独答应遍历策略
    // 同时为了简化编码
    // 中序递归遍历  左、根、右
    @Override
    public void inOrderTraverse() {
        System.out.println("\n中序遍历!");
        inOrderTraverse(root);
    }

    // 可以不向外部暴露
    private void inOrderTraverse(Node node) {
        if (node != null) {
            inOrderTraverse(node.leftChild);
            System.out.print(node.value+" | ");
            inOrderTraverse(node.rightChild);
        }
    }

    // 后序递归遍历
    @Override
    public void nextOrderTraverse() {
        System.out.println("\n后续遍历");
        nextOrderTraverse(root);
    }

    @Override
    public void nextOrderTraverse(Node node) {
        if (node != null) {
            nextOrderTraverse(node.leftChild);
            nextOrderTraverse(node.rightChild);
            System.out.print(node.value+" | ");
        }
    }

    @Override
    public void preOrderByStack() {

    }

    // 非递归中序遍历,和深度优先遍历很想
    @Override
    public void inOrderByStack() {
        System.out.println("\n中序非递归遍历");
        Deque<Node> stack = new LinkedList<Node>();
        Node current = root;
        while (current != null || !stack.isEmpty()) {
            // 这里的意思是一直遍遍历完左子树。
            while (current != null) {
                stack.push(current);
                current = current.leftChild;
            }
            if (!stack.isEmpty()) {
                current = stack.pop(); // 弹栈,并把指针往回指
                System.out.println(current + " | ");
                current = current.rightChild;
            }
        }
        System.out.println();
    }

    @Override
    public void nextOrderByStack() {

    }

    @Override
    public void nextOrderByStack(Node node) {

    }
	// 层次遍历,利用队列去完成。
    @Override
    public void levelOrderByQueue() {
        if (root == null) return;
        Queue<Node> queue = new LinkedList<Node>();
        queue.add(root); // 存入根结点
        while (queue.size() != 0) {
            int len = queue.size();
            for (int i = 0; i < len; i++) {
                Node temp = queue.poll();
                System.out.print(temp.value+" | ");
                if (temp.leftChild != null) queue.add(temp.leftChild);
                if (temp.rightChild != null) queue.add(temp.rightChild);
            }
        }
        System.out.println();
    }

}

5、二叉树测试

构建的二叉树。

在这里插入图片描述

package com.gwz.datastructure.btree;

public class TestBinaryTree {
    public static void main(String[] args) {
        // 创建一个二叉树
        Node node5 = new Node(5,null,null);
        Node node4 = new Node(4,null,node5);

        Node node3 = new Node(3,null,null);
        Node node7 = new Node(7,null,null);
        Node node6 = new Node(6,null,node7);

        Node node2 = new Node(2,node3,node6);
        Node node1 = new Node(1,node4,node2);

        BinaryTree btree =  new LinkedBinaryTree(node1);
        // 判断二叉树是否为空
        System.out.println(btree.isEmpty());
        // 前序遍历(递归) 1 4 5 2 3 6 7
        System.out.println("先序遍历!");
        btree.preOrderTraverse();
        // 中序遍历(递归) 4 5 1 3 2 6 7
        btree.inOrderTraverse();
        // 后序遍历(递归) 5 4 3 7 6 2 1
        btree.nextOrderTraverse();
        // 中序遍历(非递归,借助栈)
        btree.inOrderByStack();
        // 层次遍历(非递归,借助队列)
        btree.levelOrderByQueue();
        // 在二叉树中查找某个值
        System.out.println(btree.findKey(1));
        // 获取二叉树的高度
        System.out.println(btree.getHeight());
        // 获取二叉树结点个数
        System.out.println(btree.size());
    }
}

猜你喜欢

转载自blog.csdn.net/qq_40749830/article/details/105778262