Skip to content

Commit 66a0a2d

Browse files
authored
Merge pull request #450 from c-p-murphy/mutable_list
Add MutableLinkedList
2 parents b11a10f + 63fed45 commit 66a0a2d

File tree

7 files changed

+445
-10
lines changed

7 files changed

+445
-10
lines changed

README.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,7 @@ This package implements a variety of data structures, including
2424
- Ordered Dicts and Sets
2525
- Dictionaries with Defaults
2626
- Trie
27-
- Linked List
27+
- Linked List and Mutable Linked List
2828
- Sorted Dict, Sorted Multi-Dict and Sorted Set
2929
- DataStructures.IntSet
3030
- Priority Queue

docs/src/index.md

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@ This package implements a variety of data structures, including
1515
- Ordered Dicts and Sets
1616
- Dictionaries with Defaults
1717
- Trie
18-
- Linked List
18+
- Linked List and Mutable Linked List
1919
- Sorted Dict, Sorted Multi-Dict and Sorted Set
2020
- DataStructures.IntSet
2121

@@ -36,6 +36,7 @@ Pages = [
3636
"default_dict.md",
3737
"trie.md",
3838
"linked_list.md",
39+
"mutable_linked_list.md"
3940
"intset.md",
4041
"sorted_containers.md",
4142
]

docs/src/mutable_linked_list.md

Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
# Mutable Linked List
2+
3+
The `MutableLinkedList` type implements a doubly linked list with mutable nodes.
4+
This data structure supports constant-time insertion/removal of elements
5+
at both ends of the list.
6+
7+
Usage:
8+
9+
```julia
10+
l = MutableLinkedList{T}() # initialize an empty list of type T
11+
l = MutableLinkedList{T}(elts...) # initialize a list with elements of type T
12+
isempty(l) # test whether list is empty
13+
length(l) # get the number of elements in list
14+
collect(l) # return a vector consisting of list elements
15+
eltype(l) # return type of list
16+
first(l) # return value of first element of list
17+
last(l) # return value of last element of list
18+
l1 == l2 # test lists for equality
19+
map(f, l) # return list with f applied to elements
20+
filter(f, l) # return list of elements where f(el) == true
21+
reverse(l) # return reversed list
22+
copy(l) # return a copy of list
23+
getindex(l, idx) # get value at index
24+
setindex!(l, data, idx) # set value at index to data
25+
append!(l1, l2) # attach l2 at the end of l1
26+
append!(l, elts...) # attach elements at end of list
27+
delete!(l, idx) # delete element at index
28+
delete!(l, range) # delete elements within range [a,b]
29+
push!(l, data) # add element to end of list
30+
pushfirst!(l, data) # add element to beginning of list
31+
pop!(l) # remove element from end of list
32+
popfirst!(l) # remove element from beginning of list
33+
```
34+
35+
`MutableLinkedList` implements the Iterator interface, iterating over the list
36+
from first to last.

src/DataStructures.jl

Lines changed: 7 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,20 +1,17 @@
11
module DataStructures
22

3-
import Base: <, <=, ==, length, isempty, iterate, delete!,
3+
import Base: <, <=, ==, length, isempty, iterate,
44
show, dump, empty!, getindex, setindex!, get, get!,
5-
in, haskey, keys, merge, copy, cat,
5+
in, haskey, keys, merge, copy, cat, collect,
66
push!, pop!, pushfirst!, popfirst!, insert!, lastindex,
7-
union!, delete!, similar, sizehint!, empty,
8-
isequal, hash,
9-
map, reverse,
7+
union!, delete!, similar, sizehint!, empty, append!,
8+
isequal, hash, map, filter, reverse,
109
first, last, eltype, getkey, values, sum,
1110
merge, merge!, lt, Ordering, ForwardOrdering, Forward,
1211
ReverseOrdering, Reverse, Lt,
13-
isless,
14-
union, intersect, symdiff, setdiff, issubset,
12+
isless, union, intersect, symdiff, setdiff, issubset,
1513
searchsortedfirst, searchsortedlast, in,
1614
eachindex, keytype, valtype, minimum, maximum
17-
import Base: iterate
1815

