二叉树、二叉查找树与散列表区别、红黑树

一、二叉树
1、基本概念

树(tree)是n(n>=0)个结点的有限集,只有一个根节点,子树的数目没有限制,但一定是不想交的。树的定义用子递归的方式。节点的度:节点拥有子树的数目。

二叉树(binary tree)是指树中节点的度不大于2的有序树,它是一种最简单且最重要的树。

二叉树的递归定义为:二叉树是一棵空树,或者是一棵由一个根节点和两棵互不相交的,分别称作根的左子树和右子树组成的非空树;左子树和右子树又同样都是二叉树 。
二叉树、二叉查找树与散列表区别、红黑树_第1张图片

没有父节点的节点叫做根节点,图中F为根节点,C为A和D的父节点,A、D、H、G互为兄弟节点,没有子节点的节点叫做叶子节点或者叶节点,A 、B 、H、 M都是叶子节点。

小结:二叉树可以是空树(n>=0)。
二叉树特点:每个节点最多两颗子树,左子树,右子树(互不相交);左子树和右子树是有顺序的;即便树中某个节点只有一颗子树也要区分它是左子树还是右子树。

2、树的三个重要概念:高度(Height)、深度(Depth)、层(Level)

节点的高度=节点到叶子节点的最长路径 (边数)

​节点的深度=根节点到这个节点所经历的边的个数

节点的层数=节点的深度+1

树的高度=根节点的高度
二叉树、二叉查找树与散列表区别、红黑树_第2张图片

3、树的特殊类型
  • 满二叉树:如果一棵二叉树只有度为0的结点和度为2的结点,并且度为0的结点在同一层上,则这棵二叉树为满二叉树 。

  • 完全二叉树:深度为k,有n个结点的二叉树当且仅当其每一个结点都与深度为k的满二叉树中编号从1到n的结点一一对应时,称为完全二叉树 。
    二叉树、二叉查找树与散列表区别、红黑树_第3张图片

  • 左斜树 :所有节点都只有左子树

  • 右斜树 :所有节点都只有右子树
    二叉树、二叉查找树与散列表区别、红黑树_第4张图片
    在这里插入图片描述

小结:完全二叉树的特点:是叶子结点只可能出现在最下层或次下层;最下层叶子节点集中在树的左部;同样节点数目的二叉树,完全二叉树深度最小。
满二叉树特点:是所有分支都有左子树和右子树,所有叶子节点都在最底层;满二叉树一定是完全二叉树,反过来不一定成立。

4、二叉树的存储

一种是基于指针或者引用的二叉 链式存储法 ,一种是基于数组的 顺序存储法

1) 顺序存储

就是使用一维数组存储二叉树中节点,并且节点的存储位置就是数组的下标索引。

可以看出完全二叉树适合采用顺序存储结构。非完全二叉树会浪费一部分存储空间,极端情况下,右斜树会超级浪费空间。

2) 链式存储
二叉树每个节点有两个孩子,因此将节点数据结构定义为一个数据和两个指针域。
二叉树、二叉查找树与散列表区别、红黑树_第5张图片

小结:二叉树有两种存储方式,分别是顺序存储和链式存储。顺序存储适合完全二叉树,非完全二叉树的顺序存储会造成空间的相对浪费,所以转为链式存储。相对来说链式存储法我们比较常用。

5、二叉树的遍历

经典的方法:前序遍历、中序遍历和后序遍历。另外还有层次遍历。每个节点遍历一次,n个节点,遍历的时间复杂度都是 O(n)。
二叉树、二叉查找树与散列表区别、红黑树_第6张图片

前序遍历(根左右):A->B->D->E->C->F
中序遍历(左根右):D->B->E->A->F->C
后序遍历(左右根):D->E->B->F->C->A
前中后序遍历也可以看做树的深度优先搜索(DFS)

层次遍历(按照高度一层一层访问):A->B->C->D->E->F
层次遍历也可以看做树的宽度优先搜索(BFS)

代码实现此处先不描述,可另行查找理解,递归法,迭代法处理等。

小结:已知前序和中序遍历,或者已知中序和后序遍历都可以确定二叉树。前序遍历第一个访问的根节点,中序遍历根节点在中间,后序遍历最后访问根节点。

