PJUllrich

PJUllrich

Author of Building Table Views with Phoenix LiveView

Big-O Time Complexities of Elixir Data Structures

I am currently trying to compile a Big-O Time Complexity table for the Elixir data structures, but can’t find information for all complexities and am also not 100% sure that I’m getting them right. My goal is to have a comprehensive table like the Big-O Algorithm Complexity Table and maybe put it into a nice cheatsheet poster for future reference. I was able to find bits and pieces in the docs, Elixirforum posts and the Elixir mailing list, but I failed to find a comprehensive overview of all the complexities.

Would you mind helping me to complete and review the following table, please?

# Big-O Time Complexities for Elixir data structures

# Map [1]
Access:    O(log n)
Search:    O(log n)
Insertion: O(n) for < 32 elements, O(log n) for >= 32 elements [2]
Deletion:  O(n) for < 32 elements, O(log n) for >= 32 elements [2]
Caveats:
- 'With fewer than 32 elements, a Map is a list of tuples sorted by keys'
- 'With 32 and more elements, a Map is a Hash Array Mapped Trie (HAMT)'
- 'Maps are unordered, allow any key type, but disallow duplicate keys'

# List [3]
Access:    O(n)
Search:    O(n)
Insertion: O(1) for prepending, otherwise O(n)
Deletion:  O(1) if first element, otherwise O(n)
Caveats:
- 'Lists are not arrays as in other languages, but single-linked lists'

# Keyword [4]
Access:    O(n)
Search:    O(n)
Insertion: O(n)
Deletion:  O(n)

# Tuple [5]
Access:    O(1)
Search:    O(n)
Insertion: O(n)
Deletion:  O(n)
Caveats: 
- 'Tuples are better for reading, whereas Lists are better for traversals'
- 'Avoid using tuples as a collection'
  '(i.e. avoid Tuple.append/2, Tuple.insert_at/2, or Tuple.delete_at/2)'

# (erlang) array [6]
Access:    O(log n) [7]
Search:    O(log n)
Insertion: O(log n)
Deletion:  O(log n)
Caveats:
- 'An array is a trie of small tuples, with a smaller memory overhead to Lists'

# MapSet [8]
Same complexities as 'Map'

Discussion points

  • The time complexities are a mix of average, best, and worst complexities. Should we separate them into average, worst and best columns maybe?
  • Did I forget a data structure? I excluded the Arrays library, because it’s a library that uses different data structures under the hood.
  • Should we include ets as well? It has O(1) for access and insertion for set, bag, and duplicate_bag tables, but isn’t technically a data-structure :thinking:

References

  1. Map in Docs
  2. Map structure for < 32 and >= 32 elements
  3. List in Docs
  4. Tuple in Docs
  5. Keyword in Docs
  6. array in erlang Docs
  7. Complexities of erlang data structures
  8. MapSet in Docs

Other resources
Partial overview of complexities
Discussion of :array
Does Elixir have persistent data structures?
Way to get O(1) access/set
Sequences by @sasajuric

Most Liked

PJUllrich

PJUllrich

Author of Building Table Views with Phoenix LiveView

Thank you for the suggestion @hauleth. I moved the table to a GitHub Gist. The gist deviates only slightly from above table (I added a caveat to array as @sabiwara suggested). I’m happy that above table was quite comprehensive already. I hope it will serve as a good documentation for future reference :slight_smile:

GitHub gist: Big-O Time Complexities for Elixir and erlang Data Structures · GitHub

hauleth

hauleth

Maps:

Access is O(log n) amortised - always. If there is less than 32 keys, then these are stored as sorted tuples, which mean, than you can use binary search.

Insertion/deletion is O(n) or O(log n) (amortised) respectively for less than 32 and more than 32 keys.

List:

In the middle is still O(n)

Deletion O(1) if first element (just do tl(list) which is constant) O(n) otherwise

Keyword list:

The same as regular list (as these are the same things) unless you use Keyword module, which will do deduplication in most cases. Then indeed it will be O(n).

Array:

It is trie of tuples, so your Big-Os are wrong there.

sabiwara

sabiwara

Elixir Core Team

