<p dir="ltr">As for ETS cost, it may be described in the docs as constant, but in reality for the core operations it's (size of key + size of data moved into or out of table).<br>
In many use cases, it makes no difference (because the key and value sizes are small or constant), but for some it does.</p>
<div class="gmail_quote">Den 17/09/2015 17.57 skrev "Fred Hebert" <<a href="mailto:mononcqc@ferd.ca">mononcqc@ferd.ca</a>>:<br type="attribution"><blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex">On 09/17, Eric des Courtis wrote:<br>
<blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex">
Regardless if concurrency and parallelism plays a role *I still need to<br>
know if an operation in a sequential process I am working on is O(1) or<br>
O(n)* or am I missing something?<br>
</blockquote>
<br>
These values are way more worthwhile as a property of libraries than language, since they're far more impacted by the choice of algorithm taken there.<br>
<br>
Let's look at a few modules:<br>
<br>
1. Queue<br>
<br>
"all operations has an amortized O(1) running time, except len/1, join/2, split/2, filter/2 and member/2 that have O(n). To minimize the size of a queue minimizing the amount of garbage built by queue operations, the queues do not contain explicit length information, and that is why len/1 is O(n)."<br>
<br>
<br>
2. Maps<br>
<br>
undefined in the module doc, but from the EEP (<a href="http://www.erlang.org/eeps/eep-0043.html" rel="noreferrer" target="_blank">http://www.erlang.org/eeps/eep-0043.html</a>):<br>
<br>
"has at most O(log N) time complexity in insert and lookup operations, where N is the number of key-value associations."<br>
<br>
3. Dict<br>
<br>
undefined in docs. I know that it is a very flat tree (bunch of buckets) acting as a hash map, so O(log N)<br>
<br>
4. Array<br>
<br>
undefined in docs. Also a very flat tree. O(Log N), where N is the size of the array, and if I recall, the tree has a branching factor of 10 to compromise between the speed of lookups and garbage generated when modifying it. It's described in the source only, sadly.<br>
<br>
5. Gb_trees<br>
<br>
Doc compares them to AVL trees, without storage overhead and with better performance. O(log N) it is (those are the worst cases for AVL trees)<br>
<br>
6. Sets<br>
<br>
They're using the same mechanism as dicts, so O(Log N)<br>
<br>
7. Gb_sets<br>
<br>
Same mechanism as gb_trees, so O(log N)<br>
<br>
8. ETS<br>
<br>
Doc says: "These provide the ability to store very large quantities of data in an Erlang runtime system, and to have constant access time to the data. (In the case of ordered_set, see below, access time is proportional to the logarithm of the number of objects stored)."<br>
<br>
9. Orddict<br>
<br>
Doc says " An orddict is a representation of a dictionary, where a list of pairs is used to store the keys and values. The list is ordered after the keys."<br>
<br>
lists are O(N) traversal and insertion, so let's consider this the best case.<br>
<br>
10. ordsets<br>
<br>
implemented over orddict, O(N) too.<br>
<br>
11. sofs<br>
<br>
despite having the most cryptic documentation, it does mention: "The execution time of the functions of this module is dominated by the time it takes to sort lists. When no sorting is needed, the execution time is in the worst case proportional to the sum of the sizes of the input arguments and the returned value. A few functions execute in constant time: from_external, is_empty_set, is_set, is_sofs_set, to_external, type."<br>
<br>
O(N log N) for most (optimal sort time, where N = sum(Input)), with a list of O(1) functions<br>
<br>
12. Digraph<br>
<br>
Unspecified, no idea<br>
<br>
13. lists:key* functions<br>
<br>
using lists, so O(N), but they're fast given they're implemented in C<br>
<br>
14. Proplists<br>
<br>
Using lists, so O(N).<br>
<br>
<br>
<br>
Now with these modules somewhat covered (there's a lot of subtleties in the APIs making some better than others depending on the access patterns), it's interesting to look at basic operations we may do a lot, for example:<br>
<br>
1. Message receiving (non-selective)<br>
<br>
O(1), though accessing the mailbox when it's very large can trigger GCs and mess up expectations a bit.<br>
<br>
2. Message receiving (selective)<br>
<br>
O(N) selection where N is the mailbox size. An optimization existsw for common access patterns where a reference (with make_ref()) is created in the scope of the receive and used in all clauses, which truncates the existing mailbox, therefore reducing N.<br>
<br>
3. Sorting (lists:sort)<br>
<br>
O(N log N), performing a fancypants merge sort<br>
<br>
<br>
<br>
So yeah, for a lot of data structures, the information is already there.  For many, it's also still missing.<br>
<br>
Regards,<br>
Fred.<br>
_______________________________________________<br>
erlang-questions mailing list<br>
<a href="mailto:erlang-questions@erlang.org" target="_blank">erlang-questions@erlang.org</a><br>
<a href="http://erlang.org/mailman/listinfo/erlang-questions" rel="noreferrer" target="_blank">http://erlang.org/mailman/listinfo/erlang-questions</a><br>
</blockquote></div>