Skip to content

Commit 214f1d3

Browse files
committed
first commit
0 parents  commit 214f1d3

8 files changed

+370
-0
lines changed

.gitignore

+24
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
# Files generated by invoking Julia with --code-coverage
2+
*.jl.cov
3+
*.jl.*.cov
4+
5+
# Files generated by invoking Julia with --track-allocation
6+
*.jl.mem
7+
8+
# System-specific files and directories generated by the BinaryProvider and BinDeps packages
9+
# They contain absolute paths specific to the host computer, and so should not be committed
10+
deps/deps.jl
11+
deps/build.log
12+
deps/downloads/
13+
deps/usr/
14+
deps/src/
15+
16+
# Build artifacts for creating documentation generated by the Documenter package
17+
docs/build/
18+
docs/site/
19+
20+
# File generated by Pkg, the package manager, based on a corresponding Project.toml
21+
# It records a fixed state of all packages used by the project. As such, it should not be
22+
# committed for packages, but should be committed for applications that require a static
23+
# environment.
24+
Manifest.toml

.vscode/settings.json

+2
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
{
2+
}

Project.toml

+4
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
name = "LinkedList"
2+
uuid = "3e022a7e-7250-4727-bf30-41362114d8c7"
3+
authors = ["steiner <[email protected]>"]
4+
version = "0.1.0"

src/LinkedList.jl

+16
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
module LinkedList
2+
3+
import Base: iterate, show, push!, pop!, popat!, pushfirst!, popfirst!,
4+
isempty, length,
5+
first, last,
6+
replace!, filter, keys, eltype
7+
8+
export ForwardList, List, ForwardNode, ListNode, AbstractLinkedList, AbstractListNode, AbstractConsNode,
9+
iterate, show, push!, popat!, pushfirst!, popfirst!,
10+
isempty, length, first, last, replace!, filter, keys, eltype
11+
12+
include("nodes.jl")
13+
include("exceptioins.jl")
14+
include("lists.jl")
15+
16+
end # module LinkedList

src/exceptioins.jl

+3
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
struct BadOperationException <: Exception
2+
message::String
3+
end

src/lists.jl

