树结构
认识树结构
树的特点
- 树通常有一个根。连接着根的是树干
- 树干到上面之后会进行分叉成树枝,树枝还会分又成更小的树枝
- 在树枝的最后是叶子
树的抽象
- 树可以模拟生活中的很多场景,比如:公司组织架构、家谱、DOM Tree、电脑文件夹架构
优秀的哈希函数(补充)
- 快速计算:霍纳法则
- 均匀分布:质数(长度、幂的底)
树结构优点
数据结构对比
数组
- 优点
- 数组的主要优点是根据 下标值访问 效率会很高
- 但是如果我们希望根据元素来查找对应的位置呢?
- 比较好的方式先对数组进行排序,再进行二分查找
- 缺点
- 需要 先对数组进行排序,生成有序数组,才能提高查找效率
- 另外数组和插入和删除数据时,需要有大量的位移操作(插入到首位或者中间位置的时候)效率很低
链表
- 优点
- 链表的插入和删除操作效率都很高
- 缺点
- 查找效率很低,需要从头开始依次访问链表中的每个数据项,直到找到
- 而且即使插入和删除操作操作效率很高,但是如果要插入和删除中间位置的数据,还是需要从头先找到对应的数据
哈希表
- 优点
- 哈希表的插入、查询、删除效率都是非常高的
- 缺点
- 空间利用率不高,底层使用的数组,并且某些单元是没有被利用的
- 哈希表中的元素是无序的,不能安装固定的顺序来遍历哈希表中的元素
- 不能快速的找出哈希表中的 最大值或最小值 这些特殊的值
树
- 不能说树结构比其他结构都要好,因为 每种数据结构都有自己的特定的应用场景
- 但是树确实综合了上面的数据结构的优点,并且弥补了上面数据结构的缺点
而且模拟某些场景,我们使用树结构会更加方便
- 因为数结构的非线性,可以表示一对多的关系
- 比如:文件的目录结构
树结构术语
不过大部分术语都与真实世界的树相关,或者和家庭关系相关(如父节点和子节点)
树(Tree):n(n>=0)个节点构成的有限集合
- 当 n=0 时,称为空树
对于任一颗非空树(n>0),它具备以下性质:
- 树中有一个称为 "根(Root)" 的特殊节点,用 r 表示
- 其余节点可分为 m(m>0)个互不相交的有限集 T1、T2...Tm,其中每个集合本身又是一棵树,称为原来数的 "子树(SubTree)"
- 节点的度(Degree):节点的子树个数
- 树的度(Degree):树的所有节点的最大度数
- 叶节点(Leaf):度为 0 的节点(也称为叶子节点)
- 父节点(Parent):有子树节点时其子树的根节点的父节点
- 子节点(Child):若 A 节点是 B 节点的父节点,则称 B 节点是 A 节点的子节点,子节点也称孩子节点
- 兄弟节点(Sibling):具有同一父节点的各节点彼此是兄弟节点
- 路径和路径长度:从节点 n1 到 nk 的路径为一个节点序列 n1、n2...nk
- ni 是 n(i+1) 的父节点
- 路径所包含边的个数为路径的长度
- 节点的层次(Level):规定节点在 1 层,其它任一节点的层数是其父节点的层数+1
- 树的深度(Depth):树中所有节点中的最大层次是这棵树的深度
树结构表示方法
所有的数本质上都可以使用二叉树模拟出来
认识二叉树
二叉树分类
如果树中每个节点 最多只能有两个子节点,这样的数就称为 "二叉树"
- 二叉树可以为空,也就是没有节点
- 若不为空,则它是由根节点和称为其 左子树TL 和 右子树TR 的两个不相交的二叉树组成
二叉树有几个比较重要的特性,笔试题中比较常见:
- 一颗二叉树第 i 层的最大节点树为:
2^(i-1), i>=1
- 深度为 k 的二叉树有最大节点总数为:
2^k-1, k>=1
- 对任何非空二叉树 T,若 n0 表示叶子点的个数,n2 是度为 2 的非叶节点个数,那么两者满足关系 n0=n2+1
完美二叉树(Perfect Binary Tree),也称满二叉树(Full Binary Tree)
- 在二叉树中,除了下一层的叶节点外,每层节点都有 2 个子节点,就构成了满二叉树
完全二叉树(Complete Binary Tree)
- 除二叉树最后一层外,其它各层的节点个数都达到最大个数
- 最后一层从左到右的叶节点连续存在,只缺右侧若干节点
- 完美二叉树是特殊的完全二叉树
二叉树存储方式
二叉树的存储常见的方式是数组和链表
二叉树最常见的方式还是使用链表存储
- 每个节点封装成一个 Node,Node 中包含存储的数据,左节点的引用,右节点的引用
二叉搜索树
二叉搜索树(BST,Binary Search Tree),也称二叉排序树或二叉查找树
二叉搜索树是一颗二叉树,可以为空,如果不为空,满足以下性质:
- 非空左子树的所有键值小于根节点的键值
- 非空右子树的所有键值大于其根节点的键值
- 左、右子树本身也都是二叉搜索树
这种方式就是二分查找的思想:
- 查找所需的最大次数等于二叉搜索树的深度
- 插入节点,也利用类似的方法,一层层比较大小,找到新节点合适的位置
认识平衡树
二叉搜索树缺陷
二叉搜索树作为数据存储的结构有重要的优势
- 可以快速地找到给定关键字的数据项,并且可以快速地插入和删除数据项
但是,二叉搜索树有一个很麻烦的问题:
- 如果插入的数据是有序的数据,比如下面的情况
- 有一颗初始化为 9、8、12 的二叉树
- 插入下面的数据:7、6、5、4、3
非平衡树
- 比较好的二叉搜索树数据应该是 左右分布均匀 的
- 但是插入 连续数据 后,分布的不均匀,称这种树为非平衡树
- 对于一颗平衡二叉树来说,插入/查找等操作的效率是 O(logN)
- 对于一颗非平衡二叉树,相当于编写了一个链表,查找效率变成了 O(N)
考虑平衡性
为了能以较快的时间 O(log N)来操作一棵树,我们需要保证树总是平衡的
- 至少大部分是平衡的,那么时间复杂度也是接近 O(logN) 的
- 也就是说树中 每个节点左边的子孙节点的个数,应该尽可能的等于 右边的子孙节点的个数
AVL 树
- AVL 树是最早的一种平衡树,它有些办法保证树的平衡(每个节点存储了一个额外的数据)
- 因为 AVL 树是平衡的,所以时间复杂度也是 O(logN)
- 但是,每次插入/删除操作相对于红黑树效率都不高,所以整体效率不如红黑树
红黑树
- 红黑树也通过一些特性来保持树的平衡
- 因为是平衡树,所以时间复杂度也是 O(logN)
- 另外插入/删除等操作,红黑树的性能要优于 AVL 树,所以现在平衡树的应用基本都是红黑树