二叉树相关概念及前中后层序遍历

二叉树

二叉树:二叉树是每个节点最多有两个子树的树结构;是n(n>=0)个结点的有限集合,它或者是空树(n=0),或者是由一个根结点及两颗互不相交的、分别称为左子树和右子树的二叉树所组成。

img

完全二叉树

完全二叉树:除最后一层外,每一层上的结点数均达到最大值;在最后一层上只缺少右边的若干结点;

img

满二叉树

满二叉树:除最后一层外,每一层上的所有结点都有两个子结点;满二叉树是一种特殊的完全二叉树;

img

二叉排序树(二叉搜索树)

二叉搜索树是二叉树的一种,是应用非常广泛的一种二叉树,英文简称为 BST 又被称为:二叉查找树、二叉排序树

  • 任意一个节点的值都大于其左子树所有节点的值
  • 任意一个节点的值都小于其右子树所有节点的值
  • 它的左右子树也是一棵二叉搜索树

二叉排序(搜索)树:二叉树中,每个节点都不比它左子树的任意元素小,而且不比它的右子树的任意元素大。又叫二叉搜索树。

img

平衡二叉树

平衡二叉树(Balanced Binary Tree)是二叉查找树的一个进化体,也是第一个引入平衡概念的二叉树。1962年,G.M. Adelson-Velsky 和 E.M. Landis发明了这棵树,所以它又叫AVL树。

平衡二叉树要求对于每一个节点来说,它的左右子树的高度之差不能超过1,如果插入或者删除一个节点使得高度之差大于1,就要进行节点之间的旋转,将二叉树重新维持在一个平衡状态。

这个方案很好的解决了二叉查找树退化成链表的问题,把插入,查找,删除的时间复杂度最好情况和最坏情况都维持在O(logN)。但是频繁旋转会使插入和删除牺牲掉O(logN)左右的时间,不过相对二叉查找树来说,时间上稳定了很多。

二叉树遍历

package com.michealkz.tree;

import com.michealkz.printer.BinaryTreeInfo;

import java.util.Comparator;
import java.util.LinkedList;
import java.util.Queue;

/**
 * 二叉搜索树继承自BinaryTreeInfo 实现其中的方法以便进行打印
 *
 * @param <E>
 */
public class BinarySearchTree<E> implements BinaryTreeInfo {
    
    
    private int size;
    private Node<E> root;
    private Comparator<E> comparator;

    public int size() {
    
    
        return size;
    }

    public boolean isEmpty() {
    
    
        return size == 0;
    }

    public void clear() {
    
    
        root = null;
        size = 0;
    }

    public void add(E element) {
    
    
        elementNotNullCheck(element);

        // 添加第一个节点
        if (root == null) {
    
    
            root = new Node<E>(element, null);
            size++;
            return;
        }

        // 添加的不是第一个节点 则找到父节点
        Node<E> parent = root;
        Node<E> node = root;
        int cmp = 0;
        do {
    
    
            /*
             * 根据compare的返回值正负或者相等来判断是左子树还是右子树还是相等
             */
            cmp = compare(element, node.element);
            // 将节点保存下来作为查找下一个的父节点
            parent = node;
            if (cmp > 0) {
    
    
                node = node.right;
            } else if (cmp < 0) {
    
    
                node = node.left;
            } else {
    
     // 相等
                node.element = element;
                return;
            }
        } while (node != null);

        // 看看插入到父节点的哪个位置
        Node<E> newNode = new Node<E>(element, parent);
        if (cmp > 0) {
    
    
            parent.right = newNode;
        } else {
    
    
            parent.left = newNode;
        }
        size++;
    }

    /*
     * @return 返回值等于0,代表e1和e2相等;返回值大于0,代表e1大于e2;返回值小于于0,代表e1小于e2
     */
    private int compare(E e1, E e2) {
    
    
        if (comparator != null) {
    
    
            return comparator.compare(e1, e2);
        }
        return ((Comparable<E>) e1).compareTo(e2);
    }

