热门标签 | HotTags
当前位置:  开发笔记 > 编程语言 > 正文

gb_tree平衡树源码

1.平衡树简称AVL,出名的有红黑树,这里介绍一下gb_tree的实现gb_tree的原理比红黑树简单,没有过多的旋转跳跃闭着眼,是一种叫AA树的结构(ArneAnderssonsGene

1.平衡树简称AVL,出名的有红黑树,这里介绍一下gb_tree的实现

  gb_tree的原理比红黑树简单,没有过多的旋转跳跃闭着眼,是一种叫AA树的结构(Arne Andersson's General Balanced Trees),有兴趣看这篇论文:传送门

2.结构

{Size, Tree}  是整个结构体,Tree的定义又是 {Key, Value, Smaller, Bigger} | nil

初始化直接返回{0, nil}

3.插入

insert(Key, Val, {S, T}) when is_integer(S) ->  
S1 = S+1,
{S1, insert_1(Key, Val, T, ?pow(S1, ?p))}. % 给size+1,insert_1返回新的结构

 insert_1又是如何找到要插入的位置,且做平衡的?

% 由于对称性,这里讲插入左子树的情况就行
insert_1(Key, Value, {Key1, V, Smaller, Bigger}, S) when Key % 要插入的key比目前节点的key小
case insert_1(Key, Value, Smaller, ?div2(S)) of
% 递归,在目前节点的左子树继续查找,当Smaller为nil的时候返回下面两种情况
% T1 就是已经更新好的左子树
{T1, H1, S1} ->
T = {Key1, V, T1, Bigger},
{H2, S2} = count(Bigger),
H = ?mul2(erlang:max(H1, H2)), %% 每层都会被调用一次
SS = S1 + S2 + 1,
P = ?pow(SS, ?p),
if
H > P -> % 满足这个条件就重新平衡
balance(T, SS);
true ->
{T, H, SS}
end;
T1 ->
{Key1, V, T1, Bigger} % 结果--节点和右子树均没改变,T1改变
end;

4.平衡

也就是上面的balance(T, SS),这里什么时候会被执行呢?看一下下面代码

%% 是的insert_1的{T1,H1, S1}分支被执行
insert_1(Key, Value, nil, S) when S =:= 0 ->
{{Key, Value, nil, nil}, 1, 1};

看看官方的说明

也就是说 13行的H>P就是重新进行平衡的时候了,而平衡的操作也很简单,看下代码,就是按顺序填满一棵树

balance_list_1(L, S) when S > 1 ->
Sm = S - 1,
S2 = Sm div 2,
S1 = Sm - S2,
{T1, [{K, V} | L1]} = balance_list_1(L, S1),
{T2, L2} = balance_list_1(L1, S2),
T = {K, V, T1, T2},
{T, L2};
balance_list_1([{Key, Val} | L], 1) ->
{{Key, Val, nil, nil}, L};
balance_list_1(L, 0) ->
{nil, L}.

5.删除

删除比插入是更简单了,找到对应的结点,然后从结点的右子树里找到一个最小的代替当前的点

delete_1(Key, {Key1, Value, Smaller, Larger}) when Key 
Smaller1 = delete_1(Key, Smaller),
{Key1, Value, Smaller1, Larger};
delete_1(Key, {Key1, Value, Smaller, Bigger}) when Key > Key1 ->
Bigger1 = delete_1(Key, Bigger),
{Key1, Value, Smaller, Bigger1};
delete_1(_, {_, _, Smaller, Larger}) ->
merge(Smaller, Larger).

merge(Smaller, nil) ->
Smaller;
merge(nil, Larger) ->
Larger;
merge(Smaller, Larger) ->
{Key, Value, Larger1} = take_smallest1(Larger),
{Key, Value, Smaller, Larger1}.

可以看到整棵树没有旋转等复杂操作,但是仍是一个效率比lists高的二叉树

 


推荐阅读
  • 十大经典排序算法动图演示+Python实现
    本文介绍了十大经典排序算法的原理、演示和Python实现。排序算法分为内部排序和外部排序,常见的内部排序算法有插入排序、希尔排序、选择排序、冒泡排序、归并排序、快速排序、堆排序、基数排序等。文章还解释了时间复杂度和稳定性的概念,并提供了相关的名词解释。 ... [详细]
  • 欢乐的票圈重构之旅——RecyclerView的头尾布局增加
    项目重构的Git地址:https:github.comrazerdpFriendCircletreemain-dev项目同步更新的文集:http:www.jianshu.comno ... [详细]
  • 本文介绍了解决Facebook脸书面试题中插入区间的方法,通过模拟遍历的方式判断当前元素与要插入元素的关系,找到插入点并将新区间插入。同时对算法的时间复杂度和空间复杂度进行了分析。 ... [详细]
  • 上图是InnoDB存储引擎的结构。1、缓冲池InnoDB存储引擎是基于磁盘存储的,并将其中的记录按照页的方式进行管理。因此可以看作是基于磁盘的数据库系统。在数据库系统中,由于CPU速度 ... [详细]
  • MySQL多表数据库操作方法及子查询详解
    本文详细介绍了MySQL数据库的多表操作方法,包括增删改和单表查询,同时还解释了子查询的概念和用法。文章通过示例和步骤说明了如何进行数据的插入、删除和更新操作,以及如何执行单表查询和使用聚合函数进行统计。对于需要对MySQL数据库进行操作的读者来说,本文是一个非常实用的参考资料。 ... [详细]
  • 本文介绍了使用PHP实现断点续传乱序合并文件的方法和源码。由于网络原因,文件需要分割成多个部分发送,因此无法按顺序接收。文章中提供了merge2.php的源码,通过使用shuffle函数打乱文件读取顺序,实现了乱序合并文件的功能。同时,还介绍了filesize、glob、unlink、fopen等相关函数的使用。阅读本文可以了解如何使用PHP实现断点续传乱序合并文件的具体步骤。 ... [详细]
  • Python正则表达式学习记录及常用方法
    本文记录了学习Python正则表达式的过程,介绍了re模块的常用方法re.search,并解释了rawstring的作用。正则表达式是一种方便检查字符串匹配模式的工具,通过本文的学习可以掌握Python中使用正则表达式的基本方法。 ... [详细]
  • 本文讨论了Kotlin中扩展函数的一些惯用用法以及其合理性。作者认为在某些情况下,定义扩展函数没有意义,但官方的编码约定支持这种方式。文章还介绍了在类之外定义扩展函数的具体用法,并讨论了避免使用扩展函数的边缘情况。作者提出了对于扩展函数的合理性的质疑,并给出了自己的反驳。最后,文章强调了在编写Kotlin代码时可以自由地使用扩展函数的重要性。 ... [详细]
  • 本文介绍了iOS数据库Sqlite的SQL语句分类和常见约束关键字。SQL语句分为DDL、DML和DQL三种类型,其中DDL语句用于定义、删除和修改数据表,关键字包括create、drop和alter。常见约束关键字包括if not exists、if exists、primary key、autoincrement、not null和default。此外,还介绍了常见的数据库数据类型,包括integer、text和real。 ... [详细]
  • 开发笔记:实验7的文件读写操作
    本文介绍了使用C++的ofstream和ifstream类进行文件读写操作的方法,包括创建文件、写入文件和读取文件的过程。同时还介绍了如何判断文件是否成功打开和关闭文件的方法。通过本文的学习,读者可以了解如何在C++中进行文件读写操作。 ... [详细]
  • MyBatis多表查询与动态SQL使用
    本文介绍了MyBatis多表查询与动态SQL的使用方法,包括一对一查询和一对多查询。同时还介绍了动态SQL的使用,包括if标签、trim标签、where标签、set标签和foreach标签的用法。文章还提供了相关的配置信息和示例代码。 ... [详细]
  • Go语言实现堆排序的详细教程
    本文主要介绍了Go语言实现堆排序的详细教程,包括大根堆的定义和完全二叉树的概念。通过图解和算法描述,详细介绍了堆排序的实现过程。堆排序是一种效率很高的排序算法,时间复杂度为O(nlgn)。阅读本文大约需要15分钟。 ... [详细]
  • Day2列表、字典、集合操作详解
    本文详细介绍了列表、字典、集合的操作方法,包括定义列表、访问列表元素、字符串操作、字典操作、集合操作、文件操作、字符编码与转码等内容。内容详实,适合初学者参考。 ... [详细]
  • Java学习笔记之使用反射+泛型构建通用DAO
    本文介绍了使用反射和泛型构建通用DAO的方法,通过减少代码冗余度来提高开发效率。通过示例说明了如何使用反射和泛型来实现对不同表的相同操作,从而避免重复编写相似的代码。该方法可以在Java学习中起到较大的帮助作用。 ... [详细]
  • 本文介绍了使用哈夫曼树实现文件压缩和解压的方法。首先对数据结构课程设计中的代码进行了分析,包括使用时间调用、常量定义和统计文件中各个字符时相关的结构体。然后讨论了哈夫曼树的实现原理和算法。最后介绍了文件压缩和解压的具体步骤,包括字符统计、构建哈夫曼树、生成编码表、编码和解码过程。通过实例演示了文件压缩和解压的效果。本文的内容对于理解哈夫曼树的实现原理和应用具有一定的参考价值。 ... [详细]
author-avatar
1輩孓莣8鋽
这个家伙很懒,什么也没留下!
PHP1.CN | 中国最专业的PHP中文社区 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved | 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有