Skip to content

Commit 7c830d1

Browse files
feat: allow adding Node as child of Node (#27)
Closes #14
1 parent 2a1b372 commit 7c830d1

File tree

2 files changed

+79
-2
lines changed

2 files changed

+79
-2
lines changed

src/LeftChildRightSiblingTrees.jl

Lines changed: 47 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,8 @@ export Node,
1313
isleaf,
1414
islastsibling,
1515
lastsibling,
16-
prunebranch!
16+
prunebranch!,
17+
copy_subtree
1718

1819
mutable struct Node{T}
1920
data::T
@@ -100,6 +101,50 @@ function addchild(parent::Node{T}, data) where T
100101
newc
101102
end
102103

104+
"""
105+
child = addchild(parent::Node{T}, data::Node{T}) where {T}
106+
107+
Add a node `data` as the last child of `parent`. Requires that `data` is a root node.
108+
"""
109+
function addchild(parent::Node{T}, data::Node{T}) where T
110+
if !isroot(data)
111+
error("Child node must be a root node")
112+
end
113+
prevc = parent.child
114+
if prevc == parent
115+
parent.child = data
116+
else
117+
prevc = lastsibling(prevc)
118+
prevc.sibling = data
119+
end
120+
data.parent = parent
121+
data
122+
end
123+
124+
"""
125+
new_root = copy_subtree(root::Node{T}) where {T}
126+
127+
Get a shallow copy of the subtree rooted at `root`. Note that this does not copy the
128+
data, and only copies the tree structure.
129+
"""
130+
function copy_subtree(root::Node{T}) where {T}
131+
new_root = Node{T}(root.data)
132+
if !isleaf(root)
133+
last_child = new_root
134+
for child in root
135+
new_child = copy_subtree(child)
136+
if last_child === new_root
137+
new_root.child = new_child
138+
else
139+
last_child.sibling = new_child
140+
end
141+
new_child.parent = new_root
142+
last_child = new_child
143+
end
144+
end
145+
return new_root
146+
end
147+
103148
"""
104149
isroot(node)
105150
@@ -239,7 +284,7 @@ function Base.:(==)(a::Node, b::Node)
239284
reta, retb = iterate(a), iterate(b)
240285
while true
241286
reta === retb === nothing && return true
242-
(reta === nothing) || (retb === nothing) && return false
287+
((reta === nothing) || (retb === nothing)) && return false
243288
childa, statea = reta
244289
childb, stateb = retb
245290
childa == childb || return false

test/runtests.jl

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -104,6 +104,38 @@ end
104104
c = collect(tree1)
105105
addchild(last(c), "Kid")
106106
@test tree1 != tree2
107+
108+
root = Node(1)
109+
otherroot = Node(2)
110+
addchild(otherroot, 3)
111+
addchild(otherroot, 4)
112+
newc = addchild(root, otherroot)
113+
@test newc === otherroot
114+
@test !isleaf(root)
115+
@test depth(root) == 3
116+
@test map(x -> x.data, collect(PreOrderDFS(root))) == [1, 2, 3, 4]
117+
tmp = Node(0)
118+
@test_throws ErrorException addchild(tmp, otherroot)
119+
thirdroot = Node(5)
120+
addchild(thirdroot, 6)
121+
addchild(thirdroot, 7)
122+
newc = addchild(root, thirdroot)
123+
@test newc === thirdroot
124+
@test map(x -> x.data, collect(PreOrderDFS(root))) == [1, 2, 3, 4, 5, 6, 7]
125+
126+
@test !islastsibling(otherroot)
127+
copied_root = copy_subtree(otherroot)
128+
@test AbstractTrees.isroot(copied_root)
129+
@test islastsibling(copied_root)
130+
for (oldchild, newchild) in zip(otherroot, copied_root)
131+
@test oldchild.parent === otherroot
132+
@test newchild.parent === copied_root
133+
end
134+
135+
leaf = Node(2)
136+
copied_leaf = copy_subtree(leaf)
137+
@test isleaf(leaf)
138+
@test isleaf(copied_leaf)
107139
end
108140

109141
@testset "AbstractTrees" begin

0 commit comments

Comments
 (0)