Java多线程实现方式及并发与同步,【Java数据结构与算法

在这里插入图片描述

二叉树(binary tree)是指树中节点的度不大于 2 的有序树,它是一种最简单且最重要的树。二叉树的递归定义为:二叉树是一棵空树,或者是一棵由一个根节点和两棵互不相交的,分别称作根的左子树和右子树组成的非空树;左子树和右子树又同样都是二叉树

相关术语:

  1. 结点:包含一个数据元素及若干指向子树分支的信息

  2. 结点的度:一个结点拥有子树的数目称为结点的度

  3. 叶子结点:也称为终端结点,没有子树的结点或者度为零的结点

  4. 分支结点:也称为非终端结点,度不为零的结点称为非终端结点

  5. 树的度:树中所有结点的度的最大值

  6. 结点的层次:从根结点开始,假设根结点为第 1 层,根结点的子结点为第 2 层,依此类推,如果某一个结点位于第 L 层,则其子结点位于 L + 1 层

  7. 树的深度:也称为树的高度,树中所有结点的层次最大值称为树的深度

  8. 有序树:如果树中各棵子树的次序是有先后次序,则称该树为有序树

  9. 无序树:如果树中各棵子树的次序没有先后次序,则称该树为无序树

    10.森林:由 m (m ≥ 0) 棵互不相交的树构成一片森林。如果把一棵非空的树的根结点删除,则该树就变成了一片森林,森林中的树由原来根结点的各棵子树构成

特殊类型:

  • 满二叉树:指的是深度为 k 且含有 2^k - 1 个结点的二叉树

  • 完全二叉树:设二叉树的深度为 h,除第 h 层外,其他各层的结点数都达到最大个数,且第 h 层所有的结点都连续集中在最左边。也就是说,树中所含的 n 个结点和满二叉树中编号为 1 至 n 的结点一一对应

    • 第 n 个元素的左子结点为 2n

    • 第 n 个元素的右子结点为 2n + 1

    • 第 n 个元素的父结点为 (n - 1)/ 2

性质:

  1. 二叉树的第 i 层上至多有 2^(i - 1) 个点(i ≥ 1)

  2. 深度为 h 的二叉树中至多含有 2^h - 1 个结点

  3. 若在任意一棵二叉树中,有 n0 个叶子结点,有 n2 个度为 2 的结点,则必有 n0 = n2 + 1

  4. 具有 n 个 结点的完全二叉树深度为 log2(x + 1) ,其中 x 表示不大于 n 的最大整数

  5. 若对一棵有 n 个结点的完全二叉树进行顺序编号(1 ≤ i ≤ n),那么,对于编号为 i (i ≥ 1)的结点:

    当 i = 1 时,该结点为根,它无双亲结点

    当 i > 1 时,该结点的双亲结点的编号为 i / 2

    若 2i < n,则有编号为 2i 的左结点,否则没有左结点

    若 2i + 1 ≤ n,则有编号为 2i + 1 的右节点,否则没有右节点

2.遍历二叉树


前序遍历二叉树

在这里插入图片描述

思路:

访问到一个结点后就打印该结点,并继续遍历其左右子树

遍历顺序:

GDAFEMHZ

代码实现:


//前序遍历

public void preOrder(){

    //打印父结点

    System.out.println(this);

    //递归向左子树前序遍历

    if (this.left != null){

        this.left.preOrder();

    }

    //递归向右子树前序遍历

    if (this.right != null){

        this.right.preOrder();

    }

} 

中序遍历二叉树

在这里插入图片描述

思路:

访问到一个结点后将其暂存,遍历完左子树后,再打印该结点的值,然后遍历右子树

遍历顺序:

ADEFGHMZ

代码实现:


//中序遍历

public void infixOrder(){

    //递归向左子树中序遍历

    if (this.left != null){

        this.left.infixOrder();

    }

    //打印父结点

    System.out.println(this);

    //递归向右子树中序遍历

    if (this.right != null){

        this.right.infixOrder();

    }

} 

后续遍历二叉树

在这里插入图片描述

思路:

访问到一个结点后将其暂存,遍历完左右子树后,再打印该结点的值

遍历顺序:

AEFDHZMG

代码实现:


//后序遍历

public  void postOrder(){

    //递归向左子树后序遍历

    if (this.left != null){

        this.left.postOrder();

    }

    //递归向右子树后序遍历

    if (this.right != null){

        this.right.postOrder();

    }

    //打印父结点

    System.out.println(this);

} 

层次遍历二叉树

在这里插入图片描述

思路:

建立一个循环队列,先将二叉树根结点入队列,然后出队列,访问根结点,如果它有左子树,则将左子树的根结点入队:如果它有右子树,则将右子树的根结点入队。然后出队列,对出队结点访问,如此反复,直到队列为空为止

遍历顺序:

ADMAFHZ

