数据结构 -- 二叉树及实现

本文介绍了二叉树的概念,包括其结构特点、特殊类型的二叉树如满二叉树和完全二叉树。还讨论了二叉树的存储结构,如顺序结构和链式结构,并详述了前序、中序和后序遍历的递归实现。最后提到了二叉搜索树的基本实现。

一、概念及结构

  1. 概念:一棵二叉树是结点的一个有限集合,该集合或者为空,或者是由一个根节点加上两棵别称为左子树和右子树的二叉树组成。
  2. 特点

         2.1:二叉树有天然递归的特性。

        2.2:每个结点最多有两棵子树,即二叉树不存在度大于2的结点。

        2.3:二叉树的子树有左右之分,其子树的次序不能颠倒。

     3.特殊的二叉树:

       3.1:满二叉树:一个二叉树,如果每一层的结点数都达到最大值,则这个二叉树就是满二叉树。也就是说,如果一个二叉树的层数为K,且结点总数是(2^K) - 1,则它就是满二叉树。

       3.2:完全二叉树:完全二叉树是效率很高的数据结构,完全二叉树是由满二叉树引出来的。对于深度为K的,有n个结点的二叉树,当且仅当其每一个结点都与深度为K的满二叉树中编号从1~n的结点 -- 对应时称之为完全二叉树。满二叉树是一种特殊的完全二叉树。

   4.二叉树的储存结构:

          二叉树一般可以使用两种结构储存,一种顺序结构,一种链式结构。

         二叉树接口定义:

package BinaryTree;

import javax.xml.soap.Node;

/**
 * 二叉树通用接口
 * @param <E>
 */
public interface BinTree<E> {
    /**
     * 向二叉树中添加元素
     * @param e
     */
    void add(E e);

    /**
     * 取得二叉树节点个数
     * @return
     */
    int getSize();

    /**
     * 查找是否含有指定元素
     * @param e
     * @return
     */
    boolean contains(E e);

    /**
     * 二叉树的前序遍历
     */
    void preOrder();

    /**
     * 二叉树中序遍历
     */
    void inOrder();
    /**
     * 二叉树后序遍历
     */
    void postOrder();
    /**
     * 层序遍历
     */
    void levelOrder();
    /**
     * 取得二叉树的最小值节点
     */
    E getmin();
    /**
     * 取得二叉树的最大值节点
     */
    E getmax();
    E removeMin();
    E removeMax();
    /**
     * 移除指定值结点
     * @param e
     * @return
     */
    void remove(E e);
}

5.前序/中序/后序的递归结构遍历:

  1.前序遍历(NLR/先序遍历/Preorder):先访问根节点 --> 左子树 --> 右子树(最自然的访问方式来输出二叉树)

  2.中序遍历(LNR/inorder):先访问左子树 --> 根节点 --> 右子树(二叉树的排序)

  3.后序遍历(LRN/Postorder):  先访问左子树 --> 右子树 --> 根节点(二叉树的内存释放) 

6.二叉搜索树的基本实现:

package BinaryTree;

/**
 * 二叉搜索树
 */
import java.util.Queue;
import java.util.LinkedList;
import java.util.Stack;

/**
 * 二分搜索树
 * @param <E>
 */
public class BinSearchTree<E extends Comparable> implements BinTree<E> {
    private class Node {
        E data;//存放元素
        Node left;//左子树
        Node right;//右子树

        public Node(E data) {
            this.data = data;
        }
    }
    private Node root;//根节点
    private int size;//节点个数

    @Override
    public void add(E e) {
        if (root == null){
            Node node = new Node(e);
            root = node;
            size++;
        }
        //根据值遍历子树
        add(root,e);
    }

    /**
     * 以指定的root为根节点,插入指定元素e
     * @param root
     * @param e
     */
    private void add(Node root ,E e){
        //插入值刚好是当前根节点的值。终止条件。函数出口
        if (e.equals(root.data)){
            return;
        }else if (e.compareTo(root.data) < 0 && root.left == null){
            Node node = new Node(e);
            root.left = node;
            size++;
        }else if (e.compareTo(root.data) > 0 && root.right == null) {
            Node node = new Node(e);
            root.right = node;
            size++;
        }
        //左子树递归
        if (e.compareTo(root.data) < 0){
            add(root.left,e);
        }
        //右子树递归
        if (e.compareTo(root.data) > 0){
            add(root.right,e);
        }
    }

    @Override
    public int getSize() {
        return size;
    }