    private void elementNotNullCheck(E element) {
    
    
        if (element == null) {
    
    
            throw new IllegalArgumentException("element must not be null");
        }
    }

    // 二叉树的前序遍历操作
    public void preorderTraversal() {
    
    
        preorderTraversal(root);
    }

    // 二叉树的前序遍历传入根节点进行遍历操作
    private void preorderTraversal(Node<E> node) {
    
    
        if (node == null) return;
        System.out.print(node.element + "\t");
        preorderTraversal(node.left);
        preorderTraversal(node.right);
    }

    // 二叉树中序遍历
    public void middleOrderTraversal() {
    
    
        middleOrderTraversal(root);
    }

    // 二叉树中序遍历实现逻辑
    private void middleOrderTraversal(Node<E> node) {
    
    
        if (node == null) return;
        middleOrderTraversal(node.left);
        System.out.print(node.element + "\t");
        middleOrderTraversal(node.right);
    }

    // 二叉树后序遍历
    public void postOrderTraversal() {
    
    
        postOrderTraversal(root);
    }

    // 二叉树后序遍历实现
    private void postOrderTraversal(Node<E> node) {
    
    
        if (node == null) return;
        postOrderTraversal(node.left);
        postOrderTraversal(node.right);
        System.out.print(node.element + "\t");
    }

    // 二叉树层序遍历
    public void levelOrderTraversal() {
    
    
        levelOrderTraversal(root);
    }

    // 二叉树层序遍历实现逻辑

    /**
     * 二叉树层序遍历很重要
     * 遍历思路:
     *  - 1.定义队列存放节点
     *  - 2.首先将根节点入队列
     *  - 3.如果队列不为空,那么将队列顶部元素出队
     *  - 4.输出根节点的值
     *  - 5.判断根节点左右节点是否为空,如果不为空,那么将左右节点入队列,只要队列不为空就一直执行while循环
     * @param root
     */
    private void levelOrderTraversal(Node<E> root) {
    
    
        Queue<Node<E>> queue = new LinkedList<>();
        queue.offer(root);
        while (!queue.isEmpty()) {
    
    
            Node<E> node = queue.poll();
            System.out.print(node.element + "\t");

            if (node.left != null) {
    
    
                queue.offer(node.left);
            }

            if (node.right != null) {
    
    
                queue.offer(node.right);
            }
        }

    }

    /**
     * 下面是打印需要重写的四个方法
     * 根节点
     */
    @Override
    public Object root() {
    
    
        return root;
    }

    // 左树的寻找方式
    @Override
    public Object left(Object node) {
    
    
        return ((Node<E>) node).left;
    }

    // 右树的寻找方式
    @Override
    public Object right(Object node) {
    
    
        return ((Node<E>) node).right;
    }

    // 打印方式
    @Override
    public Object string(Object node) {
    
    
        Node<E> myNode = (Node<E>) node;
        // 获取父节点保存下来并打印
        String parentString = "null";
        if (myNode.parent != null) {
    
    
            parentString = myNode.parent.element.toString();
        }
        return myNode.element;
    }

    public BinarySearchTree() {
    
    
        this(null);
    }

    public BinarySearchTree(Comparator<E> comparator) {
    
    
        this.comparator = comparator;
    }

    /**
     * 二叉树的 Node节点 对象
     */
    public static class Node<E> {
    
    
        E element;
        Node<E> left;
        Node<E> right;
        Node<E> parent;

        public Node(E element, Node<E> parent) {
    
    
            this.element = element;
            this.parent = parent;
        }

        public boolean isLeaf() {
    
    
            return left == null && right == null;
        }

        public boolean hasTwoChildren() {
    
    
            return left != null && right != null;
        }
    }
}

猜你喜欢

转载自blog.csdn.net/qq_43081842/article/details/113838089