二叉树概念及基本功能实现

文章详细介绍了二叉树的概念,包括满二叉树和完全二叉树的定义。通过Java代码展示了如何创建和遍历二叉树,包括先序、中序、后序和层次遍历。同时,提供了查询和删除节点的方法,并讨论了二叉树深度的计算。此外,还提及了线索化二叉树的概念,以及堆排序的基本原理。
摘要由CSDN通过智能技术生成

目录

一、二叉树概述 

 二、代码实现一棵二叉树:

三、二叉树的遍历

四、二叉树遍历代码实现

1.先序遍历:

2.中序遍历:

3.后序遍历:

4.层次遍历(一层一层遍历):

5.main方法执行

五、二叉树的查询和删除:

1.二叉树的查询:

2.二叉树的删除:

3.main方法执行:

六、二叉树深度的计算

七、线索化二叉树:

八、堆排序概述:

一、二叉树概述 

二叉树是每个节点最多有两个子树的树结构,也就是说树的度是2.

满二叉树:每一层的结点数都达到最大值。

完全二叉树:若设二叉树的深度为k,除第k层外,其他各层(1~k-1)的结点数都达到最大个数,第k层所有的结点都连续集中在最左边,这就是完全二叉树。

 注:完全二叉树的话,所有的结点都连续集中在最左边,也就是如下图所示,右子节点可以没有,但如果右子节点有的话,则左子节点必须存在。下图中如果叶子结点只有4结点,5、6、7结点没有的话,也是完全二叉树。

 二、代码实现一棵二叉树:

1.定义结点        2.创建一棵树,手动创建子节点        3.定义一个根节点

public class BinaryTree {
    //定义一个根节点
    Node root;

    //定义结点类
    public class Node{
        //存储数据节点
        Object item;
        //左子节点
        Node left;
        //右子节点
        Node right;

        public Node(Object obj){
            this.item = obj;
        }
    }

    //创建一棵树
    public void createTree(){
        //创建根节点
        root = new Node(1);
        //创建左子节点
        Node leftNode = new Node(2);
        //创建右子节点
        Node rightNode = new Node(3);

        //把左右子节点关联到根节点
        root.left = leftNode;
        root.right = rightNode;

        //创建左子节点的左子节点
        Node leftLeftNode = new Node(4);
        //创建左子节点的右子节点
        Node leftRightNode = new Node(5);

        //把左节点的左右子节点关联到左节点
        leftNode.left = leftLeftNode;
        leftNode.right = leftRightNode;

        //创建右子节点的左子节点
        Node rightLeftNode = new Node(6);
        //创建右子节点的右子节点
        Node rightRightNode = new Node(7);

        //把右结点的左右子节点关联到右节点
        rightNode.left = rightLeftNode;
        rightNode.right = rightRightNode;
    }
}

三、二叉树的遍历

 

 注:每次遍历的时候,大化小,也就是把大的树化成一颗颗小的树。

比如先序遍历:根左右,先遍历根“1”,然后左子树“2 4 5”作为整体充当根节点的左子树,再进行先序遍历。最后遍历结果就是 1  245   367

四、二叉树遍历代码实现

1.先序遍历:

//实现先序遍历
    public void preTrival(Node node){
        //退出的条件
        if (node == null){
            return;
        }
        //先遍历根节点
        System.out.print(node.item+" ");
        //遍历左子树
        preTrival(node.left);
        //遍历右子树
        preTrival(node.right);
    }

2.中序遍历:

//实现中序遍历
    public void midTrival(Node node){
        //退出的条件
        if (node == null){
            return;
        }
        //遍历左子树
        midTrival(node.left);
        //先遍历根节点
        System.out.print(node.item+" ");
        //遍历右子树
        midTrival(node.right);
    }

3.后序遍历:

//实现后序遍历
    public void postTrival(Node node){
        //退出的条件
        if (node == null){
            return;
        }
        //遍历左子树
        postTrival(node.left);
        //遍历右子树
        postTrival(node.right);
        //先遍历根节点
        System.out.print(node.item+" ");
    }

注:由上面代码规律可以看出,除了根节点是直接打印其值之外,左节点、右节点都是通过递归遍历的方式遍历到。如:

先序遍历:打印根节点--->递归遍历左节点--->递归遍历右节点

中序遍历:递归遍历左节点--->打印根节点--->递归遍历右节点

后序遍历:递归遍历左节点--->递归遍历右节点--->打印根节点

4.层次遍历(一层一层遍历):

思路:将根节点放入一个队列中,然后每次取出这个节点后,相应地将它的左右子节点依次放入队列中,按照队列的先进先出的特性,依次将元素出队列并打印。(如果觉得抽象,可以画图感受一下。)

//实现层次遍历(就是一层一层遍历)
    //思路:将根节点放入一个队列中,然后每次取出这个节点后,相应地将它的左右子节点依次放入队列
    //     中,按照队列的先进先出的特性,依次将元素出队列并打印。
    public void levelTrival(Node node){
        //创建一个队列
        ArrayDeque<Node> queue = new ArrayDeque<Node>(10);
        //将开始的结点放入到队列中
        queue.add(node);
        while (!queue.isEmpty()){
            //将队列中的结点出列
            Node n = queue.poll();
            System.out.print(n.item+" ");
            //将左子节点放入到队列中
            if (n.left != null){
                queue.add(n.left);
            }
            //将右子节点放入到队列中
            if (n.right != null){
                queue.add(n.right);
            }
        }
    }