Oh sorry, I wasn’t really clear. Strictly speaking you can still use random access in a sparse index, but you would need to account for the “holes”, since the positions and size won’t be shifted. This will impact the rest of your algorithm if you cannot assume a dense array anymore.

In pseudo-code:

> dense_array = delete_at([1, 2, 3, 4], 2)
[1, 2, 4]
> sparse_array = reset_at([1, 2, 3, 4], 2)
[1, 2, :undefined, 4]
> dense_array[2]
4
> sparse_array[2]
:undefined
> sparse_array[3]
4

The sparse version is just really a replace_at, not an actual deletion, so it is a bit like comparing apples and oranges. But depending on your algorithm, it is probably the best option in practice when possible, and maybe convert it back to a dense array once you’re done deleting using sparse_to_list/1 (O(n)).

ityonemo

ityonemo

I highly recommend adding ets. Digraph is another batteries-included data structure, as is queue. Also counters.

sabiwara

sabiwara

Elixir Core Team

Oh this is a nice initiative :+1:
Although it doesn’t mention the complexities explicitly, this article comparing sequences might be an interesting resource to mention as well.

This one would actually be O(log n), since erlang’s :arrays are tries (like maps), not actual arrays in the traditional imperative programming sense.

Where Next?

Popular in Questions Top

senggen
Erlang/OTP 25 [erts-13.2.2] [source] [64-bit] [smp:8:8] [ds:8:8:10] [async-threads:1] 15:22:35.803 [error] gen_event {lager_file_backend...
New
pgiesin
This should be a simple problem but I just can’t seem to figure it out. I have a standalone Elixir app that won’t find the database. Dep...
New
vac
Hi, I'm quite new in Elixir and I'm trying to format a string to a PEM format. I have the certificate value like MIIDBTCCAe2...... and ...
New
mcarvalho
What is the difference between System.get_env and Application.get_env? For example, what are best practices to use one versus another.
New
mathew4509
I have a list say x = ["23gh", "56kh", "97mh"] I would like to pass each element to Val in each iteration. Say, in iteration 1 -------...
New
fayddelight
I tried installing elixir 1.11.2 erlang 23.3.4 via asdf in my zsh shell. Enabled the versions locally and globally. When I list them ...
New
vonH
When I run the Plug and I recompile I wind up having to use Ctrl C to quit iex and start again. Witht the help of rlwrap I can use the cu...
New
sabri
Can someone explain the settings of pool_size of Ecto in config file? and what is the recommend size? Thanks
New
wernerlaude
In AR this is so simple @articles = current_user.articles How to do in Ecto? def index(conn, _params) do current_user = conn.assig...
New
romenigld
I am trying to run a deploy with docker and I successfully runned with this command: docker build -t romenigld/blog-prod . but when I t...
New

Other popular topics Top

joaquinalcerro
Hi there, I am working with Ecto-Postgresql and I need to call all of the records from a specific table but the table has 40,000 record...
New
_russellb
I want to try my hand at web scraping. What tools/libraries do I need to use. I’m hoping to turn this into something professional so don’...
New
malloryerik
Hi, this is for people who, like me, have had some friction using .html.heex templates in VSCode. The solution seems to be, in a hyphena...
New
vertexbuffer
Hello, can anybody help here..? I have a list of players and I what to delete an element, but every for loop the list is reverting to ori...
New
vac
Hi, I'm quite new in Elixir and I'm trying to format a string to a PEM format. I have the certificate value like MIIDBTCCAe2...... and ...
New
mcarvalho
What is the difference between System.get_env and Application.get_env? For example, what are best practices to use one versus another.
New
qwerescape
Is there a way to get the call stack or stack trace at any point in the code? Not from exceptions, but an expression that returns how the...
New
fayddelight
I tried installing elixir 1.11.2 erlang 23.3.4 via asdf in my zsh shell. Enabled the versions locally and globally. When I list them ...
New
ovidiubadita
Hey all, I discovered Elixir and I love it. I always wanted to learn a functional programming and I intended to go for Haskell, but afte...
New
josevalim
Hi everyone, One of the features added to Elixir early on to help integration with Erlang code was the idea of overridable function defi...
New

We're in Beta

About us Mission Statement