数据结构与算法第8章:树结构和基础

二叉树

二叉树了解

1 数组对比链表存储方式分析
1.1 数组

  • 优点:通过下标方式访问元素, 速度快。 对于有序数组, 还可使用二分查找提高检索速度
  • 缺点: 如果要检索具体某个值, 或者插入值(按一定顺序)会整体移动,效率较低

1.2链表

  • 优点: 在一定程度上对数组存储方式有优化(比如: 插入一个数值节点, 只需要将插入节点, 链接到链表中即可,删除效率也很好)。
  • 缺点:在进行检索时, 效率仍然较低, 比如(检索某个值, 需要从头节点开始遍历)

1.3二叉树

  • 能提高数据存储, 读取的效率, 比如利用 二叉排序树(Binary Sort Tree), 既可以保证数据的检索速度, 同时也可以保证数据的插入, 删除, 修改的速度
    在这里插入图片描述

2 树的常用术语

  • 节点 (每一个节点)
  • 根节点 (最上级节点)
  • 父节点 (节点的上一节点)
  • 子节点 (父节点的下一节点)
  • 叶子节点 (没有子节点的节点)
  • 节点的权(节点值)
  • 路径(从 root 节点找到该节点的路线)
  • 层 (节点在第几层)
    在这里插入图片描述
  • 满二叉树
    在这里插入图片描述
  • 完全二叉树
    在这里插入图片描述

二叉树遍历

