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 < Key1 ->  % 要插入的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 < Key1 ->
    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高的二叉树

gb_tree平衡树源码的更多相关文章

  1. LevelDB源码剖析

    LevelDB的公共部件并不复杂,但为了更好的理解其各个核心模块的实现,此处挑几个关键的部件先行备忘. Arena(内存领地) Arena类用于内存管理,其存在的价值在于: 提高程序性能,减少Heap ...

  2. 死磕 java集合之TreeMap源码分析(二)- 内含红黑树分析全过程

    欢迎关注我的公众号"彤哥读源码",查看更多源码系列文章, 与彤哥一起畅游源码的海洋. 插入元素 插入元素,如果元素在树中存在,则替换value:如果元素不存在,则插入到对应的位置, ...

  3. Java - TreeMap源码解析 + 红黑树

    Java提高篇(二七)-----TreeMap TreeMap的实现是红黑树算法的实现,所以要了解TreeMap就必须对红黑树有一定的了解,其实这篇博文的名字叫做:根据红黑树的算法来分析TreeMap ...

  4. 源码速读及点睛:HashMap

    Java 8 HashMap的分离链表 从Java 2到Java 1.7,HashMap在分离链表上的改变并不多,他们的算法基本上是相同的.如果我们假设对象的Hash值服从平均分布,那么获取一个对象需 ...

  5. 【转】【java源码分析】Map中的hash算法分析

    全网把Map中的hash()分析的最透彻的文章,别无二家. 2018年05月09日 09:08:08 阅读数:957 你知道HashMap中hash方法的具体实现吗?你知道HashTable.Conc ...

  6. JDK部分源码阅读与理解

    本文为博主原创,允许转载,但请声明原文地址:http://www.coselding.cn/article/2016/05/31/JDK部分源码阅读与理解/ 不喜欢重复造轮子,不喜欢贴各种东西.JDK ...

  7. 跟着大彬读源码 - Redis 9 - 对象编码之 三种list

    目录 1 ziplist 2 skiplist 3 quicklist 总结 Redis 底层使用了 ziplist.skiplist 和 quicklist 三种 list 结构来实现相关对象.顾名 ...

  8. Java源码解析|HashMap的前世今生

    HashMap的前世今生 Java8在Java7的基础上,做了一些改进和优化. 底层数据结构和实现方法上,HashMap几乎重写了一套 所有的集合都新增了函数式的方法,比如说forEach,也新增了很 ...

  9. Redis学习之zskiplist跳跃表源码分析

    跳跃表的定义 跳跃表是一种有序数据结构,它通过在每个结点中维持多个指向其他结点的指针,从而达到快速访问其他结点的目的 跳跃表的结构 关于跳跃表的学习请参考:https://www.jianshu.co ...

随机推荐

  1. IdentityServer Topics(2)- 定义资源

    您通常在系统设计中的第一件事就是您要保护的资源. 这可能是您的用户的身份信息,如个人资料数据或电子邮件地址,或访问API. 您可以使用C#对象模型定义资源(硬编码),或从数据存储中加载它们. IRes ...

  2. Codeforces 893F - Subtree Minimum Query

    893F - Subtree Minimum Query 题意 给出一棵树,每次询问 \(x\) \(k\),求以 \(x\) 为根结点的子树中的结点到结点 \(x\) 的距离小于等于 \(k\) 的 ...

  3. 【jQuery】(7)---jQueryAjax同步异步区别

    jQueryAjax同步异步 今天在项目开发过程中,要实现这么一个功能 <!-- 当我点击就业的时候,触发onclick时间,check()方法里通过ajax请求返回数据, 如果该用户已经毕业可 ...

  4. 加载进度圈,带遮罩层(jquery)

    如图: Js下载地址:http://files.cnblogs.com/files/holdon521/cvi_busy_lib.js 如下使用实例: <script src="/st ...

  5. H5中的web worker示例demo分析

    web worker 是运行在后台的 JavaScript,不会影响页面的性能. 什么是 Web Worker? 当在 HTML 页面中执行脚本时,页面的状态是不可响应的,直到脚本已完成. web w ...

  6. 探讨 java中 接口和对象的关系

    接口是对象么?接口可以有对象么?这个问题要跟类比对着,或许更好理解;类是对象的模版.接口不是类,所以:接口肯定不是对象的模版.那接口跟对象有什么样的关系?还是得从类入手;因为类实现了接口,所以可以说, ...

  7. python os 模块

    os.getcwd() 获取当前工作目录,即当前python脚本工作的目录路径os.chdir("dirname") 改变当前脚本工作目录:相当于shell下cdos.curdir ...

  8. Gym 101612C Consonant Fencity

    原题传送门 题意:给定一个只含小写字母的字符串,假设aeiouyw为元音字母,现在要把一些字母变为大写,要求相同字母的大小写必须相同,统计变化后的字符串中有多少对相邻.同为辅音字母且大小写不一样的字符 ...

  9. 最新版Sublime Text Build 3156 x64 的下载 + 注册码 + Install Package Control + 汉化教程

    一.Sublime Text  下载 神器 Sublime Text 最近开始更新到开发版本 Build 3156,本身英语不是太6,汉化党自然各种百度汉化教程,网上不是一堆绿色汉化包,就是让你下载汉 ...

  10. c++(八皇后)

    八皇后是一道很具典型性的题目.它的基本要求是这样的:在一个8*8的矩阵上面放置8个物体,一个矩阵点只允许放置一个物体,任意两个点不能在一行上,也不能在一列上,不能在一条左斜线上,当然也不能在一条右斜线 ...