一篇理解-链表,哈希表,二叉树,平衡二叉树,B树,B+树

18 篇文章 0 订阅

链表:

链表的概念:链表是一种物理存储结构上非连续,非顺序的存储结构,数据元素的逻辑顺序是通过链表中的指针链接次序实现的。

链表的结构是多式多样的,当时通常用的也就是两种:

 

无头单向非循环列表:结构简单,一般不会单独用来存放数据。
                   实际中更多是作为其他数据结构的子结构,比如说哈希桶等等。
带头双向循环链表:结构最复杂,一般单独存储数据。实际中经常使用的链表数据结构,
                 都是带头双向循环链表。这个结构虽然复杂,
                 但是使用代码实现后会发现这个结构会带来很多优势,实现反而简单了。

单链表和双链表的区别:

单链表的每一个节点中只有指向下一个结点的指针,不能进行回溯,适用于节点的增加和删除。

双链表的每一个节点给中既有指向下一个结点的指针,也有指向上一个结点的指针,
可以快速的找到当前节点的前一个节点,适用于需要双向查找节点值的情况。

 哈希表:

哈希表简介:

哈希表也叫散列表,哈希表是一种数据结构,它提供了快速的插入操作和查找操作,
无论哈希表总中有多少条数据,插入和查找的时间复杂度都是为O(1),因为哈希表的查找速度非常快,
所以在很多程序中都有使用哈希表,例如拼音检查器。

哈希表也有自己的缺点,哈希表是基于数组的,我们知道数组创建后扩容成本比较高,
所以当哈希表被填满时,性能下降的比较严重。

哈希函数:

哈希函数的写法有很多中,我们来看看「HashMap」中的哈希函数

static final int hash(Object key) {
        int h;
        return (key == null) ? 0 : (h = key.hashCode()) ^ (h >>> 16);
    }

「HashMap」中利用了「hashCode」来完成这个转换。哈希函数不管怎么实现,都应该满足下面三个基本条件:

  • 散列函数计算得到的散列值是一个非负整数
  • 如果 key1 = key2,那 hash(key1) == hash(key2)
  • 如果 key1 ≠ key2,那 hash(key1) ≠ hash(key2)
第一点:因为数组的下标是从0开始,所以哈希函数生成的哈希值也应该是非负数

第二点:同一个key生成的哈希值应该是一样的,因为我们需要通过key查找哈希表中的数据

第三点:看起来非常合理,但是两个不一样的值通过哈希函数之后可能才生相同的值,
        因为我们把巨大的空间转出成较小的数组空间时,不能保证每个数字都映射到数组空白处。
        所以这里就会才生冲突,在哈希表中我们称之为哈希冲突

哈希冲突:

哈希冲突是不可避免的,我们常用解决哈希冲突的方法有两种「开放地址法」「链表法」

开放地址法:在开放地址法中,若数据不能直接存放在哈希函数计算出来的数组下标时,就需要寻找其他位置来存放。在开放地址法中有三种方式来寻找其他的位置,分别是「线性探测」「二次探测」「再哈希法」

链表法:开放地址法中,通过在哈希表中再寻找一个空位解决冲突的问题,还有一种更加常用的办法是使用「链表法」来解决哈希冲突。「链表法」相对简单很多,「链表法」是每个数组对应一条链表。当某项关键字通过哈希后落到哈希表中的某个位置,把该条数据添加到链表中,其他同样映射到这个位置的数据项也只需要添加到链表中,并不需要在原始数组中寻找空位来存储。

HashMap的存储和查询过程:

1.获取key,计算key的hash值
2.通过key的哈希值,定位到value存储的位置
3.去value存储的位置进行存储或者读取(IO输入输出)

 特点:每个key无论是存储还是读取都是一次IO,因此时间复杂度是O(1)

缺点: 当数据量大时候,链表链接的节点过多,存储和读取性能会逐渐降低为O(n)

            哈希索引不适合做范围查询和排序

从二分法到二叉树:        

二分法是我们常用的一种查找算法,可以有效的提升数据找找的效率,其实现思路是:

1、首先对数据集进行排序。

2、找到数据集中间位置的节点。

3、用查找的条件和间节点进行比较,等于则直接返回,中间节点数据小于查找条件则说明数据在排序列表的左边,大于则说明数据在排序列表的右边。

 从二分法查找的过程来看,如果能保证数据的有序性,并且预先把数据进行分段存储好数据的中间节点,那么查找的时候就会很简单,所以如果要使用二分法,我们通常都会在数据存储的时候就预先把数据整理成适合二分法查找的数据结构,这就演化出了树和跳表两种数据结构, 这里我们主要来了解树的结构, 比如我们把上面的[9,2,6,5,7,8,4,3,1] 构建成一个二叉树,那么就是下面这样

 特点:相较于哈希表进行优化,每次IO都可以淘汰50%的数据,从而提升查询的效率

            时间复杂度为O(logn):对分查找

缺点:可能退化成为链表

二叉查找树充分了利用二分法的思维提升了数据查找的效率,不过我们在构建二叉树的时候就会发现很容易出现一个问题, 就是二叉查找树的“高度”不稳定,同样的数据插入的先后顺序不一样,就很有可能变成下图一样的结构。

 

