数据结构--树详解(1)

1.树(tree)的概念

注释在线结构:https://www.cs.usfca.edu/~galles/visualization/Algorithms.html

:是n个节点的有限集合。当n=0时,称为空树。在任意一个非空树中,有且仅有一个特定的称为根(root)的节点。当n>1时,其余节点可分为m(m>0)个互不相交的有限集合 T1,T2 ,Tm,其中每一个集合又是一棵树,并且称为根的子树。

节点的度:节点拥有的子树个数称为节点的度。如下图B节点的度为2,J节点的度为1,度为0的节点称为叶子节点或终端节点(拥有一个节点的树),如 A,C,E,K

树的度:节点的度中最大值,为数的度,如下图树度为2

树的深度或高度:节点的层次从根开始定义起,根为第一层,根的孩子为第二层
如下如:
在这里插入图片描述

线性结构:

  • 第一个数据元素:无前驱。
  • 最后一个元素:无后继。
  • 中间元素:一个前驱一个后继。

树结构:

  • 根节点:无双亲,唯一。
  • 叶子节点:无孩子,可以多个。
  • 中间节点:一个双亲多个孩子。

2.树的存储结构

2.1 双亲表示法

结构代码定义:

@Data
public class TreeParentDemo {

    //根节点
    private  Node  root;

    public TreeDemo(String data) {
        this.root = new Node(data,null);
    }

    @Data
    class Node{

        public Node(String data, Node parent) {
            this.data = data;
            this.parent = parent;
        }

        /**
         * 数据域  存储A,B,C等
         */
       private String  data;

        /**
         * 指向父亲节点的地址
         */
        private Node parent;
    }

}

注释:根节点的父级地址设置为null,每个节点存储数据域和父级节点地址。

如下图:
在这里插入图片描述

数据库存储:

iddataparentId
0A-1
1B0
2C0
3D1
4E2
5F2
6G3
7H3
8I3
9J4

优点:1.查找已知节点的父节点很容易,直接通过父级节点地址找到它的双亲。所用时间复杂度为O[1]。
例如:已知F(5)节点 ,查找其父节点,可直接通过F节点中父级地址(id:2),直接查找。
缺点:1.查找已知节点的孩子节点,需要遍历整个数据结构才行.
例如:已知F(5)节点 ,查找其孩子节点,需要遍历正个数据结构,对比查找。如数据库执行 select * from 表 where parentId = 5 需要扫描整个数据行一一对比(该表parentId未加索引的情况下).

2.2 孩子表示发

结构代码定义:

@Data
public class TreeChildDemo {

    //根节点
    private  Node  root;

    public TreeChildDemo(String data, List<Node> childList) {
        this.root = new Node(data,childList);
    }

    @Data
    class Node{

        public Node(String data, List<Node> childList) {
            this.data = data;
            this.childList = childList;
        }

        /**
         * 数据域  存储A,B,C等
         */
       private String  data;

        /**
         * 指向孩子节点的地址(可为数组arraylist或单链表linkArralist)(一个双亲可有多个孩子)
         */
        private List<Node> childList;
    }


注释:双亲节点可有多个孩子,故节点用一个集合来存储,该集合可为LinkArrayList 单链表结构存储,也可为ArrayList 数组结构存储

如图:

在这里插入图片描述
数据库存储:

iddatachildId
0A1,2
1B3
2C4,5
3D6,7,8
4E9
5FNull
6GNull
7HNull
8INull
9JNull

优点:1.已知节点查找其孩子节点,比较容易直接通过节点孩子节点地址即可查找到,若是查找某个孩子,遍历集合(底层为单链表或数组),时间复杂度为O[1].
例如:已知D(5)节点 ,查找其孩子点,可直接通过F节点中孩子地址(id:6,id:7,id:8),直接查找。
缺点:1.已知节点查找其父节点,需要遍历整个数据结构查找,如D
父级节点:select * from table where childId like ‘7,%’ or childId like ‘%,7,%’ or childId like ‘%,7’ 需要扫描整个数据行一一对比(该表childId未加索引的情况下).
2.节点的度没办法控制,孩子越多度的值越大。
注释:多唠叨一句这里既是加索引也无效,%,7,% 和 %,7 会使索引失效,or 必须都走索引 ,整个条件才会走索引

2.3.孩子兄弟表示发

结构代码定义:

@Data
public class TreeChildBrothersDemo {

    //根节点
    private  Node  root;

    public TreeChildBrothersDemo(String data, Node firstChild, Node rightBrother) {
        this.root = new Node(data,firstChild,rightBrother);
    }

    @Data
    class Node{

        public Node(String data, Node firstChild, Node rightBrother) {
            this.data = data;
            this.firstChild = firstChild;
            this.rightBrother = rightBrother;
        }

        /**
         * 数据域  存储A,B,C等
         */
       private String  data;

        /**
         * 第一个孩子
         */
        private Node firstChild;