1916
using OrderedCollections
2017
import OrderedCollections: filter, filter!, isordered
@@ -44,6 +41,7 @@ module DataStructures
4441

4542
export LinkedList, Nil, Cons, nil, cons, head, tail, list, filter, cat,
4643
reverse
44+
export MutableLinkedList
4745
export SortedDict, SortedMultiDict, SortedSet
4846
export SDToken, SDSemiToken, SMDToken, SMDSemiToken
4947
export SetToken, SetSemiToken
@@ -76,6 +74,7 @@ module DataStructures
7674
include("int_set.jl")
7775

7876
include("list.jl")
77+
include("mutable_list.jl")
7978
include("balanced_tree.jl")
8079
include("tokens.jl")
8180

src/mutable_list.jl

Lines changed: 238 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,238 @@
1+
mutable struct ListNode{T}
2+
data::T
3+
prev::ListNode{T}
4+
next::ListNode{T}
5+
function ListNode{T}() where T
6+
node = new{T}()
7+
node.prev = node
8+
node.next = node
9+
return node
10+
end
11+
function ListNode{T}(data) where T
12+
node = new{T}(data)
13+
return node
14+
end
15+
end
16+
17+
mutable struct MutableLinkedList{T}
18+
len::Int
19+
front::ListNode{T}
20+
back::ListNode{T}
21+
function MutableLinkedList{T}() where T
22+
l = new{T}()
23+
l.len = 0
24+
l.front = ListNode{T}()
25+
l.back = ListNode{T}()
26+
l.front.next = l.back
27+
l.back.prev = l.front
28+
return l
29+
end
30+
end
31+
32+
MutableLinkedList() = MutableLinkedList{Any}()
33+
34+
function MutableLinkedList{T}(elts...) where T
35+
l = MutableLinkedList{T}()
36+
for elt in elts
37+
push!(l, elt)
38+
end
39+
return l
40+
end
41+
42+
iterate(l::MutableLinkedList) = begin
43+
l.len == 0 ? nothing : (l.front.next.data, l.front.next.next)
44+
end
45+
iterate(l::MutableLinkedList, n::ListNode) = begin
46+
n.next == n ? nothing : (n.data, n.next)
47+
end
48+
49+
isempty(l::MutableLinkedList) = l.len == 0
50+
length(l::MutableLinkedList) = l.len
51+
collect(l::MutableLinkedList{T}) where T = T[x for x in l]
52+
eltype(l::MutableLinkedList{T}) where T = T
53+
function first(l::MutableLinkedList)
54+
isempty(l) && throw(ArgumentError("List is empty"))
55+
return l.front.next.data
56+
end
57+
function last(l::MutableLinkedList)
58+
isempty(l) && throw(ArgumentError("List is empty"))
59+
return l.back.prev.data
60+
end
61+
62+
==(l1::MutableLinkedList{T}, l2::MutableLinkedList{S}) where {T,S} = false
63+
64+
function ==(l1::MutableLinkedList{T}, l2::MutableLinkedList{T}) where T
65+
length(l1) == length(l2) || return false
66+
for (i, j) in zip(l1, l2)
67+
i == j || return false
68+
end
69+
return true
70+
end
71+
72+
function map(f::Base.Callable, l::MutableLinkedList{T}) where T
73+
if isempty(l) && f isa Function
74+
S = Core.Compiler.return_type(f, (T,))
75+
return MutableLinkedList{S}()
76+
elseif isempty(l) && f isa Type
77+
return MutableLinkedList{f}()
78+
else
79+
S = typeof(f(first(l)))
80+
l2 = MutableLinkedList{S}()
81+
for h in l
82+
el = f(h)
83+
if el isa S
84+
push!(l2, el)
85+
else
86+
R = typejoin(S, typeof(el))
87+
l2 = MutableLinkedList{R}(collect(l2)...)
88+
push!(l2, el)
89+
end
90+
end
91+
return l2
92+
end
93+
end
94+
95+
function filter(f::Function, l::MutableLinkedList{T}) where T
96+
l2 = MutableLinkedList{T}()
97+
for h in l
98+
if f(h)
99+
push!(l2, h)
100+
end
101+
end
102+
return l2
103+
end
104+
105+
function reverse(l::MutableLinkedList{T}) where T
106+
l2 = MutableLinkedList{T}()
107+
for h in l
108+
pushfirst!(l2, h)
109+
end
110+
return l2
111+
end
112+
113+
function copy(l::MutableLinkedList{T}) where T
114+
l2 = MutableLinkedList{T}()
115+
for h in l
116+
push!(l2, h)
117+
end
118+
return l2
119+
end
120+
121+
function getindex(l::MutableLinkedList, idx::Int)
122+
@boundscheck 0 < idx <= l.len || throw(BoundsError(l, idx))
123+
node = l.front
124+
for i = 1:idx
125+
node = node.next
126+
end
127+
return node.data
128+
end
129+
130+
function setindex!(l::MutableLinkedList{T}, data, idx::Int) where T
131+
@boundscheck 0 < idx <= l.len || throw(BoundsError(l, idx))
132+
node = l.front
133+
for i = 1:idx
134+
node = node.next
135+
end
136+
node.data = convert(T, data)
137+
return l
138+
end
139+
140+
function append!(l1::MutableLinkedList{T}, l2::MutableLinkedList{T}) where T
141+
l1.back.prev.next = l2.front.next
142+
l2.front.next.prev = l1.back.prev
143+
l1.len += length(l2)
144+
return l1
145+
end
146+
147+
function append!(l::MutableLinkedList, elts...)
148+
for elt in elts
149+
push!(l, elt)
150+
end
151+
l.len += length(elts)
152+
return l
153+
end
154+
155+
function delete!(l::MutableLinkedList, idx::Int)
156+
@boundscheck 0 < idx <= l.len || throw(BoundsError(l, idx))
157+
node = l.front
158+
for i = 1:idx
159+
node = node.next
160+
end
161+
prev = node.prev
162+
next = node.next
163+
prev.next = next
164+
next.prev = prev
165+
l.len -= 1
166+
return l
167+
end
168+
169+
function delete!(l::MutableLinkedList, r::UnitRange)
170+
@boundscheck 0 < first(r) < last(r) <= l.len || throw(BoundsError(l, r))
171+
node = l.front
172+
for i = 1:first(r)
173+
node = node.next
174+
end
175+
prev = node.prev
176+
len = length(r)
177+
for j in 1:len
178+
node = node.next
179+
end
180+
next = node
181+
prev.next = next
182+
next.prev = prev
183+
l.len -= len
184+
return l
185+
end
186+
187+
function push!(l::MutableLinkedList{T}, data) where T
188+
last = l.back.prev
189+
node = ListNode{T}(data)
190+
node.next = l.back
191+
node.prev = last
192+
l.back.prev = node
193+
last.next = node
194+
l.len += 1
195+
return l
196+
end
197+
198+
function pushfirst!(l::MutableLinkedList{T}, data) where T
199+
first = l.front.next
200+
node = ListNode{T}(data)
201+
node.prev = l.front
202+
node.next = first
203+
l.front.next = node
204+
first.prev = node
205+
l.len += 1
206+
return l
207+
end
208+
209+
function pop!(l::MutableLinkedList)
210+
isempty(l) && throw(ArgumentError("List must be non-empty"))
211+
last = l.back.prev.prev
212+
data = l.back.prev.data
213+
last.next = l.back
214+
l.back.prev = last
215+
l.len -= 1
216+
return data
217+
end
218+
219+
function popfirst!(l::MutableLinkedList)
220+
isempty(l) && throw(ArgumentError("List must be non-empty"))
221+
first = l.front.next.next
222+
data = l.front.next.data
223+
first.prev = l.front
224+
l.front.next = first
225+
l.len -= 1
226+
return data
227+
end
228+
229+
function show(io::IO, node::ListNode)
230+
x = node.data
231+
print(io, "$(typeof(node))($x)")
232+
end
233+
234+
function show(io::IO, l::MutableLinkedList)
235+
print(io, typeof(l), '(')
236+
join(io, l, ", ")
237+
print(io, ')')
238+
end

test/runtests.jl

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@ tests = ["int_set",
2222
"default_dict",
2323
"trie",
2424
"list",
25+
"mutable_list",
2526
"multi_dict",
2627
"circular_buffer",
2728
"sorting",

0 commit comments

Comments
 (0)