java数据结构之--树(二叉树)

1.数据结构分析?

  1. 数组的存储方式分析:
    1. 优点:通过下标方式访问元素,速度快,对于有序数组还可以使用二分查找提高检索速度。
    2. 缺点:如果要检索具体某个值,或者插入值会整理移动,效率较低。

  2. 链式储存的方式分析:

    1. 优点:在一定程序上对数组存储方式有优化,比如插入一个数值时,只需要讲插入点接到链表中即可,删除效率也是同理效果好。

    2. 缺点:在进行检索时,效率仍然很低,检索某一个值时,需要从链表头一直做检索。

  3. 树存储方式分析:

    1. 能提高数据存储,读取的效率,比如可以使用二叉树既可以保证数据检索速度,同时也可以保证数据的插入,删除,修改的速度。

2.二叉树介绍:

        二叉树(Binary tree)是树形结构的一个重要类型。许多实际问题抽象出来的数据结构往往是二叉树形式,即使是一般的树也能简单地转换为二叉树,而且二叉树的存储结构及其算法都较为简单,因此二叉树显得特别重要。二叉树特点是每个结点最多只能有两棵子树,且有左右之分。

3.树的结构示意图:

4. 树的常用术语:

  1. 结点
    根结点
    父结点
    子结点
    叶子结点(没有子结点的结点)
    结点的全(结点值)
    路径(从root结点找到目标结点的线路)
    层
    子树
    树的高度(最大层数)
    森林(多颗子树构成森林)

5.二叉树分类:

  1. 树有很多种,每个结点最多只能有两个子结点的一种形式称之为二叉树,二叉树分为左结点和右结点。

        2.如果该二叉树的所有叶子结点都在最后一层,并且结点总数是2^n-1,n是层数,则我们称之为满二叉树。

         3.如果该二叉树的所有叶子结点都在最后一层或者倒数第二层,而且最后一层的叶子结点在左边连续,倒数第二层的叶子结点在右边连续,我们称之为全完二叉树。

 6.二叉树应用案例:

        可以使用前序,中序,后序对下面的二叉树进行遍历

  1. 前序遍历:先输出父结点,再遍历左子树和右子树
  2. 中序遍历:先遍历左子树,再遍历父结点,再遍历右子树
  3. 后序遍历:先遍历左子树,再遍历右子树,最后遍历父结点

结论:看父结点输出顺序即是某序遍历

7. 二叉树应用案例:

  1. 前序查找
  2. 中序查找
  3. 后序查找

8.二叉树应用案例:

  1. 删除的结点是叶子结点,那么删除当前结点即可。
  2. 删除的结点是非叶子结点,那么需要删除该子树。

9.完整代码实现:

package tree;

/**
 * @author WuChenGuang
 */
public class Node {

    private int no;

    private String name;

    private Node left;

    private Node right;

    public Node(int no, String name) {
        this.no = no;
        this.name = name;

    }

    public int getNo() {
        return no;
    }

