Java数据结构之二叉树的基本操作

1 二叉树的基本概念

(1)树有很多种,每个节点最多只能有两个子节点的树就是二叉树。
(2)二叉树的子节点分为左节点和右节点
(3)示意图
在这里插入图片描述
(4)如果所有二叉树的叶节点都在最后一层,并且节点总数为2*n-1,n为层数,则该二叉树为满二叉树。
在这里插入图片描述
(5)如果该二叉树的所有叶节点都在最后一层或者倒数第二层,而且最后一层的叶节点在左边连续,倒数第二层的叶节点在右边连续,则该二叉树为完全二叉树。
在这里插入图片描述

2 二叉树的遍历

二叉树的遍历方式有四种,前序遍历、中序遍历、后序遍历和层次遍历。这里介绍以下三种常用的遍历算法。
(1)前序遍历:先输出父节点,再遍历左子树和右子树
(2)中序遍历:先遍历左子树,再输出父节点,再遍历右子树
(3)后序遍历:先遍历左子树,在遍历右子树,再输出父节点
(4)小结:看父节点的输出顺序,确定是前序、中序还是后序。

3 代码实现二叉树的遍历

public class BinaryTreeDemo {
    public static void main(String[] args) {
        //创建一颗空二叉树
        BinaryTree binaryTree = new BinaryTree();
        //创建需要的节点
        TreeNode root = new TreeNode(1);
        TreeNode node2 = new TreeNode(2);
        TreeNode node3 = new TreeNode(3);
        TreeNode node4 = new TreeNode(4);
        TreeNode node5 = new TreeNode(5);
        //手动创建二叉树
        root.setLeft(node2);
        root.setRight(node3);
        node3.setRight(node4);
        node3.setLeft(node5);
        binaryTree.setRoot(root);
    }
}
//创建二叉树
class BinaryTree{
    private TreeNode root;

    public void setRoot(TreeNode 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("二叉树为空,无法遍历");
        }
    }

    //先序遍历查找
    public boolean preOrderSearch(int no){
        if (this.root != null){
            TreeNode resNode = this.root.preOrderSearch(no);
            if (resNode != null)  return true;
        }else {
            System.out.println("二叉树为空,无法查找!\n");
        }
        return false;
    }
    //中序遍历查找
    public boolean infixOrderSearch(int no){
        if (this.root != null){
            TreeNode resNode = this.root.infixOrderSearch(no);
            if (resNode != null) {
                return true;
            }
        }else {
            System.out.println("二叉树为空,无法查找!\n");
        }
        return false;
    }

    //后序遍历查找
    public boolean postOrderSearch(int no){
        if (this.root != null){
            TreeNode resNode = this.root.postOrderSearch(no);
            if (resNode != null) return true;
        }else {
            System.out.println("二叉树为空,无法查找!\n");
        }
        return false;
    }

    //递归删除节点
    public void delNode(int no){
        if (root != null){
            //如果只有一个root节点,判断root是否是需要删除的节点
            if (root.getVal() == no){
                root = null;
            }else {
                //递归删除
                root.deleteNode(no);
            }
        }else {
            System.out.println("空树,不能删除!");
        }
    }

}

//创建二叉树的节点
class TreeNode{
    int val;
    TreeNode left;
    TreeNode right;
    TreeNode(){}
    TreeNode(int val){
        this.val =val;
    }
    TreeNode(int val,TreeNode left,TreeNode right){
        this.val = val;
        this.left = left;
        this.right = right;
    }

    public int getVal() {
        return val;
    }

    public void setVal(int val) {
        this.val = val;
    }

    public TreeNode getLeft() {
        return left;
    }

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

    public TreeNode getRight() {
        return right;
    }

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

    //编写前序遍历方法
    public void preOrder(){
        System.out.print(this.val+" "); //先输出父节点
        //递归向左子树前序遍历
        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.print(this.val+" ");;
        //递归向右子树中序遍历
        if (this.right != null){
            this.right.preOrder();
        }
    }

    //后序遍历
    public void postOrder(){
        //递归向左子树后序遍历
        if (this.left != null){
            this.left.postOrder();
        }
        //递归向右子树后序遍历
        if (this.right != null){
            this.right.postOrder();
        }
        //输出根节点
        System.out.print(this.val+" ");
    }
}

4 代码实现前序、中序、后序查找

//前序遍历查找
    public TreeNode preOrderSearch(int no){
        if (this.val == no){
            return this;
        }
        TreeNode resNode = null;
        if (this.left != null){
            resNode = this.left.preOrderSearch(no);
        }
        if (this.right != null){
            resNode = this.right.preOrderSearch(no);
        }
        return resNode;
    }

    //中序遍历查找
    public TreeNode infixOrderSearch(int no){
        //判断当前节点的左子节点是否为空,如果不为空,则递归中序查找
        TreeNode resNode = null;
        if (this.left != null){
            resNode = this.left.infixOrderSearch(no);
        }
        if (resNode != null){
            return resNode;
        }
        System.out.println("进入中序查找\n");
        if (this.val == no){
            return this;
        }
        if (this.right != null){
            resNode = this.right.infixOrderSearch(no);
        }

        return resNode;
    }

    //后序遍历查找
    public TreeNode postOrderSearch(int no){
        TreeNode 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("进入后序遍历\n");
        //如果左右子树都没有找到
        if (this.val == no){
            return this;
        }
        return resNode;
    }

