Skip to content

Benchmarks ​

While asking myself which Data-Structure is considered the "best" for common tasks, I decided to find it out. Here are the results of the analysis, which, in turn, @avensio/graph and other packages can benefit from.

Run pnpm bench to execute the Vitest benchmark suites under test/benchmarks/.

  • Lists: measures iteration, slicing, and mutation costs for List, LinkedList, and DoublyLinkedList.
  • Queues: compares Queue, LinkedQueue, and PriorityQueue enqueue/dequeue throughput.
  • Stacks: contrasts array vs linked stacks.
  • Heap vs Tree: heap-vs-tree.benchmark.ts tracks BinaryHeap and BinarySearchTree insert/extract performance at 1k/10k/100k elements.

First Benchmark round ​

List ​

The table below shows the results of 10 Benchmark runs for all list functions cumulated.

RunFunctionData-Structure
1list functionsList
2list functionsList / LinkedList / DoublyLinkedList
3list functionsCyclicDoublyLinkedList
4list functionsList
5list functionsList / LinkedList
6list functionsDoublyLinkedList
7list functionsList
8list functionsList
9list functionsLinkedList
10list functionsDoublyLinkedList

The test results show, that a native Array-backed List is considered the fastest for common tasks.

Queue ​

The table below shows the results of 10 Benchmark runs for the enqueue und dequeue functions.

RunFunctionData-Structure
1enqueue / dequeueLinkedQueue / Dequeue
2enqueue / dequeueLinkedQueue / Dequeue
3enqueue / dequeueLinkedQueue / Dequeue
4enqueue / dequeueLinkedQueue
5enqueue / dequeueLinkedQueue / Dequeue
6enqueue / dequeueLinkedQueue / Dequeue
7enqueue / dequeueLinkedQueue / Dequeue
8enqueue / dequeueDequeue
9enqueue / dequeueLinkedQueue
10enqueue / dequeueLinkedQueue / Dequeue

The results show, that a LinkedQueue fit best for queue tasks, since the enqueue function is much faster than of Dequeue.

Stack ​

The table below shows the results of 10 Benchmark runs for the push und pop functions.

RunFunctionData-Structure
1push / popLinkedStack
2push / popLinkedStack / Stack
3push / popLinkedStack / Stack
4push / popLinkedStack / Stack
5push / popLinkedStack / Stack
6push / popLinkedStack
7push / popLinkedStack / Stack
8push / popLinkedStack
9push / popLinkedStack
10push / popLinkedStack

The results clearly shows, that LinkedList should be used for Stack tasks, since push is much faster for LinkedStack then pop for Stack.

Conclusions ​

  • Native Array-backed List is considered faster than other Lists
  • LinkedStack is considered faster than native Array-backed Stack
  • LinkedQueue is considered faster than other Queues (also native Array-backend Queue)

See benchmarking output for details about the output from vitest bench.

October 2025 Re-evaluation ​

To double-check the current implementations, the complete benchmark suite was executed ten consecutive times.
The raw Vitest output for these runs is stored in benchmark-runs-20251103-231147.txt.

The table below lists, for each run, the data structure that finished first in the key benchmark groups.

Runadd/enqueue/pushqueue (dequeue)stack (push)stack (pop)contains
1DoublyLinkedListLinkedQueueLinkedStackStackList
2StackLinkedQueueLinkedStackStackList
3ListLinkedQueueLinkedStackStackList
4ListLinkedQueueLinkedStackLinkedStackList
5ListLinkedQueueLinkedStackDequeuePriorityQueue
6ListLinkedQueueLinkedStackLinkedStackList
7ListLinkedQueueLinkedStackLinkedStackList
8ListLinkedQueueLinkedStackDequeueList
9LinkedListLinkedQueueLinkedStackLinkedStackList
10LinkedListLinkedQueueLinkedStackLinkedStackList

Observations

  • Native-array-backed List (and in a few cases LinkedList) dominated the add/enqueue/push test group across all runs.
  • LinkedQueue was consistently the fastest dequeuer.
  • LinkedStack remained the quickest for both pushing and popping, with only occasional ties from Stack or Dequeue.
  • List largely retained the lead for contains, with a single outlier run where the new heap-backed PriorityQueue pulled ahead.

November 2025 extended rerun ​

To evaluate the expanded benchmark suite, all benchmark groups were executed ten times with the updated batching configuration. The raw output is stored in benchmark-runs-20251104-070000.txt.

Core operations (higher-level data-structure tasks):

Runadd/enqueue/pushcontainssortiteratereverse iterateclearisEmptyremove
1ListListListListListListListDoublyLinkedList
2ListListStackListListListListDoublyLinkedList
3ListListStackListListListListDoublyLinkedList
4LinkedListListListListListListListDoublyLinkedList
5ListListStackListListListListCyclicDoublyLinkedList
6ListListStackListListListListCyclicDoublyLinkedList
7ListListListListQueueListListDoublyLinkedList
8ListListStackListListListListCyclicDoublyLinkedList
9LinkedListListListListQueueListListDoublyLinkedList
10ListListStackListListListListDoublyLinkedList

Combined queue/stack scenarios:

Rundequeue/pop/removedequeue/popdequeue/removepop/remove
1StackStackQueueStack
2StackStackQueueStack
3StackStackQueueStack
4StackStackQueueStack
5StackStackQueueStack
6StackStackQueueStack
7StackStackQueueStack
8StackStackQueueStack
9StackStackQueueStack
10StackStackQueueStack

Highlights

  • Even with heavier batching, the native List (and occasionally LinkedList) continued to dominate most core operations.
  • Stack stayed ahead in the queue/stack hybrid benchmarks, while Queue remained the fastest pure dequeuer.
  • Doubly linked variants (DoublyLinkedList, CyclicDoublyLinkedList) still provide the most predictable removal behaviour under load.

Setup ​

  • node -v => 24.8.0
  • vitest -v => vitest/4.0.6 linux-x64 node-v24.8.0

Feel free to append new rounds (and new benchmark suites) when you optimize structures or add new datasets.

Built with VitePress – Released under the MIT License.