二、二叉查找树(二叉排序树)

二叉查找树要求,在树中的任意一个节点,其左子树中的每个节点的值,都要小于这个节点的值,而右子树节点的值都大于这个节点的值。
二叉查找树最大的特点就是,支持动态数据集合的快速插入、删除、查找操作。
特别是中序遍历二叉查找树,可以输出有序的数据序列,相当于升序排列,时间复杂度是 O(n),非常高效。因此,二叉查找树也叫作二叉排序树。

三、散列表和二叉查找树区别

第一,散列表中的数据是无序存储的,如果要输出有序的数据,需要先进行排序。而对于二叉查找树来说,我们只需要中序遍历,就可以在 O(n) 的时间复杂度内,输出有序的数据序列。

第二,散列表扩容耗时很多,而且当遇到散列冲突时,性能不稳定,尽管二叉查找树的性能不稳定,但是在工程中,我们最常用的平衡二叉查找树的性能非常稳定,时间复杂度稳定在 O(logn)。

第三,笼统地来说,尽管散列表的查找等操作的时间复杂度是常量级的,但因为哈希冲突的存在,这个常量不一定比 logn 小,所以实际的查找速度可能不一定比 O(logn) 快。加上哈希函数的耗时,也不一定就比平衡二叉查找树的效率高。

第四,散列表的构造比二叉查找树要复杂,需要考虑的东西很多。比如散列函数的设计、冲突解决办法、扩容、缩容等。平衡二叉查找树只需要考虑平衡性这一个问题,而且这个问题的解决方案比较成熟、固定。

最后,为了避免过多的散列冲突,散列表装载因子不能太大,特别是基于开放寻址法解决冲突的散列表,不然会浪费一定的存储空间。

综合这几点,平衡二叉查找树在某些方面还是优于散列表的,所以,这两者的存在并不冲突。我们在实际的开发过程中,需要结合具体的需求来选择使用哪一个。

四、红黑树

1、红黑树特点

  • 根节点是黑色的; 每个叶子节点都是黑色的空节点(NIL),也就是说,叶子节点不存储数据;
  • 任何相邻的节点都不能同时为红色,也就是说,红色节点是被黑色节点隔开的;
  • 每个节点,从该节点到达其可达叶子节点的所有路径,都包含相同数目的黑色节点;

2、红黑树意义:

红黑树是一种平衡二叉查找树。它是为了解决普通二叉查找树在数据更新的过程中,复杂度退化的问题而产生的。

红黑树的高度近似 log2n ,所以它是近似平衡,插入、删除、查找操作的时间复杂度都是 O(logn)。因为红黑树是一种性能非常稳定的二叉查找树,所以,在工程中,但凡是用到动态插入、删除、查找数据的场景,都可以用到它。不过,它实现起来比较复杂。

小结:
散列表:插入删除查找都是O(1), 是最常用的,但其缺点是不能顺序遍历以及扩容缩容的性能损耗。适用于那些不需要顺序遍历,数据更新不那么频繁的。
跳表:插入删除查找都是O(logn), 并且能顺序遍历。缺点是空间复杂度O(n)。适用于不那么在意内存空间的,其顺序遍历和区间查找非常方便。
红黑树:插入删除查找都是O(logn), 中序遍历即是顺序遍历,稳定。缺点是难以实现,去查找不方便。其实跳表更佳,但红黑树已经用于很多地方了。

数据结构 查找 插入 删除 遍历
数组 O(N) O(1) O(N) -
有序数组 O(logN) O(N) O(N) O(N)
链表 O(N) O(1) O(N) -
有序链表 O(N) O(N) O(N) O(N)
二叉树(一般情况) O(logN) O(logN) O(logN) O(N)
二叉树(最坏情况) O(N) O(N) O(N) O(N)
平衡树(一般情况和最坏情况) O(logN) O(logN) O(logN) O(N)
哈希表 O(1) O(1) O(1) -

3、红黑树的平衡调整
调整的过程包含两种基础的操作:左右旋转改变颜色,相对比较复杂,此处不过多描述。

你可能感兴趣的:(《数据结构与算法》系列,数据结构,二叉树,散列表,算法,java)