5 代码实现二叉树指定节点的删除

    //递归删除节点
    //1.如果删除的节点是叶子节点,则删除该节点
    //2.如果删除的节点是非叶子节点,则删除该子树
    public void deleteNode(int no){
        //如果当前节点的左子节点不为空,并且左子节点就是要删除的节点,就将this.left = null;并且就返回(结束递归删除)
        if (this.left != null && this.left.val == no){
            this.left = null;
            return;
        }
        //如果当前节点的右子节点不为空,并且右子节点就是要删除的节点,就将this.right = null;并且就返回(结束递归删除)
        if (this.right != null && this.right.val == no){
            this.right = null;
            return;
        }
        //向左子树递归删除
        if (this.left != null){
            this.left.deleteNode(no);
        }
        //向右子树递归删除
        if (this.right != null){
            this.right.deleteNode(no);
        }
    }
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
/* * 基于链表节点实现二叉树节点 */ package dsa; public class BinTreeNode implements BinTreePosition { protected Object element;//该节点中存放的对象 protected BinTreePosition parent;//父亲 protected BinTreePosition lChild;//左孩子 protected BinTreePosition rChild;//右孩子 protected int size;//后代数目 protected int height;//高度 protected int depth;//深度 /**************************** 构造方法 ****************************/ public BinTreeNode() { this(null, null, true, null, null); } public BinTreeNode( Object e,//节点内容 BinTreePosition p,//父节点 boolean asLChild,//是否作为父节点的左孩子 BinTreePosition l,//左孩子 BinTreePosition r)//右孩子 { size = 1; height = depth = 0; parent = lChild = rChild = null;//初始化 element = e;//存放的对象 //建立与父亲的关系 if (null != p) if (asLChild) p.attachL(this); else p.attachR(this); //建立与孩子的关系 if (null != l) attachL(l); if (null != r) attachR(r); } /**************************** Position接口方法 ********************************/ //返回当前节点中存放的对象 public Object getElem() { return element; } //将对象obj存入当前节点,并返回此前的内容 public Object setElem(Object obj) { Object bak = element; element = obj; return bak; } /**************************** BinTreePosition接口方法 *************************/ //判断是否有父亲(为使代码描述简洁) public boolean hasParent() { return null != parent; } //返回当前节点的父节点 public BinTreePosition getParent() { return parent; } //设置当前节点的父节点 public void setParent(BinTreePosition p) { parent = p; } //判断是否为叶子 public boolean isLeaf() { return !hasLChild() && !hasRChild(); } //判断是否为左孩子(为使代码描述简洁) //若当前节点有父亲,而且是左孩子,则返回true;否则,返回false public boolean isLChild() { return (hasParent() && this == getParent().getLChild()) ? true : false; } //判断是否有左孩子(为使代码描述简洁) public boolean hasLChild() { return null != lChild; } //返回当前节点的左孩子 public BinTreePosition getLChild() { return lChild; } //设置当前节点的左孩子(注意:this.lChild和c.parent都不一定为空) public void setLChild(BinTreePosition c) { lChild = c; } //判断是否为右孩子(为使代码描述简洁) //若当前节点有父亲,而且是右孩子,则返回true;否则,返回false public boolean isRChild() { return (hasParent() && this == getParent().getRChild()) ? true : false; } //判断是否有右孩子(为使代码描述简洁) public boolean hasRChild() { return null != rChild; } //返回当前节点的右孩子 public BinTreePosition getRChild() { return rChild; } //设置当前节点的右孩子(注意:this.rChild和c.parent都不一定为空) public void setRChild(BinTreePosition c) { rChild = c; } //返回当前节点后代元素的数目 public int getSize() { return size; } //在孩子发生变化后,更新当前节点及其祖先的规模 public void updateSize() { size = 1;//当前节点 if (hasLChild()) size += getLChild().getSize();//左子树的规模 if (hasRChild()) size += getRChild().getSize();//右子树的规模 if (hasParent()) getParent().updateSize();//递归更新各个真祖先的规模记录 } //返回当前节点的高度 public int getHeight() { return height; } //在孩子发生变化后,更新当前节点及其祖先的高度 public void updateHeight() { height = 0;//先假设没有左、右孩子 if (hasLChild()) height = Math.max(height, 1+getLChild().getHeight());//左孩子 if (hasRChild()) height = Math.max(height, 1+getRChild().getHeight());//右孩子 if (hasParent()) getParent().updateHeight();//递归更新各个真祖先的高度记录 } //返回当前节点的深度 public int getDepth() { return depth; } //在父亲发生变化后,更新当前节点及其后代的深度 public void updateDepth() { depth = hasParent() ? 1+getParent().getDepth() : 0;//当前节点 if (hasLChild()) getLChild().updateDepth();//沿孩子引用逐层向下, if (hasRChild()) getRChild().updateDepth();//递归地更新所有后代的深度记录 } //按照中序遍历的次序,找到当前节点的直接前驱 public BinTreePosition getPrev() { //若左子树非空,则其中的最大者即为当前节点的直接前驱 if (hasLChild()) return findMaxDescendant(getLChild()); //至此,当前节点没有左孩子 if (isRChild()) return getParent();//若当前节点是右孩子,则父亲即为其直接前驱 //至此,当前节点没有左孩子,而且是左孩子 BinTreePosition v = this;//从当前节点出发 while (v.isLChild()) v = v.getParent();//沿左孩子链一直上升 //至此,v或者没有父亲,或者是父亲的右孩子 return v.getParent(); } //按照中序遍历的次序,找到当前节点的直接后继 public BinTreePosition getSucc() { //若右子树非空,则其中的最小者即为当前节点的直接后继 if (hasRChild()) return findMinDescendant(getRChild()); //至此,当前节点没有右孩子 if (isLChild()) return getParent();//若当前节点是左孩子,则父亲即为其直接后继 //至此,当前节点没有右孩子,而且是右孩子 BinTreePosition v = this;//从当前节点出发 while (v.isRChild()) v = v.getParent();//沿右孩子链一直上升 //至此,v或者没有父亲,或者是父亲的左孩子 return v.getParent(); } //断绝当前节点与其父亲的父子关系 //返回当前节点 public BinTreePosition secede() { if (null != parent) { if (isLChild()) parent.setLChild(null);//切断父亲指向当前节点的引用 else parent.setRChild(null); parent.updateSize();//更新当前节点及其祖先的规模 parent.updateHeight();//更新当前节点及其祖先的高度 parent = null;//切断当前节点指向原父亲的引用 updateDepth();//更新节点及其后代节点的深度 } return this;//返回当前节点 } //将节点c作为当前节点的左孩子 public BinTreePosition attachL(BinTreePosition c) { if (hasLChild()) getLChild().secede();//摘除当前节点原先的左孩子 if (null != c) { c.secede();//c脱离原父亲 lChild = c; c.setParent(this);//确立新的父子关系 updateSize();//更新当前节点及其祖先的规模 updateHeight();//更新当前节点及其祖先的高度 c.updateDepth();//更新c及其后代节点的深度 } return this; } //将节点c作为当前节点的右孩子 public BinTreePosition attachR(BinTreePosition c) { if (hasRChild()) getRChild().secede();//摘除当前节点原先的右孩子 if (null != c) { c.secede();//c脱离原父亲 rChild = c; c.setParent(this);//确立新的父子关系 updateSize();//更新当前节点及其祖先的规模 updateHeight();//更新当前节点及其祖先的高度 c.updateDepth();//更新c及其后代节点的深度 } return this; } //前序遍历 public Iterator elementsPreorder() { List list = new List_DLNode(); preorder(list, this); return list.elements(); } //中序遍历 public Iterator elementsInorder() { List list = new List_DLNode(); inorder(list, this); return list.elements(); } //后序遍历 public Iterator elementsPostorder() { List list = new List_DLNode(); postorder(list, this); return list.elements(); } //层次遍历 public Iterator elementsLevelorder() { List list = new List_DLNode(); levelorder(list, this); return list.elements(); } /**************************** 辅助方法 ****************************/ //在v的后代中,找出最小者 protected static BinTreePosition findMinDescendant(BinTreePosition v) { if (null != v) while (v.hasLChild()) v = v.getLChild();//从v出发,沿左孩子链一直下降 //至此,v或者为空,或者没有左孩子 return v; } //在v的后代中,找出最大者 protected static BinTreePosition findMaxDescendant(BinTreePosition v) { if (null != v) while (v.hasRChild()) v = v.getRChild();//从v出发,沿右孩子链一直下降 //至此,v或者为空,或者没有右孩子 return v; } //前序遍历以v为根节的(子)树 protected static void preorder(List list, BinTreePosition v) { if (null == v) return;//递归基:空树 list.insertLast(v);//访问v preorder(list, v.getLChild());//遍历左子树 preorder(list, v.getRChild());//遍历右子树 } //中序遍历以v为根节的(子)树 protected static void inorder(List list, BinTreePosition v) { if (null == v) return;//递归基:空树 inorder(list, v.getLChild());//遍历左子树 list.insertLast(v);//访问v inorder(list, v.getRChild());//遍历右子树 } //后序遍历以v为根节的(子)树 protected static void postorder(List list, BinTreePosition v) { if (null == v) return;//递归基:空树 postorder(list, v.getLChild());//遍历左子树 postorder(list, v.getRChild());//遍历右子树 list.insertLast(v);//访问v } //层次遍历以v为根节的(子)树 protected static void levelorder(List list, BinTreePosition v) { Queue_List Q = new Queue_List();//空队 Q.enqueue(v);//根节点入队 while (!Q.isEmpty()) { BinTreePosition u = (BinTreePosition) Q.dequeue();//出队 list.insertLast(u);//访问v if (u.hasLChild()) Q.enqueue(u.getLChild()); if (u.hasRChild()) Q.enqueue(u.getRChild()); } } }

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值