数据结构-二叉树(一)

92 篇文章 0 订阅
16 篇文章 0 订阅

树(Tree)

  • 树与数组& 链表对比
  1. 数组存储
  • 优点: 通过下标访问元素, 速度快
  • 缺点: 检索具体元素值, 或数组底部或元素与元素之间插入新元素或删除元素, 效率都很低
  1. 链式存储
  • 优点: 插入和删除效率较好
  • 缺点: 检索效率很低
  1. 树存储
  • 增删改查4样性能都比较好

二叉树(Binary Tree)

  1. 每个节点最多只能有两个子节点, 一个左节点一个右节点
  2. 如果二叉树的所有叶子节点都在最后一层, 且节点总数=2^n-1, n为层数, 则称为满二叉树
  3. 如果二叉树的所有叶子节点都在最后一层或者倒数第二层, 且最后一层的叶子节点在左边连续, 倒数第二层的叶子节点在右边连续, 则称为完全二叉树
    * 满二叉树肯定是完全二叉树, 而完全二叉树不一定是满二叉树

三种遍历

  • 前序遍历:
  1. 先输出根节点, 再递归输出左子树, 最后递归输出右子树
  2. 左右子树从父节点往下遍历输出, 左节点优先于右节点. 依次父左右顺序输出
  • 中序遍历:
  1. 先递归输出左子树, 再输出根节点, 最后递归输出右子树
  2. 左右子树从最左, 且最底节点开始输出. 依次左父右顺序输出
  • 后序遍历:
  1. 先递归输出左子树, 再递归输出右子树, 最后输出根节点
  2. 左右子树从最左, 且最底节点开始输出. 依次左右父顺序输出

* 看根节点的输出顺序, 就可以确定是什么遍历了


public class BinaryTreeApp {
    public static void main(String[] args) {
        /** 创建二叉树实例*/
        BinaryTree binaryTree = new BinaryTree();
        /** 创建多个结点*/
        Node node1 = new Node(1, "节点1"); // root
        Node node2 = new Node(2, "节点2");
        Node node3 = new Node(3, "节点3");
        Node node4 = new Node(4, "节点4");
        Node node5 = new Node(5, "节点5");
        Node node6 = new Node(6, "节点6");
        Node node7 = new Node(7, "节点7");
        Node node8 = new Node(8, "节点8");
        Node node9 = new Node(9, "节点9");
        /** 设定根节点*/
        binaryTree.setRoot(node1);
        /** 手动设定各节点*/
        node1.setLeft(node2);
        node1.setRight(node3);
        node3.setRight(node4);
        node3.setLeft(node5);
        node4.setLeft(node8);
        node4.setRight(node9);
        node5.setLeft(node6);
        node5.setRight(node7);
        System.out.println("前序遍历:");
        binaryTree.preOrder();
        System.out.println("中序遍历:");
        binaryTree.infixOrder();
        System.out.println("后序遍历:");
        binaryTree.postOrder();
    }
}

/** 定义二叉树*/
class BinaryTree {
    private Node root;

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

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

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

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

/** 定义节点*/
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 + "]";
    }

    /** 前序遍历*/
    public void preOrder() {
        /** 1. 输出父结点*/
        System.out.println(this);
        /** 2. 递归向左子树前序遍历*/
        if(this.left != null) {
            this.left.preOrder();
        }
        /** 2. 递归向右子树前序遍历*/
        if(this.right != null) {
            this.right.preOrder();
        }
    }

    /** 中序遍历*/
    public void infixOrder() {
        /** 1. 递归向左子树中序遍历*/
        if(this.left != null) {
            this.left.infixOrder();
        }
        /** 2. 输出父结点*/
        System.out.println(this);
        /** 3. 递归向右子树中序遍历*/
        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);
    }

}