+197
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,197 @@
1+
abstract type AbstractLinkedList end
2+
3+
mutable struct ForwardList{T} <: AbstractLinkedList
4+
dummy::DummyNode{T}
5+
current::Union{DummyNode{T}, ForwardNode{T}}
6+
length::Int
7+
nodeConstructor::Function
8+
end
9+
10+
function ForwardList(::Type{T}) where T
11+
dummy = DummyNode{T}(nothing)
12+
13+
return ForwardList{T}(dummy, dummy, 0, (data::T) -> ForwardNode(data))
14+
end
15+
16+
mutable struct List{T} <: AbstractLinkedList
17+
dummy::DummyNode{T}
18+
current::Union{DummyNode{T}, ListNode{T}}
19+
length::Int
20+
nodeConstructor::Function
21+
end
22+
23+
function List(::Type{T}) where T
24+
dummy = DummyNode{T}(nothing)
25+
return List{T}(dummy, dummy, 0, (data::T) -> ListNode(data))
26+
end
27+
28+
dummy(list::AbstractLinkedList) = list.dummy
29+
current(list::AbstractLinkedList) = list.current
30+
length(list::AbstractLinkedList) = list.length
31+
32+
keys(list::AbstractLinkedList) = next(dummy(list))
33+
isempty(list::AbstractLinkedList) = length(list) == 0
34+
35+
nodeConstructor(list::AbstractLinkedList) = list.nodeConstructor
36+
37+
function push!(list::AbstractLinkedList, data::T) where T
38+
list.length += 1
39+
newnode = nodeConstructor(list)(data)
40+
41+
insertNext!(list.current, newnode)
42+
list.current = next(list.current)
43+
end
44+
45+
function pushfirst!(list::ForwardList, data::T) where T
46+
# TODO
47+
end
48+
49+
function pushfirst!(list::List, data::T) where T
50+
list.length += 1
51+
newnode::ListNode = nodeConstructor(list)(data)
52+
unlink::Union{Nothing, ListNode} = next(dummy(list))
53+
54+
if !isnothing(unlink)
55+
insertNext!(newnode, unlink)
56+
else
57+
newnode.next = nothing
58+
newnode.prev = dummy(list)
59+
list.current = newnode
60+
end
61+
62+
insertNext!(dummy(list), newnode)
63+
end
64+
65+
function pop!(list::T) where T <: AbstractLinkedList
66+
if isempty(list)
67+
throw(BadOperationException("the list is empty"))
68+
end
69+
70+
list.length -= 1
71+
72+
prevnode = prev(current(list), dummy(list))
73+
target = next(prevnode)
74+
removeNext!(prevnode)
75+
list.current = prevnode
76+
77+
return dataof(target)
78+
end
79+
80+
function popfirst!(list::T) where T <: AbstractLinkedList
81+
if isempty(list)
82+
throw(BadOperationException("the list is emtpy"))
83+
end
84+
85+
list.length -= 1
86+
prevnode = dummy(list)
87+
target = next(prevnode)
88+
removeNext!(prevnode)
89+
90+
if isempty(list)
91+
list.current = dummy(list)
92+
end
93+
94+
return dataof(target)
95+
end
96+
97+
function popat!(list::L, position::T) where {L <: AbstractLinkedList, T <: AbstractConsNode}
98+
list.length -= 1
99+
100+
prevnode = prev(position, dummy(list))
101+
removeNext!(prevnode)
102+
103+
if isempty(list)
104+
list.current = dummy(list)
105+
end
106+
107+
dataof(position)
108+
end
109+
110+
function pushnext!(list::L, position::E, data::T) where {L <: AbstractLinkedList, E <: AbstractConsNode, T}
111+
list.length += 1
112+
newnode = nodeConstructor(list)(data)
113+
unlink = next(position)
114+
insertNext!(newnode, unlink)
115+
insertNext!(position, newnode)
116+
end
117+
118+
function iterate(list::T) where T <: AbstractLinkedList
119+
firstNode = next(dummy(list))
120+
return if isnothing(firstNode)
121+
firstNode
122+
else
123+
dataof(firstNode), next(firstNode)
124+
end
125+
end
126+
127+
function iterate(::T, state::E) where {T <: AbstractLinkedList, E <: Union{AbstractConsNode, Nothing}}
128+
return if isnothing(state)
129+
nothing
130+
else
131+
dataof(state), next(state)
132+
end
133+
end
134+
135+
replace!(node::Union{ForwardNode{T}, ListNode{T}}, data::T) where T = node.data = data
136+
137+
function first(list::AbstractLinkedList)
138+
firstnode = next(dummy(list))
139+
140+
if isnothing(firstnode)
141+
throw(BadOperationException("there is no elements in the list"))
142+
end
143+
144+
return dataof(firstnode)
145+
end
146+
147+
function last(list::AbstractLinkedList)
148+
lastnode = current(list)
149+
150+
if isnothing(lastnode)
151+
throw(BadOperationException("there is no elements in the list"))
152+
end
153+
154+
return dataof(lastnode)
155+
end
156+
157+
function contains(list::AbstractLinkedList, data::T)::Bool where T
158+
for value in list
159+
if value == data
160+
return true
161+
end
162+
end
163+
164+
return false
165+
end
166+
167+
function show(io::IO, list::AbstractLinkedList)
168+
print(io, "list: ")
169+
170+
for value in list
171+
print(io, value, ' ')
172+
end
173+
end
174+
175+
function filter(pred::Function, list::ForwardList{T})::ForwardList{T} where T
176+
result = ForwardList(T)
177+
178+
for value in list
179+
if pred(value)
180+
push!(result)
181+
end
182+
end
183+
184+
result
185+
end
186+
187+
function filter(pred::Function, list::List{T})::List{T} where T
188+
result = ForwardList(T)
189+
190+
for value in list
191+
if pred(value)
192+
push!(result)
193+
end
194+
end
195+
196+
result
197+
end

src/nodes.jl