        /**
         * 该节点的右兄弟
         */
        private  Node  rightBrother;
    }

}

如图:

注释:这里必须用弄清楚,孩子为该节点第一个最左边孩子,兄弟为该节点的右兄弟。如:D 是B的第一个孩子,C 是B的右兄弟。
与上边两种表示方法不同,双亲和孩子表示法树的深度和度都为4和3,孩子兄弟表示法树的深度为6 而树的度为2 (二叉树)
也就是把树转换为二叉树存储结构来存储。

在这里插入图片描述
数据库存储:

iddatafirstchildrightBrother
0A1Null
1B32
2C4Null
3D6Null
4E95
5FNullNull
6GNull7
7HNull8
8INullNull
9JNullNull

优点:1.已知某个节点查找某个孩子节点,只需要通过firstchild 找到第一个孩子(最左边孩子),通过该孩子的rightBrother ,查找第二个孩子… 一直查找下去,直到查找到具体孩子。
2.该树的度是固定的为2 ,其实这个表示法最大的好处就是把一棵树变成了一棵二叉树。
缺点:1已知节点查找其父节点,需要遍历整个数据结构查找,如D
父级节点:select * from table where firstchild = 3 or rightBrother= 3 需要扫描整个数据行一一对比(该表firstchild ,rightBrother 未加索引的情况下).

注释:如果真的有必要,完全可以再增加一个parentId 指针域来解决快速查找的双亲的问题。

3.二叉树

3.1二叉树概念:二叉树是n(n>=0)个节点的有限集合,该集合或者为空集,或者有一个根节点和两棵互不相交的,分别称为根节点的左子树和右子树的二叉树组成。

注释:通俗的讲就是树的度为2的树,就是二叉树数。

3.2二叉树特点:

  1. 每棵树最多有两颗子树,也就是二叉树的度不能大于2。
  2. 左子树和右子树是有顺序的,次序不能任意颠倒。
  3. 即使树中有一棵子树,也要区分左子树还是右子树 。如下图,树1和树2 他们是同一棵树,但是它们是不同的二叉树。

在这里插入图片描述

3.3 特殊二叉树

1.斜树:所有节点都只有左子树的二叉树叫左斜树 如下图 树1。所有节点都是只有右子树的二叉树叫右斜树,如下图 树2这两者统称为斜树
在这里插入图片描述
2.满二叉树:在一颗二叉树中,如果所有分支节点都存在左子树和右子树,并且所有叶子节点都在同一层上,这样的二叉树称为满二叉树
如下图就是一棵满二叉树
在这里插入图片描述
3.完全二叉树

完全二叉树:对一个棵具有n个节点的二叉树按层序编号,如果编号为i(1<=i >=n)的节点与同样深度的满二叉树中编号为i的节点在二叉树中位置完全相同,则这颗二叉树称为完全二叉树。

如下图 树1 为完全二叉树,树2 和树3 不能为完全二叉树。
在这里插入图片描述
4.二叉树的性质:

  1. 在二叉树的第i层上至多有2^(i-1) 个节点(i>=1)。
  2. 深度为k的二叉树至多有2^k -1 个节点。
  3. 度为0的节点数N0 ,度为2的节点数N2 关系为N0=N2+1。
  4. 具有n个节点的完全二叉树的深度为|Log2^n|+1

3.4 二叉树的存储

1.结构代码定义:

@Data
public class TwoThree {

    private  Node root;

    public TwoThree(Integer data) {
        this.root = new Node(data);
    }


    class Node{

        public Node(Integer data) {
            this.data = data;
            this.leftChild = null;
            this.rightChild = null;
        }

        /**
         * 数据域
         */
        Integer data;
        /**
         * 左孩子地址
         */
        private  Node  leftChild;
        /**
         * 右孩子地址
         */
        private Node  rightChild;
    }
}

如图
在这里插入图片描述

数据库存储(这里用数据库表示不太准确):

iddataleftchildrightchild
0A12
1B34
2C56
3D78
4E9Null
5FNullNull
6GNullNull
7HNullNull
8INullNull
9JNullNull

2.二叉树的遍历:

1.先序遍历

/**
     * 先序遍历(第一次访问节点的时候打印节点)
     * @param node
     */
    public  void preOrderX(Node node) {
        if(node == null) {
            return ;
        }
        System.out.println(node.data);
        preOrderX(node.leftChild);
        preOrderX(node.rightChild);
    }
结果:ABDHIEJACFG

2.中序遍历

/**
     * 中序遍历(第二次访问节点的时候打印节点)
     * @param node
     */
    public  void preOrderX(Node node) {
        if(node == null) {
            return ;
        }
        preOrderX(node.leftChild);
        System.out.println(node.data);
        preOrderX(node.rightChild);
    }
结果:HDIBJEAFCG

2.后序遍历

/**
     * 中序遍历(第三次访问节点的时候打印节点)
     * @param node
     */
    public  void preOrderX(Node node) {
        if(node == null) {
            return ;
        }
        preOrderX(node.leftChild);
        preOrderX(node.rightChild);
        System.out.println(node.data);
    }
结果:HIJEBFGCA
  • 1
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值