输出:
> 前序遍历:
> Node [no=1, name=节点1]
> Node [no=2, name=节点2]
> Node [no=3, name=节点3]
> Node [no=5, name=节点5]
> Node [no=6, name=节点6]
> Node [no=7, name=节点7]
> Node [no=4, name=节点4]
> Node [no=8, name=节点8]
> Node [no=9, name=节点9]
> 中序遍历:
> Node [no=2, name=节点2]
> Node [no=1, name=节点1]
> Node [no=6, name=节点6]
> Node [no=5, name=节点5]
> Node [no=7, name=节点7]
> Node [no=3, name=节点3]
> Node [no=8, name=节点8]
> Node [no=4, name=节点4]
> Node [no=9, name=节点9]
> 后序遍历:
> Node [no=2, name=节点2]
> Node [no=6, name=节点6]
> Node [no=7, name=节点7]
> Node [no=5, name=节点5]
> Node [no=8, name=节点8]
> Node [no=9, name=节点9]
> Node [no=4, name=节点4]
> Node [no=3, name=节点3]
> Node [no=1, name=节点1]

查找节点


public class BinaryTreeApp {
    public static void main(String[] args) {
        /** 创建二叉树实例*/
        BinaryTree binaryTree = new BinaryTree();
        /** 创建多个结点*/
        Node node1 = new Node(1, "节点1"); // root
        Node node2 = new Node(2, "节点2");
        Node node3 = new Node(3, "节点3");
        Node node4 = new Node(4, "节点4");
        Node node5 = new Node(5, "节点5");
        /** 设定根节点*/
        binaryTree.setRoot(node1);
        /** 手动设定各节点*/
        node1.setLeft(node2);
        node1.setRight(node3);
        node3.setRight(node4);
        node3.setLeft(node5);

        System.out.println("前序遍历查找:");
        Node resNode = binaryTree.preOrderSearch(5);
        if (resNode != null) {
            System.out.printf("找到了, 信息为 no=%d name=%s\n", resNode.getNo(), resNode.getName());
        } else {
            System.out.printf("没有找到 no=%d", 5);
        }

        System.out.println("中序遍历查找:");
        Node resNode2 = binaryTree.infixOrderSearch(5);
        if (resNode2 != null) {
            System.out.printf("找到了, 信息为 no=%d name=%s\n", resNode2.getNo(), resNode2.getName());
        } else {
            System.out.printf("没有找到 no=%d", 5);
        }

        System.out.println("后序遍历查找:");
        Node resNode3 = binaryTree.postOrderSearch(5);
        if (resNode3 != null) {
            System.out.printf("找到了, 信息为 no=%d name=%s\n", resNode3.getNo(), resNode3.getName());
        } else {
            System.out.printf("没有找到 no=%d", 5);
        }
    }
}

/** 定义二叉树*/
class BinaryTree {
    private Node root;

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

    /** 前序遍历查找*/
    public Node preOrderSearch(int no) {
        if(root != null) {
            return root.preOrderSearch(no);
        } else {
            return null;
        }
    }

    /** 中序遍历查找*/
    public Node infixOrderSearch(int no) {
        if(root != null) {
            return root.infixOrderSearch(no);
        }else {
            return null;
        }
    }

    /** 后序遍历查找*/
    public Node postOrderSearch(int no) {
        if(root != null) {
            return this.root.postOrderSearch(no);
        }else {
            return null;
        }
    }
}

