【数据结构】--初始树型结构 二叉树的基本操作模拟实现

发布于:2023-01-10 ⋅ 阅读:(379) ⋅ 点赞:(0)

了解树结构

在了解树结构之前,想必应该对链式结构和数组有了一定的了解,树的结构是也是一种特定的元素序列的集合,定义:树是非线性结构,它是由n(n>=0)个有限结点组成的集合,当n等于0时,称之为空树,在任意非空树中:

  • 有且只有一个特定的称之为根(root)的结点
  • 其余结点可以分为m个互不相交的有限集合
  • 这些有限集合可以看作是新的树,并且称为根的子树

树结构的基本名称

结点的度:一个结点含有子树的个数称为该结点的度;
树的度:一棵树中,所有结点度的最大值称为树的度;
叶子结点或终端结点:度为0的结点称为叶结点;
双亲结点或父结点:若一个结点含有子结点,则这个结点称为其子结点的父结点;
孩子结点或子结点:一个结点含有的子树的根结点称为该结点的子结点;
根结点:一棵树中,没有双亲结点的结点;其中一棵不为空树的树,根结点是唯一的,不存在有很多根节点
树的高度或深度:树中结点的最大层次;
非终端结点或分支结点:度不为0的结点;
兄弟结点:具有相同父结点的结点互称为兄弟结点;
堂兄弟结点:双亲在同一层的结点互为堂兄弟;
结点的祖先:从根到该结点所经分支上的所有结点;
子孙:以某结点为根的子树中任一结点都称为该结点的子孙。
森林:由m(m>=0)棵互不相交的树组成的集合称为森林

树的储存形式

树在内存中的储存形式有很多种,包括孩子表示法、双亲表示法、孩子双亲表示法、孩子兄弟表示法等等,不用的储存方式有着不同的优点,就比如双亲表示法,其子节点内存有双亲结点的地址,能够在时间复杂度为O(1)的情况下,访问到双亲结点,但是想要知道孩子结点,必须要访问整个结点。但是各种表示法都有一定缺点,接下来重点讲孩子兄弟表示法,这种方法给找某个结点的孩子带来了方便
但是如果想要想到这个结点的双亲结点,显然也是比较麻烦的,如果实在有必要,可以增加一个parent指针域来解决这个问题
这种方法最大的好处就是,可以将复杂的树结构,变为较为简单的二叉树结构
二叉树的特点

  • 每个结点最多只有两颗子树,其次是有一颗子树或者不存在子树
  • 拥有两个子树的结点,将这两颗子树称为这个结点的左子树和右子树,次序不能颠倒,即使是只有一颗子树,也被分为左子树和右子树,所以在这基础上,可以演变为二叉树有五种基本形态:空二叉树、只有根节点的二叉树、根结点只有左子树,根节点只有右子树,拥有左子树和右子树的根节点。

满二叉树和完全二叉树

在这里插入图片描述
如上图就是满二叉树,所以二叉树有以下特点:

  1. 二叉树除最后一层都是度为零的结点,也称之为叶子节点外,其余都是拥有左右度为二的结点
  2. 总结点的个数为2^(n-1),其中n为该满二叉树的深度
  3. 在同样深度的二叉树中,满二叉树拥有最多的节点数

完全二叉树
对于一颗具有n个结点的二叉树,对其进行层序编号,如果编号为i (i >= 1)的结点,与相同深度的满二叉树编号为i的结点在二叉树中位置完全相同,则这颗二叉树称为完全二叉树如下图:
在这里插入图片描述
二叉树的特点:

  • 叶子结点只能出现在最下两层,最下层叶子结点集中在左边,倒数第二层如果有叶子结点,一定集中在右部位置
  • 如果度数为一,则该节点只能拥有左节点
  • 同样结点的二叉树,完全二叉树拥有最小深度

二叉树的性质

  • 在二叉树的第i层上至多有2^(i-1)个结点,(i>=1)
  • 深度为k的二叉树至多有2^k -1个结点(k>=1)
  • 叶子结点树比度为二的结点树多一个
  • n个结点的完全二叉树的深度为[log 2 (N)] +1,([X]表示不大于x的最大整数)

二叉树的模拟实现

定义二叉树

    public static class TreeNode{
        public char val;
        public TreeNode left;
        public TreeNode right;

        public TreeNode(char val) {
            this.val = val;
        }
    }

求结点的个数size

    //方法一:遍历的思想求size
    int sumSize = 0;
    public int size(TreeNode root){
        if(root != null) sumSize++;

        if(root != null) size(root.left);
        if(root != null) size(root.right);
        return sumSize;
    }
    //方法二:子问题思路
    public int size2(TreeNode root){
        if(root == null) return 0;
        return size2(root.left) + size2(root.right) + 1;
    }

得到叶子结点的个数

    public static int leafSize = 0;
    public void getLeafNodeCount1(TreeNode root){
        if(root == null)return;
        if(root.left == null && root.right == null){
            leafSize++;
        }
        getLeafNodeCount1(root.left);
        getLeafNodeCount1(root.right);
    }

    public int getLeafNodeCount2(TreeNode root){
        if(root == null)return 0;
        if(root.left == null && root.right == null){
            leafSize++;
        }
        return getLeafNodeCount2(root.left) + getLeafNodeCount2(root.right);
    }

获取第k层结点的个数

    public int getKLevelNodeCount(TreeNode root,int k){
        if(root == null)return 0;
        if(k == 1 && root != null) return 1;
        return getKLevelNodeCount(root.left,k-1) + getKLevelNodeCount(root.right,k-1);
    }

获取二叉树的高度

    //获取二叉树高度
    public int getHeight(TreeNode root){
        if(root == null) return 0;
        return (getHeight(root.left)>getHeight(root.right)?getHeight(root.left):getHeight(root.right))+1;
    }

找到目标节点

    public TreeNode find(TreeNode root,char val){
        if(root == null) return null;
        if(root.val == val) return root;
        TreeNode ret = find(root.left,val);
        if(ret != null)
            return ret;
        ret = find(root.right,val);
        if(ret != null)
            return ret;
        return null;
    }

层序遍历

    public List<List<Character>> levelOrder2(TreeNode root){
        List<List<Character>> ret = new ArrayList<>();
        if(root == null)return ret;
        Queue<TreeNode> queue = new LinkedList<>();
        queue.offer(root);

        while(!queue.isEmpty()){
            int size = queue.size();
            List<Character> list = new ArrayList<>();
            while(size != 0){
                TreeNode cur = queue.poll();
                list.add(cur.val);
                size--;
                if(cur.left != null){
                    queue.offer(cur.left);
                }
                if(cur.right != null){
                    queue.offer(cur.right);
                }
            }
            ret.add(list);
        }
        return ret;
    }

判断一棵树是不是完全二叉树

    boolean isCompleteTree(TreeNode root){
        if(root == null) return false;
        Queue<TreeNode> queue = new LinkedList<>();
        queue.offer(root);
        while(!queue.isEmpty()){
            TreeNode cur = queue.poll();
            if(cur != null){
                queue.offer(cur.left);
                queue.offer(cur.right);
            }else{
                break;
            }
        }
        while(!queue.isEmpty()){
            TreeNode cur = queue.peek();
            if(cur == null){
                queue.poll();
            }else{
                return false;
            }
        }
        return true;
    }

网站公告

今日签到

点亮在社区的每一天
去签到