+98
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,98 @@
1+
abstract type AbstractListNode end
2+
abstract type AbstractConsNode{T} <: AbstractListNode end
3+
4+
mutable struct DummyNode{T} <: AbstractListNode
5+
next::Union{Nothing, AbstractConsNode{T}}
6+
end
7+
8+
mutable struct ForwardNode{T} <: AbstractConsNode{T}
9+
data::T
10+
next::Union{Nothing, ForwardNode{T}}
11+
end
12+
13+
mutable struct ListNode{T} <: AbstractConsNode{T}
14+
data::T
15+
next::Union{Nothing, ListNode{T}}
16+
prev::Union{Nothing, DummyNode{T}, ListNode{T}}
17+
end
18+
19+
ForwardNode(data::T) where T = ForwardNode{T}(data, nothing)
20+
ListNode(data::T) where T = ListNode{T}(data, nothing, nothing)
21+
22+
next(node::AbstractListNode) = node.next
23+
dataof(node::AbstractConsNode) = node.data
24+
prev(node::ListNode, ::DummyNode) = node.prev
25+
26+
function prev(node::ForwardNode, start::DummyNode)::Union{DummyNode, ForwardNode}
27+
cursor = next(start)
28+
prev = start
29+
30+
while cursor != node
31+
prev = cursor
32+
cursor = next(cursor)
33+
end
34+
35+
return prev
36+
end
37+
38+
function insertNext!(node::DummyNode, nextnode::ForwardNode)
39+
nextOfDummy = node.next
40+
node.next = nextnode
41+
nextnode.next = nextOfDummy
42+
end
43+
44+
function insertNext!(node::DummyNode, nextnode::ListNode)
45+
nextOfDummy = node.next
46+
node.next = nextnode
47+
nextnode.next = nextOfDummy
48+
nextnode.prev = node
49+
50+
if !isnothing(nextOfDummy)
51+
nextOfDummy.prev = nextnode
52+
end
53+
end
54+
55+
function insertNext!(node::ForwardNode, nextnode::ForwardNode)
56+
nextOfNode::Union{Nothing, ForwardNode} = node.next
57+
58+
nextnode.next = nextOfNode
59+
node.next = nextnode
60+
end
61+
62+
function insertNext!(node::ListNode, nextnode::ListNode)
63+
nextOfDummy::Union{Nothing, ListNode} = node.next
64+
65+
if !isnothing(nextOfDummy)
66+
nextOfDummy.prev = nextnode
67+
end
68+
69+
nextnode.next = nextOfDummy
70+
71+
node.next = nextnode
72+
nextnode.prev = node
73+
end
74+
75+
function removeNext!(node::AbstractListNode)
76+
targetNode = next(node)
77+
78+
if isnothing(targetNode)
79+
throw(BadOperationException("there is no more nodes to remove"))
80+
end
81+
82+
unlinkNode::Union{Nothing, AbstractListNode} = next(targetNode)
83+
84+
if !isnothing(unlinkNode)
85+
insertNext!(node, unlinkNode)
86+
else
87+
node.next = unlinkNode
88+
end
89+
end
90+
91+
iterate(node::AbstractListNode) = node, next(node)
92+
iterate(::AbstractConsNode, nextnode::AbstractConsNode) = nextnode, next(nextnode)
93+
94+
show(io::IO, ::DummyNode) = print(io, "dummy ->")
95+
show(io::IO, node::AbstractConsNode) = print(io, "$(dataof(node)) ->")
96+
97+
eltype(::DummyNode{T}) where T = T
98+
eltype(::AbstractConsNode{T}) where T = T

test/runtests.jl

+26
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
using LinkedList
2+
3+
let list = List(Int)
4+
5+
for i in 1:10
6+
push!(list, i)
7+
end
8+
9+
println(list)
10+
11+
for i in 1:10
12+
pop!(list)
13+
println(list)
14+
end
15+
end
16+
17+
let list = List(Int)
18+
for i in 1:10
19+
pushfirst!(list, i)
20+
21+
println(list)
22+
end
23+
24+
end
25+
26+
# test: pop at current

0 commit comments

Comments
 (0)