5.main方法执行

public class TestBinaryTree {
    public static void main(String[] args) {
        BinaryTree bTree = new BinaryTree();
        //创建二叉树
        bTree.createTree();
        //执行前序遍历二叉树
        bTree.preTrival(bTree.root);

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

        //执行中序遍历二叉树
        bTree.midTrival(bTree.root);

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

        //执行后序遍历二叉树
        bTree.postTrival(bTree.root);

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

        //执行层次遍历
        bTree.levelTrival(bTree.root);
    }
}

五、二叉树的查询和删除:

1.二叉树的查询:

查询可以选择任意一种遍历方式,在遍历的同时对当前元素的值进行比较判断。 

这里选用先序遍历的方式来实现:

    //实现树的查询,按先序遍历
    //思路:可以选择任意一种遍历方式,在遍历的同时对当前元素的值进行比较判断即可。
    public Node preSearch(Node node, Object obj){
        //先判断树是否为null
        if (node == null){
            return null;
        }
        //定义一个target用于接收preSearch的返回值,如果找到则接收当前结点,否则接收null
        Node target = null;
        if (node.item == obj){
            //找到元素
            return node;
        }else {
            //先遍历左子树
            target = preSearch(node.left,obj);
            //判断是否找到元素
            if (target != null){
                return target;
            }
            //再遍历右子树
            target = preSearch(node.right,obj);
            //判断是否找到元素
            if (target != null){
                return target;
            }
        }
        return null;
    }

2.二叉树的删除:

因为二叉树不像平衡树那么复杂,删除元素要考虑到平衡等因素,所以删除二叉树的元素时,如果是叶子结点则直接赋予null,如果是非叶子结点则将整个子树删除,也就是给当前非叶子结点赋予null。

//实现树的删除
    //思路:遍历树将树的每一个元素与目标值进行比较,找到了就将其设为null,
    //     如果是叶子结点,则直接设为null,如果是非叶子结点,就将整个子树删除,也就是将此节点设为null即可。
    public void deleteNode(Node node,Object obj){
        //先判断树是否为空
        if (node == null){
            return;
        }
        //判断根节点是否为目标结点
        if (node == root && root.item == obj){
            this.root = null;
        }

        //判断子节点是否为目标
        //先判断左子树是否存在目标
        if (node.left != null){
            if (node.left.item == obj){
                //删除左子节点
                node.left = null;
                return;
            }else {
                //从子树中进行删除
                deleteNode(node.left,obj);
            }
        }
        //再判断右子树是否存在目标
        if (node.right != null){
            if (node.right.item == obj){
                //删除左子节点
                node.right = null;
                return;
            }else {
                //从子树中进行删除
                deleteNode(node.right,obj);
            }
        }
    }

3.main方法执行:

public class TestBinaryTree02 {
    public static void main(String[] args) {
        BinaryTree bTree = new BinaryTree();
        bTree.createTree();

        //查询结点
        BinaryTree.Node result = bTree.preSearch(bTree.root, 13);
        if (result != null){
            System.out.println("结果:"+result.item);
        }else {
            System.out.println("没有此节点");
        }

        //删除结点
        bTree.deleteNode(bTree.root,2);
        bTree.levelTrival(bTree.root);
    }
}

六、二叉树深度的计算

//二叉树高度的计算你(深度)
    //思路:将左子树与右子树进行递归比较,最后返回最深的值。
    //     比如从根节点开始,比较其左子树、右子树,到了左子树、右子树这边,再比较其对应的左子树右子树,
    //     以此循环,用递归的方式来判断。
    public int maxDepth(Node node){
        //先判断树是否为空
        if (node == null){
            return 0;
        }

        int leftDepth = 0;
        int rightDepth = 0;

        //1.先获取左子树的高度
        if (node.left != null){
            leftDepth = maxDepth(node.left);
        }
        //2.再获取右子树的高度
        if (node.right != null){
            rightDepth = maxDepth(node.right);
        }
        //3.判断左右子树谁大
        if (leftDepth > rightDepth){
           return leftDepth + 1;
        }else {
            return rightDepth + 1;
        }
    }

七、线索化二叉树:

在使用前序、中序、后序遍历的时候,都会用到递归,过多的使用递归可能会导致栈内存的溢出,这个时候可能通过将二叉树进行线索化,来避免使用递归进行树的遍历。

 在有N个节点的二叉树中会存在N+1个空指针域。可以利用这些空指针域,存放指向节点在某种遍历(前、中、后)下的前驱或后继节点的指针。

公式:2n(n-1),每个节点有两个指针,如果需要连接其他节点必须要使用n-1个指针,剩下的指针就是空的。

这种加了线索的二叉链表称为线索链表,相应的二叉树称为线索二叉树(Threaded BinaryTree)。

线索二叉树的应用:

(1)首先将二叉树进行线索化

(2)然后直接通过循环添加的线索遍历树,从而避免使用递归

八、堆排序概述:

堆排序(Heapsort)是指利用堆这种数据结构所设计的一种排序算法,它是一种选择排序,它的最坏、最好、平均时间复杂度均为O(nlog2^{n}

堆是一棵完全二叉树:

(1)当所有的结点的值都大于或者等于其左右的子节点的值称为大顶堆。

(2)当所有的结点的值都小于或者等于其左右的子节点的值称为小顶堆。

 

 

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值