forked from JuliaLang/julia
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathlinked_list.jl
152 lines (136 loc) · 4.23 KB
/
linked_list.jl
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
# This file is a part of Julia. License is MIT: https://julialang.org/license
mutable struct InvasiveLinkedList{T}
# Invasive list requires that T have a field `.next >: U{T, Nothing}` and `.queue >: U{ILL{T}, Nothing}`
head::Union{T, Nothing}
tail::Union{T, Nothing}
InvasiveLinkedList{T}() where {T} = new{T}(nothing, nothing)
end
#const list_append!! = append!
#const list_deletefirst! = delete!
eltype(::Type{<:InvasiveLinkedList{T}}) where {T} = @isdefined(T) ? T : Any
iterate(q::InvasiveLinkedList) = (h = q.head; h === nothing ? nothing : (h, h))
iterate(q::InvasiveLinkedList{T}, v::T) where {T} = (h = v.next; h === nothing ? nothing : (h, h))
isempty(q::InvasiveLinkedList) = (q.head === nothing)
function length(q::InvasiveLinkedList)
i = 0
head = q.head
while head !== nothing
i += 1
head = head.next
end
return i
end
function list_append!!(q::InvasiveLinkedList{T}, q2::InvasiveLinkedList{T}) where T
q === q2 && error("can't append list to itself")
head2 = q2.head
if head2 !== nothing
tail2 = q2.tail::T
q2.head = nothing
q2.tail = nothing
tail = q.tail
q.tail = tail2
if tail === nothing
q.head = head2
else
tail.next = head2
end
while head2 !== nothing
head2.queue = q
head2 = head2.next
end
end
return q
end
function push!(q::InvasiveLinkedList{T}, val::T) where T
val.queue === nothing || error("val already in a list")
val.queue = q
tail = q.tail
if tail === nothing
q.head = q.tail = val
else
tail.next = val
q.tail = val
end
return q
end
function pushfirst!(q::InvasiveLinkedList{T}, val::T) where T
val.queue === nothing || error("val already in a list")
val.queue = q
head = q.head
if head === nothing
q.head = q.tail = val
else
val.next = head
q.head = val
end
return q
end
function pop!(q::InvasiveLinkedList{T}) where {T}
val = q.tail::T
list_deletefirst!(q, val) # expensive!
return val
end
function popfirst!(q::InvasiveLinkedList{T}) where {T}
val = q.head::T
list_deletefirst!(q, val) # cheap
return val
end
# this function assumes `val` is found in `q`
function list_deletefirst!(q::InvasiveLinkedList{T}, val::T) where T
val.queue === q || return
head = q.head::T
if head === val
if q.tail::T === val
q.head = q.tail = nothing
else
q.head = val.next::T
end
else
head_next = head.next::T
while head_next !== val
head = head_next
head_next = head.next::T
end
if q.tail::T === val
head.next = nothing
q.tail = head
else
head.next = val.next::T
end
end
val.next = nothing
val.queue = nothing
return q
end
#function list_deletefirst!(q::Array{T}, val::T) where T
# i = findfirst(isequal(val), q)
# i === nothing || deleteat!(q, i)
# return q
#end
mutable struct LinkedListItem{T}
# Adapter class to use any `T` in a LinkedList
next::Union{LinkedListItem{T}, Nothing}
queue::Union{InvasiveLinkedList{LinkedListItem{T}}, Nothing}
value::T
LinkedListItem{T}(value::T) where {T} = new{T}(nothing, nothing, value)
end
const LinkedList{T} = InvasiveLinkedList{LinkedListItem{T}}
# delegate methods, as needed
eltype(::Type{<:LinkedList{T}}) where {T} = @isdefined(T) ? T : Any
iterate(q::LinkedList) = (h = q.head; h === nothing ? nothing : (h.value, h))
iterate(q::InvasiveLinkedList{LLT}, v::LLT) where {LLT<:LinkedListItem} = (h = v.next; h === nothing ? nothing : (h.value, h))
push!(q::LinkedList{T}, val::T) where {T} = push!(q, LinkedListItem{T}(val))
pushfirst!(q::LinkedList{T}, val::T) where {T} = pushfirst!(q, LinkedListItem{T}(val))
pop!(q::LinkedList) = invoke(pop!, Tuple{InvasiveLinkedList,}, q).value
popfirst!(q::LinkedList) = invoke(popfirst!, Tuple{InvasiveLinkedList,}, q).value
function list_deletefirst!(q::LinkedList{T}, val::T) where T
h = q.head
while h !== nothing
if isequal(h.value, val)
list_deletefirst!(q, h)
break
end
h = h.next
end
return q
end