代码实现:


//层次遍历

    public void levelOrder(){

        ArrayDeque<HeroNode> queue = new ArrayDeque<>(20);

        //首先将根结点加入队列中

        queue.add(this);

        //遍历二叉树

        while(!queue.isEmpty()){

            HeroNode tempNode = queue.poll();

            System.out.println(tempNode);



            if (tempNode.left != null){

                queue.add(tempNode.left);

            }

            if (tempNode.right != null){

                queue.add(tempNode.right);

            }

        }

    } 

3.查找二叉树


前序查找二叉树

在这里插入图片描述

思路:

  1. 首先拿根结点进行比较,如果相等,直接返回,否则左递归前序查找

  2. 如果左递归找到,直接返回,否则右递归前序查找

  3. 如果右递归找到返回,否则返回空

查到 H 结点

比较次数:

7

代码实现:


//前序遍历

    public HeroNode preOrdersearch(int no){

        System.out.println("进入前序遍历");

        //比较当前结点是不是

        if (this.no == no){

            return this;

        }

        //1.判断当前结点的左子结点是否为空,如果不为空,则递归前序查找

        //2.如果左递归前序查找,找到结点则返回

        HeroNode resNode = null;

        if (this.left != null){

            resNode = this.left.preOrdersearch(no);

        }

        if (resNode != null){   //说明我们左子树找到

            return resNode;

        }

        //1.左递归前序查找,找到结点,则返回,否继续判断

        //2.当前的结点的右子结点是否为空,如果不空,则继续向右递归前序查找

        if (this.right != null){

            resNode = this.right.preOrdersearch(no);

        }

        return resNode;

    } 

中序查找二叉树

在这里插入图片描述

思路:

  1. 首先左递归查找,如果找到,直接返回,否则和根结点比较

  2. 如果比较相等,直接返回,否则右递归中序查找

  3. 如果右递归找到则返回,否则返回空

查找 H 结点

比较次数:

6

代码实现:


//中序遍历

    public HeroNode infixOrderSearch(int no){

        //判断当前结点的左子结点是否为空,如果不为空,则递归中序查找

        HeroNode 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;

    } 

后序查找二叉树

在这里插入图片描述

思路:

  1. 首先左递归查找,如果找到,直接返回,否则右递归中序查找

  2. 如果右递归找到,直接返回,否则和根结点比较

  3. 如果比较不相等则返回空

查找 H 结点

比较次数:

5

代码实现:


//后序遍历

    public HeroNode postOrderSearch(int no){

        //判断当前节点的左子结点是否为空,如果不为空,则递归后序查找

        HeroNode 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.二叉树删除节点


思路:

  • 如果删除的结点就是 root结点,则等价将二叉树置空

  • 如果删除的结点是非叶子结点,则删除该子树

  • 如果删除的结点是叶子结点,则删除该结点

  • 因为我们的二叉树是单向的,所以只能判断当前结点的子结点是不是需要删除结点

  1. 如果当前结点的左子结点不为空,并且左子结点就是要删除的结点,执行 this.left = null,并 return

  2. 如果当前结点的右子结点不为空,并且左子结点就是要删除的结点,执行 this.right = null,并 return

  3. 如果第 1 步和第 2 步没有 return,那么我们就需要向左子树进行递归删除

  4. 如果第 3 步仍没有 return,则向右子树进行递归删除

5.二叉树综合实例


代码:


package com.sisyphus.tree;



import java.util.ArrayDeque;



/**

 * @Description: 二叉树$

 * @Param: $

 * @return: $

 * @Author: Sisyphus

 * @Date: 7/23$

 */

public class BinaryTreeDemo {

    public static void main(String[] args) {

        //先要创建一棵二叉树

        BinaryTree binaryTree = new BinaryTree();

        //创建需要的结点

        HeroNode root = new HeroNode(1, "宋江");

        HeroNode node2 = new HeroNode(2, "吴用");

        HeroNode node3 = new HeroNode(3, "卢俊义");

        HeroNode node4 = new HeroNode(4, "林冲");

        HeroNode node5 = new HeroNode(5, "关胜");



        //说明,我们先手动创建该二叉树,后面我们学习递归的方式创建二叉树

        root.setLeft(node2);

        root.setRight(node3);

        node3.setRight(node4);

        node3.setLeft(node5);

        binaryTree.setRoot(root);



        System.out.println("前序遍历"); //12354

        binaryTree.preOrder();



        System.out.println("中序遍历"); //21534

        binaryTree.infixOrder();



        System.out.println("后序遍历"); //25431

        binaryTree.postOrder();



        //前序遍历

        System.out.println("前序遍历");

        HeroNode resNode = binaryTree.preOrderSearch(5);

        if (resNode != null){

            System.out.printf("找到了,信息为 no=%d name=%s",resNode.getNo(),resNode.getName());

            System.out.println();

        }else{

            System.out.printf("没有找到 no=%d 的英雄",5);

            System.out.println();

        }

        //中序遍历

        System.out.println("中序遍历");

        resNode = binaryTree.infixOrderSearch(5);

        if (resNode != null){

            System.out.printf("找到了,信息为 no=%d name=%s",resNode.getNo(),resNode.getName());

            System.out.println();

        }else{

            System.out.printf("没有找到 no=%d 的英雄",5);

            System.out.println();

        }

        //后序遍历

        System.out.println("后序遍历");

        resNode = binaryTree.postOrderSearch(5);

        if (resNode != null){

            System.out.printf("找到了,信息为 no=%d name=%s",resNode.getNo(),resNode.getName());

            System.out.println();

        }else{

            System.out.printf("没有找到 no=%d 的英雄",5);

            System.out.println();

        }



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



        //测试删除结点

        System.out.println("删除前,前序遍历");

        binaryTree.preOrder();

        binaryTree.delNode(5);

        System.out.println("删除后,前序遍历");

        binaryTree.preOrder();



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

        System.out.println("层次遍历");

        binaryTree.levelOrder();



    }

}



//定义 BinaryTree 二叉树

class BinaryTree{

    private HeroNode root;



    public void setRoot(HeroNode root){

        this.root = root;

    }



    //删除结点

    public void delNode(int no){

        if (root != null){

            //如果只有一个 root 结点,这里立即判断 root 是不是就是要删除的结点

            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("当前二叉树为空,无法遍历");

        }

    }

    //中序遍历

    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("当前二叉树为空,无法遍历");

        }

    }

    //层次遍历

    public void levelOrder(){

        if (this.root != null){

            this.root.levelOrder();

        }else{

            System.out.println("当前二叉树为空,无法遍历");

        }

    }



    //++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++



    //查找



    //前序遍历

    public HeroNode preOrderSearch(int no){

        if (root != null){

            return root.preOrdersearch(no);

        }else{

            return null;

        }

    }

    //中序遍历

    public HeroNode infixOrderSearch(int no){

        if (root != null){

            return root.infixOrderSearch(no);

        }else{

            return null;

        }

    }

    //后序遍历

    public HeroNode postOrderSearch(int no){

        if (root != null){

            return root.postOrderSearch(no);

        }else{

            return null;

        }

    }

}