/** 定义节点*/
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 + "]";
    }

    /** 前序遍历查找*/
    public Node preOrderSearch(int no) {
        System.out.println("进入前序遍历");
        /** 判断要查找的节点是否为当前节点*/
        if(this.no == no) {
            return this;
        }

        Node resNode = null;
        /** 左递归前序查找*/
        if(this.left != null) {
            resNode = this.left.preOrderSearch(no);
        }
        /** 说明左子树中找到了指定节点*/
        if(resNode != null) {
            return resNode;
        }
        /** 右递归前序查找*/
        if(this.right != null) {
            resNode = this.right.preOrderSearch(no);
        }

        return resNode;
    }

    /** 中序遍历查找*/
    public Node infixOrderSearch(int no) {
        Node resNode = null;
        /** 左递归中序查找*/
        if(this.left != null) {
            resNode = this.left.infixOrderSearch(no);
        }
        /** 说明左子树中找到了指定节点*/
        if(resNode != null) {
            return resNode;
        }

        System.out.println("进入中序查找");
        /** 判断要查找的节点是否为当前节点*/
        if(this.no == no) {
            return this;
        }
        /** 右递归中序查找*/
        if(this.right != null) {
            resNode = this.right.infixOrderSearch(no);
        }

        return resNode;
    }

    /** 后序遍历查找*/
    public Node postOrderSearch(int no) {
        Node resNode = null;
        /** 左递归后序查找*/
        if(this.left != null) {
            resNode = this.left.postOrderSearch(no);
        }
        /** 说明左子树中找到了指定节点*/
        if(resNode != null) {
            return resNode;
        }
        /** 右递归后序查找*/
        if(this.right != null) {
            resNode = this.right.postOrderSearch(no);
        }
        /** 说明右子树中找到了指定节点*/
        if(resNode != null) {
            return resNode;
        }
        System.out.println("进入后序查找");
        /** 判断要查找的节点是否为当前节点*/
        if(this.no == no) {
            return this;
        }

        return resNode;
    }

}

输出:
> 前序遍历查找: 遍历次数为4次
> 进入前序遍历
> 进入前序遍历
> 进入前序遍历
> 进入前序遍历
> 找到了, 信息为 no=5 name=节点5
> 中序遍历查找: 遍历次数为3次
> 进入中序查找
> 进入中序查找
> 进入中序查找
> 找到了, 信息为 no=5 name=节点5
> 后序遍历查找: 遍历次数为2次
> 进入后序查找
> 进入后序查找
> 找到了, 信息为 no=5 name=节点5

删除节点

  • 规则: 要删除的节点, 如果是非叶子节点, 则删除该子树

public class BinaryTreeApp {
    public static void main(String[] args) {
        /** 创建二叉树实例*/
        BinaryTree binaryTree = new BinaryTree();
        /** 创建多个结点*/
        Node node1 = new Node(1, "节点1"); // root
        Node node2 = new Node(2, "节点2");
        Node node3 = new Node(3, "节点3");
        Node node4 = new Node(4, "节点4");
        Node node5 = new Node(5, "节点5");
        /** 设定根节点*/
        binaryTree.setRoot(node1);
        /** 手动设定各节点*/
        node1.setLeft(node2);
        node1.setRight(node3);
        node3.setRight(node4);
        node3.setLeft(node5);
        System.out.println("删除前, 前序遍历");
        binaryTree.preOrder();
        binaryTree.delNode(5);
        System.out.println("删除后, 前序遍历");
        binaryTree.preOrder();
    }
}

/** 定义二叉树*/
class BinaryTree {
    private Node root;

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

    /** 删除结点*/
    public void delNode(int no) {
        if(root != null) {
            /** 删除结点*/
            if(root.getNo() == no) {
                root = null;
            } else {
                /** 递归删除*/
                root.delNode(no);
            }
        }else{
            System.out.println("空树, 不能删除");
        }
    }

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

/** 定义节点*/
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 + "]";
    }

    /** 删除结点*/
    public void delNode(int no) {
        /** 如果当前结点的左子结点不为空, 且左子结点就是要删除结点, this.left = null; (结束递归删除)*/
        if(this.left != null && this.left.no == no) {
            this.left = null;
            return;
        }
        
        /** 如果当前结点的右子结点不为空, 且右子结点就是要删除结点, this.right= null; (结束递归删除)*/
        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);
        }
    }

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

}

输出:
> 删除前, 前序遍历
> Node [no=1, name=节点1]
> Node [no=2, name=节点2]
> Node [no=3, name=节点3]
> Node [no=5, name=节点5]
> Node [no=4, name=节点4]
> 删除后, 前序遍历
> Node [no=1, name=节点1]
> Node [no=2, name=节点2]
> Node [no=3, name=节点3]
> Node [no=4, name=节点4]

如果您觉得有帮助,欢迎点赞哦 ~ 谢谢!!

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值