思路

  • 前序遍历:先输出父节点, 再遍历左子树和右子树
  • 中序遍历:先遍历左子树, 再输出父节点, 再遍历右子树
  • 后序遍历:先遍历左子树, 再遍历右子树, 最后输出父节点
    在这里插入图片描述
  • 定义二叉树及遍历方法
  static class HeroNode {
        private int no;
        private String name;
        private HeroNode left;
        private HeroNode right;
        //get set .....
        //构造 .....
        //toString ....
        //前序遍历的方法
        public void preOrder() {
            System.out.println(this);
            //递归向左子树遍历
            if (this.left != null) {
                this.left.preOrder();
            }
            //递归向右子树遍历
            if (this.right != null) {
                this.right.preOrder();
            }
        }

        //中序遍历
        public void infixOrder() {
            //递归向左子树遍历
            if (this.left != null) {
                this.left.infixOrder();
            }
            //输出父节点
            System.out.println(this);
            //递归向右子树遍历
            if (this.right != null) {
                this.right.infixOrder();
            }
        }

        //后序遍历
        public void postOrder() {
            //递归向左子树遍历
            if (this.left != null) {
                this.left.postOrder();
            }
            //递归向右子树遍历
            if (this.right != null) {
                this.right.postOrder();
            }
            //输出父节点
            System.out.println(this);
        }
    }
  • 定义root为整个二叉树入口
 //定义二叉树
    static class BinaryTree {
        //根节点
        private HeroNode root;

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

        //前序遍历
        public void BinaryPreOrder() {
            System.out.println("==============前序遍历");
            if (this.root != null) {
                this.root.preOrder();
            } else {
                System.out.println("二叉树为空");
            }
        }
        //中序遍历
        public void BinaryInfixOrder() {
            System.out.println("==============中序遍历");
            if (this.root != null) {
                this.root.infixOrder();
            } else {
                System.out.println("二叉树为空");
            }
        }
        //后序遍历
        public void BinaryPostOrder() {
            System.out.println("==============后序遍历");
            System.out.println();
            if (this.root != null) {
                this.root.postOrder();
            } else {
                System.out.println("二叉树为空");
            }
         //前序查找
        public void BinaryPreSearch(int no) {
            System.out.println("==============前序查找");
            HeroNode heroNode = this.root.preSearch(no);
            if (heroNode == null){
                System.out.println("没找到");
            }else {
                System.out.println(heroNode);
            }
        }
        //中序查找
        public void BinaryInfixSearch(int no) {
            System.out.println("==============中序查找");
            HeroNode heroNode = this.root.infixSearch(no);
            if (heroNode == null){
                System.out.println("没找到");
            }else {
                System.out.println(heroNode);
            }
        }
        //后序查找
        public void BinaryPostSearch(int no) {
            System.out.println("==============后序查找");
            HeroNode heroNode = this.root.postSearch(no);
            if (heroNode == null){
                System.out.println("没找到");
            }else {
                System.out.println(heroNode);
            }
        }
        }
  • 测试(手动加了些节点)
    在这里插入图片描述
public static void main(String[] args) {
        BinaryTree tree = new BinaryTree();

        HeroNode root = new HeroNode(1, "宋江");
        HeroNode heroNode2 = new HeroNode(2, "吴用");
        HeroNode heroNode3 = new HeroNode(3, "卢俊义");
        HeroNode heroNode4 = new HeroNode(4, "林冲");
        HeroNode heroNode5 = new HeroNode(5, "鲁智深");

        HeroNode heroNode6 = new HeroNode(6, "鲁智深1");
        HeroNode heroNode7 = new HeroNode(7, "鲁智深2");
        HeroNode heroNode8 = new HeroNode(8, "鲁智深3");
        HeroNode heroNode9 = new HeroNode(9, "鲁智深4");

        root.left = heroNode2;
        root.right = heroNode3;

        heroNode4.left = heroNode6;
        heroNode4.right = heroNode7;

        heroNode3.left = heroNode4;

        heroNode5.left = heroNode8;
        heroNode5.right = heroNode9;
        heroNode3.right = heroNode5;
        tree.root = root;

        //
        tree.setRoot(root);
        //前序遍历
        tree.BinaryPreOrder();
    }
  • 二叉树查找节点
/*
        前序查找
         */
        public HeroNode preSearch(int no){
            System.out.println("前序查找");
            //比较当前节点是不是
            if (this.no == no){
                return this;
            }
            //1.判断当前节点的左子节点是否为空,不过不为空就继续前序查找
            //2.如果查到了节点就返回
            HeroNode resNode = null;
            if (this.left != null){
                resNode = this.left.preSearch(no);
            }
            if (resNode != null){
                return resNode;
            }
            //1.左递归前序查找,找到节点则返回,否继续判断
            //2.当前的节点的右子节点是否为空,不过不空则继续向右递归查找
            if (this.right != null){
                resNode = this.right.preSearch(no);
            }
            return resNode;
        }

        /*
        中序遍历查找
         */
        public HeroNode infixSearch(int no){
            HeroNode resNode = null;
            if (this.left != null){
                resNode = this.left.infixSearch(no);
            }
            if (resNode != null){
                return resNode;
            }
            if(this.no == no){
                return this;
            }
            if (this.right != null){
                resNode = this.right.infixSearch(no);
            }
            return resNode;
        }

        /*
        后序查找
         */
        public HeroNode postSearch(int no){
            HeroNode resNode = null;
            if (this.left != null){
                resNode = this.left.postSearch(no);
            }
            if (resNode != null) {
                return resNode;
            }
            if (this.right != null){
                resNode = this.right.postSearch(no);
            }
            if (resNode != null){
                return resNode;
            }
            if (this.no == no){
                return this;
            }
            return resNode;
        }
/*
        递归删除节点
        1:因为此二叉树是单向的,所以判断当前节点的子节点是否是需要删除节点,而不能判断当前节点是不是需要删除的节点
        2:如果当前节点的子节点不为空,并且左子节点就是需要删除的节点,就将this.left=null,并返回(递归结束)
        3: 如果当前节点的右子节点不为空,并且右子节点就是需要删除的节点,就讲this.right=null,返回(递归结束)
        4: 如果第二步和第三步都没有执行删除,那么就需要向左子树递归删除
        5:如果第四步也没有执行删除,则向右递归删除
         */
        public void delNode(int no){
            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);
            }
        }
  • 课后作业:只删除要删除节点
      //上一种删除无法做到删除某一节点保留子节点
        /*
        我的:解决思路找到要删除节点的上一节点
        1:若要删除节点无子节点则,上一节点的下一节点=null即可
        2:若要删除节点又子节点,取其某一个叶子节点,优先取左子树的。然后让叶子节点补到要删除节点
         */
        public void delNodePlus(int no){
            if (this.left != null && this.left.no == no){
                HeroNode placeNode = this.left.getLeatNode();
                if (placeNode != null){
                    placeNode.left = this.left == null ? this.left : this.left.left;
                    placeNode.right = this.left == null ? this.left : this.left.right;
                    this.left = placeNode;
                }else {
                    this.left = null;
                }
                return;
            }
            if (this.right != null && this.right.no == no){
                HeroNode placeNode = this.right.getLeatNode();
                if (placeNode != null){
                    placeNode.right = this.right == null ? this.right:this.right.right;
                    placeNode.left = this.right == null ? this.right:this.right.left;
                    this.right = placeNode;
                }else {
                    this.right = null;
                }
                return;
            }
            if (this.left != null){
                this.left.delNodePlus(no);
            }
            if (this.right != null){
                this.right.delNodePlus(no);
            }
        }
        //递归获得节点的左叶子节点
        public HeroNode getLeatNode(){
            if (this.left != null){
                if (this.left.left == null){
                    HeroNode leftLastNode = this.left;
                    this.left = null;
                    return leftLastNode;
                }else{
                   return this.left.getLeatNode();
                }
            }
            return null;
        }

顺序存储二叉树

线索化二叉树

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值