    public void setNo(int no) {
        this.no = no;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public Node getLeft() {
        return left;
    }

    public void setLeft(Node left) {
        this.left = left;
    }

    public Node getRight() {
        return right;
    }

    public void setRight(Node right) {
        this.right = right;
    }

    @Override
    public String toString() {
        return "Node{" +
                "no=" + no +
                ", name='" + name + '\'' +
                ", left=" + left +
                ", right=" + right +
                '}';
    }

    /**
     * 定义前序遍历
     */
    public void preSelect() {
        // 先输出父结点
        System.out.println(this);

        if (this.left != null) {
            this.left.preSelect();
        }
        if (this.right != null) {
            this.right.preSelect();
        }
    }

    /**
     * 中序遍历结点
     */
    public void infixSelect() {
        // 左节点  父节点  右节点
        if (this.left != null) {
            this.left.infixSelect();
        }

        System.out.println(this);

        if (this.right != null) {
            this.right.infixSelect();
        }
    }

    /**
     * 后序遍历
     */
    public void postSelect() {
        if (this.left != null) {
            this.left.postSelect();
        }
        if (this.right != null) {
            this.right.postSelect();
        }

        System.out.println(this);
    }

    /**
     * 前序遍历查找
     */
    public Node preSearch(int no) {
        // 判断是否是当前节点
        if (this.no == no) {
            return this;
        }

        // 查询左子节点
        Node lNode = null;
        if (this.left != null) {
            lNode = this.left.preSearch(no);
        }

        if (lNode != null) {
            return lNode;
        }

        // 查询当前节点右子节点,如果不为空,则继续递归前序查找
        if (this.right != null) {
            lNode = this.right.preSearch(no);
        }

        return lNode;
    }

    /**
     * 中序遍历查找
     */
    public Node infixSearch(int no) {
        Node node = null;

        if (this.left != null) {
            node = this.left.infixSearch(no);
        }

        if (node != null) {
            return node;
        }

        // 对比当前节点
        if (this.no == no) {
            return this;
        }

        // 遍历右子结点
        if (this.right != null) {
            node = this.right.infixSearch(no);
        }
        return node;
    }

    /**
     * 后序遍历查找结点
     */
    public Node postSearch(int no) {
        Node node = null;

        if (this.left != null) {
            node = this.left.postSearch(no);
        }

        if (node != null) {
            return node;
        }

        if (this.right != null) {
            node = this.right.postSearch(no);
        }

        if (node != null) {
            return node;
        }

        if (this.no == no) {
            return this;
        }

        return null;
    }

    /**
     * 删除节点两种情况:
     * 1.删除的结点是叶子结点
     * 2.删除的结点是子树。非叶子结点
     * 3.单向二叉树
     */
    public void delNode(int no) {
        /*
         1、当前节点左节点不为空,并且左子节点就是需要删除的结点,this.left=null
         2、当前结点右结点不为空,并且右子节点就是需要删除的结点,this.right = null;
         3、如果1,2步没有执行,那么需要向左子树进行递归删除
         4、如果第3步没有执行,那么则向右子树进行递归删除
         */
        if (this.left != null && this.left.no == no) {
            this.left = null;
            return;
        }

        if (this.right != null && this.right.no == no) {
            this.right = null;
            return;
        }

        // 向左子树进行递归删除
        if (this.left != null) {
            this.left.delNode(no);
        }

        // 向右子树进行递归删除
        if (this.right != null) {
            this.right.delNode(no);
        }
    }
}
package tree;

/**
 * @author WuChenGuang
 */
public class BinaryTree {

    private Node root;

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

    public void preSelect() {
        if (this.root != null) {
            this.root.preSelect();
        } else {
            System.out.println("空二叉树,无法遍历...");
        }
    }

    public void infixSelect() {
        if (this.root != null) {
            this.root.infixSelect();
        } else {
            System.out.println("空二叉树,无法遍历...");
        }
    }

    public void postSelect() {
        if (this.root != null) {
            this.root.postSelect();
        } else {
            System.out.println("空二叉树,无法遍历...");
        }
    }


    /**
     * 根据结点编号前序查询
     */
    public Node preNode(int no) {
        if (root != null) {
            return root.preSearch(no);
        } else {
            System.out.println("空二叉树,无法遍历...");
            return null;
        }
    }

    /**
     * 根据结点编号中序查询
     */
    public Node infixNode(int no) {
        if (root != null) {
            return root.infixSearch(no);
        } else {
            System.out.println("空二叉树,无法遍历...");
            return null;
        }
    }

    /**
     * 根据结点编号后序查询
     */
    public Node postNode(int no) {
        if (root != null) {
            return root.postSearch(no);
        } else {
            System.out.println("空二叉树,无法遍历...");
            return null;
        }
    }

    /**
     * 删除结点
     */
    public void delNode(int no) {
        if (root != null) {
            if (root.getNo() == no) {
                root = null;
            } else {
                root.delNode(no);
            }
        } else {
            System.out.println("空二叉树,无法删除...");
        }
    }

}

package tree;

/**
 * @author WuChenGuang
 */
public class Test {
    public static void main(String[] args) {

        BinaryTree binaryTree = new BinaryTree();

        Node root = new Node(1, "孙尚香");
        Node node2 = new Node(2, "夏侯惇");
        Node node3 = new Node(3, "貂蝉");
        Node node4 = new Node(4, "吕布");
        Node node5 = new Node(5, "虞姬");
        Node node6 = new Node(6, "王昭君");

        root.setLeft(node2);
        root.setRight(node3);
        node2.setLeft(node4);
        node3.setLeft(node5);
        node3.setRight(node6);

        binaryTree.setRoot(root);

        binaryTree.delNode(5);

        System.out.println("=====前序遍历=====");
        binaryTree.preSelect();
        System.out.println("=====中序遍历=====");
        binaryTree.infixSelect();
        System.out.println("=====后序遍历=====");
        binaryTree.postSelect();

        System.out.println("==================================================");

        Node node = binaryTree.postNode(4);
        if (node != null) {
            System.out.printf("信息为:id=%d name=%s", node.getNo(), node.getName());
        } else {
            System.out.println("没有找到结点");
        }
    }
}

运行结果:

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

ll520.

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值