Java实现,手写二叉树

本文介绍了二叉树的基本概念,包括满二叉树、完全二叉树和二叉搜索树。接着探讨了树的两种存储方式,数组形式和链表形式,详细解析了二叉链表和三叉链表的结构特点,并强调了在实际应用中,二叉链表作为二叉树存储的常见选择。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

一、基本概念

  • 二叉树:每个节点最多有两个子树的结构;
  • 满二叉树:除了最后一层没有任何节点外,每一层的所有节点都有两个子节点的二叉树;
  • 完全二叉树:结构与满二叉树类似,不同点在于最后一层可以不满,但最后一层的节点必须连续集中再最左边;
  • 二叉搜索树:各节点的值有大小要求的二叉树,左节点的值<中节点的值<右节点的值。

二、树的存储方式

1、数组形式

        使用数组存储,有一个特点就是必须连续存储,根据树的结构,满二叉树和完全二叉树可以对树的元素从上到下,从左到右进行连续存储,但是对于一般的二叉树,必须进行完全化才可以进行数组存储。所谓的完全化,就是对于没有子节点的位置,使用null代替,构成完全二叉树的结构。那么问题就来了,使用null存储,也是会占用存储空间的,所以对树的存储方式,一般采取链表的形式。

2、链表形式

链表形式可以分为两类:二叉链表和三叉链表。

        二叉链表存储,包含三个信息,左孩子节点指针,右孩子节点指针,以及数据域。如果没有孩子节点,则将指针域置为NULL。使用二叉链表结构,一般会创建一个头节点,并将其中的左子树指向根节点,右子树为NULL,这样方便了后续的操作。

            三叉链表存储,除了含有二叉链表的结构外,还含有一个双亲节点指针域,指向它的双亲节点。这是典型的空间换时间的方法,如果涉及的操作需要频繁访问双亲节点,就建议使用三叉链表的存储结构。

        对于一般的二叉树而言,二叉链表存储是最简单有效的方式,也是推荐使用的。

三、树的实现

package com.cjs.bean;

public class Node {
    private int id;
    private int data;
    private Node leftChild;
    private Node rightChild;

    public Node() {
    }

    public Node(int id, int data, Node leftChild, Node rightChild) {
        this.id = id;
        this.data = data;
        this.leftChild = leftChild;
        this.rightChild = rightChild;
    }

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

    public int getId() {
        return id;
    }

    public void setId(int id) {
        this.id = id;
    }

    public int getData() {
        return data;
    }

    public void setData(int data) {
        this.data = data;
    }

    public Node getLeftChild() {
        return leftChild;
    }

    public void setLeftChild(Node leftChild) {
        this.leftChild = leftChild;
    }

    public Node getRightChild() {
        return rightChild;
    }

    public void setRightChild(Node rightChild) {
        this.rightChild = rightChild;
    }
}
package com.cjs;

import com.cjs.bean.Node;

public class BinaryTree {
    private Node root;

    /**
     * 查找节点
     * @param key 要查找的属性id值
     * @return
     */
    public Node find(int key) {
        Node current = root;

        while (current!=null) {
            if (key > current.getId()) {
                current = root.getRightChild();
            } else if (key < current.getId()) {
                current = root.getLeftChild();
            } else if (key == current.getId()) {
                return current;
            }
        }

        return current;
    }

    /**
     * 插入一个节点
     * @param id
     * @param data
     */
    public void insert(int id, int data) {
        Node newNode = new Node(id,data);

        if (root == null) {
            root = newNode;
        } else {
            Node current = root;
            //定义parent节点,如果插入的节点不是root,肯定会影响到parent节点
            Node parent = null;

            while (true) {
                parent = current;
                if (id < current.getId()) {
                    current = current.getLeftChild();
                    if (current == null) {
                        //如果当前节点为空,说明已经找到了。
                        parent.setLeftChild(newNode);
                        return;
                    }
                } else if (id > current.getId()) {
                    current = current.getRightChild();
                    if (current == null) {
                        parent.setRightChild(newNode);
                        return;
                    }
                }
            }
        }
    }

    /**
     * 从node节点开始前序遍历
     * @param node
     */
    public void preOrder(Node node) {
        if (node!=null) {
            System.out.println(node.getData() + ",");
            preOrder(node.getLeftChild());
            preOrder(node.getRightChild());
        }
    }
    /**
     * 从node节点开始中序遍历
     * @param node
     */
    public void inOrder(Node node) {
        if (node!=null) {
            preOrder(node.getLeftChild());
            System.out.println(node.getData() + ",");
            preOrder(node.getRightChild());
        }
    }
    /**
     * 从node节点开始后序遍历
     * @param node
     */
    public void postOrder(Node node) {
        if (node!=null) {
            preOrder(node.getLeftChild());
            preOrder(node.getRightChild());
            System.out.println(node.getData() + ",");
        }
    }

    /**
     * 获取最小节点,树的最左边为最小节点
     * @return
     */
    public Node getMinNode() {
        Node current = root;
        Node lastNode = null;

        while (current != null) {
            lastNode = current;
            current = current.getLeftChild();
        }

        return lastNode;
    }

    /**
     * 获取最大节点,树的最右边为最大节点
     * @return
     */
    public Node getMaxNode() {
        Node current = root;
        Node lastNode = null;

        while (current != null) {
            lastNode = current;
            current = current.getRightChild();
        }

        return lastNode;
    }

    public boolean delete(int key) {
        Node current = root;
        Node parent = root;
        boolean isLeftChild = true;
        while (current!=null) {
            parent = current;
            if (key > current.getId()) {
                isLeftChild = false;
                current = root.getRightChild();
            } else if (key < current.getId()) {
                isLeftChild = true;
                current = root.getLeftChild();
            }
            if (key == current.getId()) {
                break;
            }
        }
//        没有找到需要删除的节点
        if (current == null) {
            return false;
        }

        if (current.getLeftChild() == null && current.getRightChild() == null) {
//        1、需要删除的节点没有子节点,直接置为null
            if (current == root) {
                root = null;
            }
            else {
                this.setNode(parent, null, isLeftChild);
            }
        }
        else if (current.getRightChild() == null) {
//        2、需要删除的节点只有一个子节点,将该子节点直接替代
            this.setNode(parent, current.getLeftChild(), isLeftChild);
        }
        else {
//        3、需要删除的节点有两个子节点,查找右子树的最左边节点,作为替代节点
            Node minNode = current.getRightChild();
            Node minNodeParent = minNode;
            while (minNode.getLeftChild()!=null) {
                minNodeParent = minNode;
                minNode = minNode.getLeftChild();
            }
            this.setNode(parent, minNode, isLeftChild);
            minNode.setLeftChild(current.getLeftChild());
            if (minNodeParent!=minNode) {
                minNodeParent.setLeftChild(null);
                minNode.setRightChild(current.getRightChild());
            }
        }
        return true;
    }

    /**
     * 设置替代节点的值
     * @param parent
     * @param targetNode
     * @param isLeftChild
     */
    private void setNode(Node parent, Node targetNode, boolean isLeftChild) {
        if (isLeftChild) {
            parent.setLeftChild(targetNode);
        } else {
            parent.setRightChild(targetNode);
        }
    }
}

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值