//先创建 HeroNode 结点

class HeroNode{

    private int no;

    private String name;

    private HeroNode left;

    private HeroNode right;



    public HeroNode(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 HeroNode getLeft() {

        return left;

    }



    public void setLeft(HeroNode left) {

        this.left = left;

    }



    public HeroNode getRight() {

        return right;

    }



    public void setRight(HeroNode right) {

        this.right = right;

    }



    @Override

    public String toString() {

        return "HeroNode{" +

                "no=" + no +

                ", name='" + name + '\'' +

                '}';

    }



    //递归删除结点

    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);

        }

    }



    //+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++



    //遍历



    //前序遍历

    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);

    }

    //层次遍历

    public void levelOrder(){

        ArrayDeque<HeroNode> queue = new ArrayDeque<>(20);

        //首先将根结点加入队列中

        queue.add(this);

        //遍历二叉树

        while(!queue.isEmpty()){

            HeroNode tempNode = queue.poll();

            System.out.println(tempNode);



            if (tempNode.left != null){

                queue.add(tempNode.left);

            }

            if (tempNode.right != null){

                queue.add(tempNode.right);

            }

        }

    }



    //++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++



    //查找



    //前序遍历

    public HeroNode preOrdersearch(int no){

        System.out.println("进入前序遍历");

        //比较当前结点是不是

        if (this.no == no){

            return this;

        }

        //1.判断当前结点的左子结点是否为空,如果不为空,则递归前序查找

        //2.如果左递归前序查找,找到结点则返回

        HeroNode resNode = null;

        if (this.left != null){

            resNode = this.left.preOrdersearch(no);

        }

        if (resNode != null){   //说明我们左子树找到

            return resNode;

        }

        //1.左递归前序查找,找到结点,则返回,否继续判断

        //2.当前的结点的右子结点是否为空,如果不空,则继续向右递归前序查找

        if (this.right != null){

            resNode = this.right.preOrdersearch(no);

        }

        return resNode;

    }

    //中序遍历

    public HeroNode infixOrderSearch(int no){

        //判断当前结点的左子结点是否为空,如果不为空,则递归中序查找

        HeroNode 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 HeroNode postOrderSearch(int no){

        //判断当前节点的左子结点是否为空,如果不为空,则递归后序查找

        HeroNode resNode = null;

        if (this.left != null){

            resNode = this.left.postOrderSearch(no);

        }

        if (resNode != null){   //说明在左子树找到

            return resNode;

        }


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值