Skip to content

Commit 841a07e

Browse files
authored
Merge pull request #3 from TheAlgorithms/minor-example-updates
update(list): Start with basic lists
2 parents 5b26a49 + f590d33 commit 841a07e

File tree

4 files changed

+228
-37
lines changed

4 files changed

+228
-37
lines changed
Lines changed: 65 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,65 @@
1+
defmodule Algorithims.DataStructures.DoublyLinkedList do
2+
@moduledoc """
3+
Because of elixir's immutability, there is no true way of having fully cyclical, referential structures. You would have to make a copy of the list with each change, and account for the new reference.
4+
We will not write overly complex code to do that, and allow the user to understand the nuance here.
5+
6+
Access for DoublyLinkedList is O(n)
7+
Search for DoublyLinkedList is O(n)
8+
Deletion/Insertion at element is O(1)
9+
"""
10+
defmodule Node, do: defstruct([:value, :prev, :next])
11+
defmodule LinkedList, do: defstruct([:size, :head, :tail])
12+
13+
def get_node(%LinkedList{size: 0}, _value), do: nil
14+
15+
def get_node(%LinkedList{size: _size, head: head, tail: _tail}, value) do
16+
check_node(head, value)
17+
end
18+
19+
defp check_node(%Node{value: value, next: nil} = node, _value), do: nil
20+
21+
defp check_node(%Node{value: value, next: next} = node, value) do
22+
if node.value == value do
23+
node
24+
else
25+
check_node(node.next, value)
26+
end
27+
end
28+
29+
def set_node(list, value) do
30+
end
31+
32+
def add_to_head(%LinkedList{head: nil, tail: nil, size: 0}, value) do
33+
new_node = %Node{value: value, prev: nil, next: nil}
34+
%LinkedList{head: new_node, tail: new_node, size: 1}
35+
end
36+
37+
def add_to_head(%LinkedList{head: old_head, tail: tail, size: size}, value) do
38+
new_head = %Node{prev: nil, next: old_head}
39+
old_head = %Node{prev: new_head, next: old_head.next}
40+
%LinkedList{size: size + 1, tail: tail, head: new_head}
41+
end
42+
43+
def add_to_tail(%LinkedList{head: head, tail: old_tail, size: size}, value) do
44+
new_tail = %Node{prev: old_tail, next: nil}
45+
# old_tail.next = new_tail
46+
%LinkedList{size: size + 1, tail: old_tail, head: head}
47+
end
48+
49+
defp remove(%LinkedList{size: 0}, value), do: nil
50+
51+
defp remove(%LinkedList{size: size, head: head, tail: tail} = list, value) do
52+
node_to_remove =
53+
case get_node(list, value) do
54+
nil -> raise "No node"
55+
node -> node
56+
end
57+
58+
# in elixir need to actually update references, this won't work in functional programming.
59+
# previous = node_to_remove.prev
60+
# next = node_to_remove.next
61+
# previous.next = next
62+
# next.previous = previous
63+
%LinkedList{size: size - 1, head: head, tail: tail}
64+
end
65+
end
Lines changed: 62 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,15 +1,71 @@
11
defmodule Algorithims.DataStructures.SinglyLinkedList do
2-
defmodule SingleLink, do: defstruct([:value, :reference])
2+
@moduledoc """
3+
Access for SinglyLinkedList is O(n)
4+
Search for SinglyLinkedList is O(n)
5+
Deletion/Insertion at element is O(1)
6+
"""
7+
defmodule Node, do: defstruct([:value, :reference])
8+
defmodule LinkedList, do: defstruct([:nodes])
39

4-
def add_node([], value) do
5-
[form_link(value, nil)]
10+
@doc """
11+
Adding to the head of a SinglyLinkedList is O(1), as you know where the head is
12+
"""
13+
def add_node_head(%LinkedList{nodes: []}, value) do
14+
first_link = form_link(value, nil)
15+
%LinkedList{nodes: [first_link]}
616
end
717

