View Source DoublyLinkedList (doubly_linked_list v0.1.0)

A fast, ammortised O(log n) doubly linked list implementation.

A doubly linked list is a type of linked list in which each node contains three elements: a data value, a pointer to the next node in the list, and a pointer to the previous node. This two-way linkage allows traversal of the list in both directions, forward and backward, which is a significant advantage over a singly linked list that can only be traversed in one direction.

A new doubly linked list can be constructed using new/0:

iex> dll = DoublyLinkedList.new()
#DoublyLinkedList<[]>

Many types of insertion and deletion are supported, the most basic being insert_head/2, insert_tail/2, remove_head/1 and remove_tail/2 which will insert and remove at the head and tail of the doubly linked list respectively:

iex> dll = DoublyLinkedList.new()
#DoublyLinkedList<[]>

iex> {dll, node} = DoublyLinkedList.insert_tail(dll, "tail value")
{#DoublyLinkedList<["tail value"]>, #DoublyLinkedNode<"tail value">}

iex> {dll, node} = DoublyLinkedList.insert_head(dll, "head value")
{#DoublyLinkedList<["head value", "tail value"]>, #DoublyLinkedNode<"head value">}

iex> dll = DoublyLinkedList.remove_tail(dll)
#DoublyLinkedList<["head value"]>

iex> dll = DoublyLinkedList.remove_head(dll)
#DoublyLinkedList<[]>

Node data can be updated with update/3:

iex> dll = DoublyLinkedList.new()
#DoublyLinkedList<[]>

iex> {dll, node} = DoublyLinkedList.insert_tail(dll, "tail value")
{#DoublyLinkedList<["tail value"]>, #DoublyLinkedNode<"tail value">}

iex> dll = DoublyLinkedList.update(dll, node, "new tail value")
#DoublyLinkedList<["new tail value"]>

There are two options for traversal. DoublyLinkedList implements the Enumerable protocol so Enum.map/2, Enum.member?/2, etc are supported; there are also the built-in find_from_head/2 and find_from_tail/2 functions. find_from_tail/2 is of particular interest as it traverses the list in reverse. Note that traversal methods are O(n).

iex> dll = DoublyLinkedList.new()
iex> {dll, node} = DoublyLinkedList.insert_tail(dll, 1)
iex> {dll, node} = DoublyLinkedList.insert_tail(dll, 2)
{#DoublyLinkedList<[1, 2]>, #DoublyLinkedNode<2>}

iex> Enum.map(dll, fn v -> v * 2 end)
[2, 4]

Summary

Functions

Find the first node whose data matches the given value (starting from the head of the list).

Find the first node whose data matches the given value (starting from the tail of the list).

Get the node.

Get the node at the head of the list.

Get the node after the given node.

Get the node before the given node.

Get the node at the tail of the list.

Insert a node after the given node.

Insert a node before the given node.

Insert a node at the head of the list.

Insert a node at the tail of the list.

Construct a new list.

Remove the node.

Remove the node after the given node.

Remove the node before the given node.

Remove the node at the head of the list.

Remove the node at the tail of the list.

Update the node with the given value.

Types

@type t() :: %DoublyLinkedList{
  head: String.t(),
  nodes: %{optional(String.t()) => DoublyLinkedList.Node.t()},
  tail: String.t()
}

Functions

Link to this function

find_from_head(dll, data)

View Source
@spec find_from_head(t(), term()) :: DoublyLinkedList.Node.t() | nil

Find the first node whose data matches the given value (starting from the head of the list).

Link to this function

find_from_tail(dll, data)

View Source
@spec find_from_tail(t(), term()) :: DoublyLinkedList.Node.t() | nil

Find the first node whose data matches the given value (starting from the tail of the list).

@spec get(t(), String.t()) :: DoublyLinkedList.Node.t() | nil
@spec get(t(), DoublyLinkedList.Node.t()) :: DoublyLinkedList.Node.t() | nil

Get the node.

@spec get_head(t()) :: nil
@spec get_head(t()) :: DoublyLinkedList.Node.t()

Get the node at the head of the list.

@spec get_next(t(), String.t()) :: DoublyLinkedList.Node.t() | nil
@spec get_next(t(), DoublyLinkedList.Node.t()) :: DoublyLinkedList.Node.t() | nil

Get the node after the given node.

@spec get_prev(t(), String.t()) :: DoublyLinkedList.Node.t() | nil
@spec get_prev(t(), DoublyLinkedList.Node.t()) :: DoublyLinkedList.Node.t() | nil

Get the node before the given node.

@spec get_tail(t()) :: nil
@spec get_tail(t()) :: DoublyLinkedList.Node.t()

Get the node at the tail of the list.

Link to this function

insert_after(dll, after_node_id, data)

View Source
@spec insert_after(t(), String.t(), term()) :: {t(), DoublyLinkedList.Node.t() | nil}
@spec insert_after(t(), DoublyLinkedList.Node.t(), term()) ::
  {t(), DoublyLinkedList.Node.t() | nil}

Insert a node after the given node.

Link to this function

insert_before(dll, before_node_id, data)

View Source
@spec insert_before(t(), String.t(), term()) :: {t(), DoublyLinkedList.Node.t() | nil}
@spec insert_before(t(), DoublyLinkedList.Node.t(), term()) ::
  {t(), DoublyLinkedList.Node.t() | nil}

Insert a node before the given node.

@spec insert_head(t(), term()) :: {t(), DoublyLinkedList.Node.t()}
@spec insert_head(
  {t(), DoublyLinkedList.Node.t()},
  term()
) :: {t(), DoublyLinkedList.Node.t()}

Insert a node at the head of the list.

@spec insert_tail(t(), term()) :: {t(), DoublyLinkedList.Node.t()}
@spec insert_tail(
  {t(), DoublyLinkedList.Node.t()},
  term()
) :: {t(), DoublyLinkedList.Node.t()}

Insert a node at the tail of the list.

@spec new() :: t()

Construct a new list.

@spec remove(t(), String.t()) :: t()
@spec remove(t(), DoublyLinkedList.Node.t()) :: t()

Remove the node.

Link to this function

remove_after(dll, after_node_id)

View Source
@spec remove_after(t(), String.t()) :: t()
@spec remove_after(t(), DoublyLinkedList.Node.t()) :: t()

Remove the node after the given node.

Link to this function

remove_before(dll, before_node_id)

View Source
@spec remove_before(t(), String.t()) :: t()
@spec remove_before(t(), DoublyLinkedList.Node.t()) :: t()

Remove the node before the given node.

@spec remove_head(t()) :: t()

Remove the node at the head of the list.

@spec remove_tail(t()) :: t()

Remove the node at the tail of the list.

Link to this function

update(dll, node_id, data)

View Source
@spec update(t(), String.t(), term()) :: t() | nil
@spec update(t(), DoublyLinkedList.Node.t(), term()) :: t() | nil

Update the node with the given value.