    /**
     * 内部方法,根据值递归检测当前二叉树是否包含指定元素
     * @param e
     * @return
     */
    @Override
    public boolean contains(E e) {
        return contains(root,e);
    }
    private boolean contains(Node root,E e){
        //终止条件
        if (root == null){
            return false;
        }
        if (e.equals(root.data)){
            return true;
            //左子树递归
        }else if (e.compareTo(root.data) < 0){
            return contains(root.left,e);
        }else {
            return contains(root.right,e);
        }
    }

    @Override
    public void preOrder() {
        postOrder(root);
    }
    private void preOrder(Node node){
        //终止条件
        if (node == null)
            return;
        System.out.println(node.data);
        preOrder(node.left);
        preOrder(node.right);

    }

    /**
     * 前序遍历非递归版本
     */
    public void preOrderNR(){
        Stack<Node> stack = new Stack<>();
        stack.push(root);
        while (!stack.isEmpty()){
            Node node = stack.pop();
            System.out.println(node.data);
            if (node.right != null)
                stack.push(node.right);
            if (node.left != null)
                stack.push(node.left);
        }
    }

    @Override
    public void inOrder() {
        inOrder(root);
    }
    private void inOrder(Node node){
        if (node == null)
            return;
        inOrder(node.left);
        System.out.println(node.data);
        inOrder(node.right);
    }

    @Override
    public void postOrder() {
        postOrder(root);
    }
    private void postOrder(Node node){
        if (node == null)
            return;
        postOrder(node.left);
        postOrder(node.right);
        System.out.println(node.data);
    }

    /**
     * 基于队列实现的二分搜索树层序遍历
     */
    @Override
    public void levelOrder() {
        Queue<Node> queue = new LinkedList<>();
        queue.add(root);
        while (!queue.isEmpty()){
            Node node = queue.poll();
            System.out.println(node.data);
            if (node.left != null)
                queue.add(node.left);
            if (node.right != null)
                queue.add(node.right);
        }
    }

    @Override
    public E getmin() {
        if (size == 0) {
            System.out.println("Empty");
        }
        Node node = getMinNode(root);
        return node.data;
    }
    private Node getMinNode(Node node){
        if (node.left == null){
            return node;
        }else {
            return getMinNode(node.left);
        }
    }

    @Override
    public E getmax() {
        if (root == null) {
            System.out.println("Empty");
        }
        Node node = getMaxNode(root);
        return node.data;
    }
    private Node getMaxNode(Node node){
        if (node.right == null)
            return node;
        return getMaxNode(node.right);
    }

    @Override
    public E removeMin() {
        E result = getmin();
        root = removeMinNode(root);
        return result;
    }

    /**
     * 删除二叉树的最小值节点
     * @param node
     * @return  返回删除后二叉树的根节点
     */
    private Node removeMinNode(Node node){
        //找到要删除的节点
        if (node.left == null){
            Node rigthNode = node.right;
            node.right = null;
            size--;
            return rigthNode;
        }
        //向左一直走,直到找到最小值节点
        node.left = removeMinNode(node.left);
        return node;
    }

    @Override
    public E removeMax() {
        E ret = getmax();
        root = removeMaxNode(root);
        return ret;
    }
    private Node removeMaxNode(Node node){
        if (node.right == null){
            Node leftNode = node.left;
            node.left = null;
            size--;
            return leftNode;
        }
        node.right = removeMaxNode(node.right);
        return node;
    }

    @Override
    public void remove(E e) {
        root = removeNode(root,e);
    }

    /**
     * 删除以node为根节点且值为e的节点
     * @param node
     * @param e
     * @return 删除后的二叉树根节点
     */
    private Node removeNode(Node node,E e){
        if (node == null) {
            return null;
        }
        //要删除的结点在左子树
        if (e.compareTo(node.data) < 0){
            node.left= removeNode(node.left,e);
            return node;
        }
        //要删除的结点在右子树
        else if (e.compareTo(node.data) > 0){
            node.right = removeNode(node.right,e);
            return node;
        }
        //此时node就为需要删除的节点
        else {
            if (node.right == null) {
                Node leftNode = node.left;
                node.left = null;
                size--;
                return leftNode;
            }
            if (node.left == null) {
                Node rightNode = node.right;
                node.right = null;
                size--;
                return rightNode;
            }
            //要删除的结点左右树均有值,找到后继或者前驱结点
            else {
                //找到右子树的最小值结点作为后继结点
                Node successor = getMinNode(node.right);
                //找到右子树的最小值结点,链到后继结点的右子树
                successor.right = removeMinNode(node.right);
                //将原左子树链到后继结点左子树
                successor.left = node.left;
                node.left = node.right = null;
                return successor;
            }
        }
    }
}

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值