8-
def add_node([head | _tail] = list, value) do
9-
[form_link(value, head) | list]
18+
def add_node_head(%LinkedList{nodes: [head | _tail] = list}, value) do
19+
new_head = form_link(value, head)
20+
%LinkedList{nodes: [new_head | list]}
21+
end
22+
23+
@doc """
24+
Adding to the tail/middle of a SinglyLinkedList is O(1)
25+
"""
26+
def add_node_tail(%LinkedList{nodes: []} = list, value) do
27+
add_node_head(list, value)
28+
end
29+
30+
def add_node_tail(%LinkedList{nodes: [head | []]}, value) do
31+
old_tail = head
32+
new_tail = form_tail_link(value)
33+
old_tail = %Node{value: old_tail.value, reference: new_tail}
34+
new_nodes = [old_tail] ++ [new_tail]
35+
36+
%LinkedList{nodes: new_nodes}
37+
end
38+
39+
def add_node_tail(%LinkedList{nodes: nodes} = list, value) do
40+
old_tail = tail(list)
41+
new_tail = form_tail_link(value)
42+
old_tail = %Node{value: old_tail.value, reference: new_tail}
43+
new_nodes = nodes |> List.delete_at(-1)
44+
new_nodes = new_nodes ++ [old_tail] ++ [new_tail]
45+
46+
%LinkedList{nodes: new_nodes}
47+
end
48+
49+
def list_length(%LinkedList{nodes: []}), do: 0
50+
def list_length(%LinkedList{nodes: nodes}), do: nodes |> length()
51+
52+
def head(%LinkedList{nodes: nodes}), do: nodes |> List.first()
53+
54+
def tail(%LinkedList{nodes: [current_tail | []]}) do
55+
current_tail
56+
end
57+
58+
def tail(%LinkedList{nodes: []}), do: nil
59+
60+
def tail(%LinkedList{nodes: [_current_head | current_tails]}) do
61+
tail(%LinkedList{nodes: current_tails})
1062
end
1163

1264
defp form_link(value, reference) do
13-
%__MODULE__.SingleLink{value: value, reference: reference}
65+
%__MODULE__.Node{value: value, reference: reference}
66+
end
67+
68+
defp form_tail_link(value) do
69+
%__MODULE__.Node{value: value, reference: nil}
1470
end
1571
end
Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,43 @@
1+
defmodule Algorithims.DataStructures.DoublyLinkedListTest do
2+
alias Algorithims.DataStructures.DoublyLinkedList
3+
alias DoublyLinkedList.LinkedList
4+
alias DoublyLinkedList.Node
5+
6+
use ExUnit.Case
7+
doctest Algorithims
8+
9+
describe "get_node/1" do
10+
test "it works when the list is empty" do
11+
end
12+
13+
test "it works when the list is not empty" do
14+
end
15+
end
16+
17+
describe "add_to_head/1" do
18+
test "it works when the list is empty" do
19+
res = DoublyLinkedList.add_to_head(%LinkedList{head: nil, tail: nil, size: 0}, 1)
20+
assert res.size == 1
21+
assert res.head == %Node{value: 1, prev: nil, next: nil}
22+
assert res.tail == %Node{value: 1, prev: nil, next: nil}
23+
end
24+
25+
test "it works when the list is not empty" do
26+
res =
27+
DoublyLinkedList.add_to_head(%LinkedList{head: nil, tail: nil, size: 0}, 10)
28+
|> DoublyLinkedList.add_to_head(3)
29+
|> DoublyLinkedList.add_to_head(5)
30+
|> DoublyLinkedList.add_to_head(-1)
31+
32+
assert head = res.head
33+
assert head.prev == nil
34+
assert head.value == 10
35+
assert head.next.value == 3
36+
37+
assert tail = res.tail
38+
assert tail.prev.value == 5
39+
assert tail.value == -1
40+
assert tail.next == nil
41+
end
42+
end
43+
end
Lines changed: 58 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -1,45 +1,72 @@
11
defmodule Algorithims.DataStructures.SinglyLinkedListTest do
22
alias Algorithims.DataStructures.SinglyLinkedList
3+
alias SinglyLinkedList.LinkedList
4+
alias SinglyLinkedList.Node
35

