Erlang数据结构

array

与那些破坏性(动态改变变量的值)语言相比,erlang array 没有固定的时间插入和查找,所以效率不高,在实践中很少使用。
array以tuple-tree实现:

-record(array, {
    size,         %% number of defined entries
    max,          %% maximum number of entries
    default,      %% the default value (usually 'undefined')
    elements      %% the tuple tree
}).

proplists

适用数据量较少的场景,处理配置文件和函数选项时常用,proplists对内部数据结构是Key-Value键值对形式,第一个元素做key用来查询和删除,如果一个key有多个值就会使用第一次出现的值,其它被忽略。Key进行比较使用的是=:=精确等于,会判断类型和值。

orddict

用List实现的有序Dictionary,orddict按照Key进行排序,Key值不重复(对比一下proplists).每一次增加新数据项都会进行重新排序,所以通常情况查找会非常快。由于也是List和tuple实现,所以和proplists一样orddict也不适合大数据量的情况(LYSE上提到orddict在复杂性和效率上达到折中,元素最好不要超过75个)。注意orddict进行Key比较使用的是相等(==)。通过模块暴露出来的接口完成对orddict的处理,不要当作普通的list直接处理,因为一些操作会涉及到重排序。

dict

动态哈希表实现的字典。在接口上和orddict保持一致,在实现上和array动态扩展的思路类似, 与proplists,orddict相比它能够支持更大的数据量,你可以在数据量膨胀的时候从orddict转为dict。

gb_trees

(General Balanced Trees) 通用二叉查找树,通常被用作有序字典。与普通未平衡二叉树相比没有额外的储存开销,这里所说的额外的存储开销是指是否使用额外的metadata记录节点相关的信息,dict和array的实现就使用了这样的描述信息,换句话说gb_trees是自描述的,性能优于平衡二叉树(AVL trees)。与proplists,orddict相比它能够支持更大的数据量
gb_trees的数据结构:

gb_trees = {Size, Tree}
Tree = {Key, Value, Smaller, Bigger} | nil
Smaller = Tree
Bigger = Tree

ordsets

lists实现的有序集合。由于数据元素的变动都会触发重新排序,所以ordsets效率不高,只适用于数据量比较小的场景。ordsets中包含了常见的集合操作:求交集,并集,是否为子集,是否存在交集。

sets

提供了和ordsets一样的接口,它的实现和dict类似,只是存储的数据元素从键值对变成了值,支持更大的数据量,与dict一样特别适用于读密集的场景,比如判断一个元素是否在集合中。

gb_sets

包含了ordsets和gb_trees所提供的接口,gb_setsgb_trees实现类似,只是存储的数据元素从键值对变成了值。gb_sets与sets相比除了读操作性能差一些,其它操作都更快gb_sets实现了sets和ordsets相同的接口,并新增了一些方法。
实际应用中你会看到绝大多数时候都是在使用gb_sets,需要=:=比较的时候使用sets

queue

queue使用两个list来实现,这两个List为{RearList,FrontList},即{尾端,前端},queue的第一个元素出现在FrontList的Head;queue的最后一个元素出现在RearList的Head。
它的内部实现充分考虑到了效率,queue模块中除了len/1, join/2, split/2, filter/2 and member/2复杂度是O(n)之外所有的操作的复杂度都在O(1)(一般情况是O(1),如调用出队接口,当前端list为空时,时间为O(length(RearList)))。

map

map数据结构的复杂性和进程字典(put,get)相比都简单很多, 所以map第一天设计就不是为了大量存放kv数据的目的,它的目的是提供一种更好的record的替代品,在细节上改进:支持atom以外的key, 语法和语义更自然。如果要性能,请使用ets,dict 等数据结构,如果要替代record用的更顺手,用map


性能相关

lists:substract(A,B),该操作的复杂度和leng(A)*length(B)成正比,当参与运算的两个都是长列表的时候就会非常慢了;使用ordsets会好很多:

%% 不要这样做: lists:subtract(A, B) is equivalent to A -- B.

%% 替代方案:
HugeSet1 = ordsets:from_list(HugeList1),
HugeSet2 = ordsets:from_list(HugeList2),
ordsets:subtract(HugeSet1, HugeSet2)

%% 显然lists中的元素原始顺序非常重要上面的方法就不适用了,要保持数据原始顺序,可以这样做:
Set = gb_sets:from_list(HugeList2),
[E || E <- HugeList1, not gb_sets:is_element(E, Set)]

两个细节:

  1. 如果lists中包含重复的元素时,两种运算不是等价的,HugeList2会移除所有在HugeList1中出现的元素。
  2. 下面的方法比较lists中的元素使用的是相等== 而’–‘操作使用的是匹配操作符’=:=';如果这个地方要求苛刻的话,可以使用sets替换为gb_sets,但要注意sets:from_list/1要比gb_sets:from_list/1慢得多.

关于查找算法

数组寻址容易,插入和删除困难;链表寻址困难,插入和删除容易;哈希表插入和删除的时间均取决于查找时间.哈希表在数据和数据存储位置之间建立了确定的函数关系,所以获得了高效的查询效率,而线性表和树,数据项在结构中的位置是随机的,和数据项取值没有确定的关系,这种结构上进行查找数据项是基于"比较",查找效率依赖比较次数。


关于iolist
http://www.cnblogs.com/me-sa/archive/2012/01/31/erlang0034.html

关于binary
http://www.cnblogs.com/me-sa/archive/2011/12/25/erlang0024.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值