平衡二叉树:

  • 概念:平衡二叉树是基于二分法的策略提高数据的查找速度的二叉树的数据结构;

平衡二叉树是采用二分法思维把数据按规则组装成一个树形结构的数据,用这个树形结构的数据减少无关数据的检索,大大的提升了数据检索的速度;平衡二叉树的数据结构组装过程有以下规则:

(1)非叶子节点只能允许最多两个子节点存在。

(2)每一个非叶子节点数据分布规则为左边的子节点小当前节点的值,右边的子节点大于当前节点的值(这里值是基于自己的算法规则而定的,比如hash值);

平衡树的层级结构:因为平衡二叉树查询性能和树的层级(h高度)成反比,h值越小查询越快、为了保证树的结构左右两端数据大致平衡降低二叉树的查询难度,一般会采用平衡算法将二叉树重新构建,实现了这种算法的有比如Treap、红黑树,使用平衡二叉树能保证数据的左右两边的节点层级相差不会大于1.,通过这样避免树形结构由于删除增加变成线性链表影响查询效率,保证数据平衡的情况下查找数据的速度近于二分法查找;

总结平衡二叉树特点:

(1)非叶子节点最多拥有两个子节点;

(2)非叶子节值大于左边子节点、小于右边子节点;

(3)树的左右两边的层级数相差不会大于1;

(4)没有值相等重复的节点;

缺点:如果数据量大的话,树依旧很高

B树(B-tree):

又叫平衡树,但是这里强调的是平衡而去掉了二叉,就说明每个节点可以有多个子节点,拥有的子节点数量多了,树的高度就下降了

  • 规则:

(1)排序方式:所有节点关键字是按递增次序排列,并遵循左小右大原则;

(2)子节点数:非叶节点的子节点数>1,且<=M ,且M>=2,空树除外(注:M阶代表一个树节点最多有多少个查找路径,M=M路,当M=2则是2叉树,M=3则是3叉);

(3)关键字数:枝节点的关键字数量大于等于ceil(m/2)-1个且小于等于M-1个(注:ceil()是个朝正无穷方向取整的函数 如ceil(1.1)结果为2);

(4)所有叶子节点均在同一层、叶子节点除了关键字和关键字记录的指针外也有指向其子节点的指针只不过其指针地址都为null对应下图最后一层节点的空格子;

特点:

B树相对于平衡二叉树的不同是,每个节点包含的关键字增多了,特别是在B树应用到数据库中的时候,数据库充分利用了磁盘块的原理(磁盘数据存储是采用块的形式存储的,每个节点的默认大小 16 KB,每次IO进行数据读取时,同一个磁盘块的数据可以一次性读取出来)把节点大小限制和充分使用在磁盘快大小范围;把树的节点关键字增多后树的层级比原来的二叉树少了,减少数据查找的次数和复杂度;

缺点:

  • BTree 每个节点都存原始数据,都是数据节点,没有目录节点。
  • 每个节点的默认大小 16 KB,存了数据,能够用来存『主键 + 页码』的空间就不够了
  • 每个节点容纳子节点的数量就很少,导致深度增加
  • 对于查询来说:深度增加 1 层,I/O 次数增加一次
  • 所以性能方面 BTree 不如 B+Tree

B+树:

概念:

B+树是B树的一个升级版,相对于B树来说B+树更充分的利用了节点的空间,让查询速度更加稳定,其速度完全接近于二分法查找。

  • 规则

1)B+跟B树不同B+树的非叶子节点不保存关键字记录的指针(本身数据),只进行数据索引,这样使得B+树每个非叶子节点所能保存的子节点指针大大增加;

(2)B+树叶子节点保存了父节点的所有关键字记录的指针,所有数据地址必须要到叶子节点才能获取到。所以每次数据查询的次数都一样;

(3)B+树叶子节点的关键字从小到大有序排列,左边结尾数据都会保存右边节点开始数据的指针。

(4)非叶子节点的子节点数<关键字数

 

 最终形成:

 一整棵 B+Tree 能够存储多少条记录?
        一层:16条
        两层:16*1024条
        三层:16*1024*1024条
        四层:16*1024*1024*1024条

  • 特点

1、B+树的层级更少:相较于B树B+每个非叶子节点存储的关键字数更多,树的层级更少所以查询数据更快;

2、B+树查询速度更稳定:B+所有关键字数据地址都存在叶子节点上,所以每次查找的次数都相同所以查询速度要比B树更稳定;

3、B+树天然具备排序功能:B+树所有的叶子节点数据构成了一个有序链表,在查询大小区间的数据时候更方便,数据紧密性很高,缓存的命中率也会比B树高。

4、B+树全节点遍历更快:B+树遍历整棵树只需要遍历所有的叶子节点即可,,而不需要像B树一样需要对每一层进行遍历,这有利于数据库做全表扫描。

B树相对于B+树的优点是,如果经常访问的数据离根节点很近,而B树非叶子节点本身存有关键字其数据的地址,所以这种数据检索的时候会要比B+树快。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值