46
use ExUnit.Case
57
doctest Algorithims
68

7-
describe "add_node/2" do
9+
describe "add_node_head/2" do
810
test "it works when the list is empty" do
9-
assert SinglyLinkedList.add_node([], 3) == [
10-
%SinglyLinkedList.SingleLink{
11-
value: 3,
12-
reference: nil
13-
}
14-
]
11+
node = %Node{value: 3, reference: nil}
12+
result = %SinglyLinkedList.LinkedList{nodes: [node]}
13+
add_node_head_result = SinglyLinkedList.add_node_head(%LinkedList{nodes: []}, 3)
14+
assert add_node_head_result == result
15+
assert SinglyLinkedList.list_length(add_node_head_result) == 1
16+
assert SinglyLinkedList.tail(add_node_head_result) == %Node{value: 3, reference: nil}
1517
end
1618

1719
test "it adds to the head" do
1820
list =
19-
SinglyLinkedList.add_node([], 3)
20-
|> SinglyLinkedList.add_node(4)
21-
|> SinglyLinkedList.add_node(5)
22-
23-
assert list == [
24-
%Algorithims.DataStructures.SinglyLinkedList.SingleLink{
25-
reference: %Algorithims.DataStructures.SinglyLinkedList.SingleLink{
26-
reference: %Algorithims.DataStructures.SinglyLinkedList.SingleLink{
27-
reference: nil,
28-
value: 3
29-
},
30-
value: 4
31-
},
32-
value: 5
33-
},
34-
%Algorithims.DataStructures.SinglyLinkedList.SingleLink{
35-
reference: %Algorithims.DataStructures.SinglyLinkedList.SingleLink{
36-
reference: nil,
37-
value: 3
38-
},
39-
value: 4
40-
},
41-
%Algorithims.DataStructures.SinglyLinkedList.SingleLink{reference: nil, value: 3}
42-
]
21+
SinglyLinkedList.add_node_head(%LinkedList{nodes: []}, 3)
22+
|> SinglyLinkedList.add_node_head(4)
23+
|> SinglyLinkedList.add_node_head(5)
24+
|> SinglyLinkedList.add_node_head(6)
25+
26+
assert SinglyLinkedList.list_length(list) == 4
27+
28+
assert SinglyLinkedList.head(list) == %Node{
29+
value: 6,
30+
reference: %Node{
31+
value: 5,
32+
reference: %Node{value: 4, reference: %Node{value: 3, reference: nil}}
33+
}
34+
}
35+
36+
assert SinglyLinkedList.tail(list) == %Node{value: 3, reference: nil}
37+
end
38+
39+
test "it adds to the tail" do
40+
list = SinglyLinkedList.add_node_tail(%LinkedList{nodes: []}, 3)
41+
list = list |> SinglyLinkedList.add_node_tail(4)
42+
43+
assert SinglyLinkedList.list_length(list) == 2
44+
assert list.nodes |> length == 2
45+
46+
assert SinglyLinkedList.tail(list) == %Node{value: 4, reference: nil}
47+
48+
assert SinglyLinkedList.head(list) == %Node{
49+
value: 3,
50+
reference: %Node{value: 4, reference: nil}
51+
}
52+
53+
list =
54+
list
55+
|> SinglyLinkedList.add_node_tail(5)
56+
57+
# need to just travese list
58+
# assert SinglyLinkedList.head(list) == %Node{
59+
# value: 3,
60+
# reference: %Node{
61+
# value: 4,
62+
# reference: %Node{value: 5, reference: nil}
63+
# }
64+
# }
65+
66+
assert SinglyLinkedList.tail(list) == %Node{
67+
value: 5,
68+
reference: nil
69+
}
4370
end
4471
end
4572
end

0 commit comments

Comments
 (0)