diff --git a/src/LeftChildRightSiblingTrees.jl b/src/LeftChildRightSiblingTrees.jl index aefc614..d29b111 100644 --- a/src/LeftChildRightSiblingTrees.jl +++ b/src/LeftChildRightSiblingTrees.jl @@ -13,7 +13,8 @@ export Node, isleaf, islastsibling, lastsibling, - prunebranch! + prunebranch!, + copy_subtree mutable struct Node{T} data::T @@ -100,6 +101,50 @@ function addchild(parent::Node{T}, data) where T newc end +""" + child = addchild(parent::Node{T}, data::Node{T}) where {T} + +Add a node `data` as the last child of `parent`. Requires that `data` is a root node. +""" +function addchild(parent::Node{T}, data::Node{T}) where T + if !isroot(data) + error("Child node must be a root node") + end + prevc = parent.child + if prevc == parent + parent.child = data + else + prevc = lastsibling(prevc) + prevc.sibling = data + end + data.parent = parent + data +end + +""" + new_root = copy_subtree(root::Node{T}) where {T} + +Get a shallow copy of the subtree rooted at `root`. Note that this does not copy the +data, and only copies the tree structure. +""" +function copy_subtree(root::Node{T}) where {T} + new_root = Node{T}(root.data) + if !isleaf(root) + last_child = new_root + for child in root + new_child = copy_subtree(child) + if last_child === new_root + new_root.child = new_child + else + last_child.sibling = new_child + end + new_child.parent = new_root + last_child = new_child + end + end + return new_root +end + """ isroot(node) @@ -239,7 +284,7 @@ function Base.:(==)(a::Node, b::Node) reta, retb = iterate(a), iterate(b) while true reta === retb === nothing && return true - (reta === nothing) || (retb === nothing) && return false + ((reta === nothing) || (retb === nothing)) && return false childa, statea = reta childb, stateb = retb childa == childb || return false diff --git a/test/runtests.jl b/test/runtests.jl index 08b0021..8d4f3bd 100644 --- a/test/runtests.jl +++ b/test/runtests.jl @@ -104,6 +104,38 @@ end c = collect(tree1) addchild(last(c), "Kid") @test tree1 != tree2 + + root = Node(1) + otherroot = Node(2) + addchild(otherroot, 3) + addchild(otherroot, 4) + newc = addchild(root, otherroot) + @test newc === otherroot + @test !isleaf(root) + @test depth(root) == 3 + @test map(x -> x.data, collect(PreOrderDFS(root))) == [1, 2, 3, 4] + tmp = Node(0) + @test_throws ErrorException addchild(tmp, otherroot) + thirdroot = Node(5) + addchild(thirdroot, 6) + addchild(thirdroot, 7) + newc = addchild(root, thirdroot) + @test newc === thirdroot + @test map(x -> x.data, collect(PreOrderDFS(root))) == [1, 2, 3, 4, 5, 6, 7] + + @test !islastsibling(otherroot) + copied_root = copy_subtree(otherroot) + @test AbstractTrees.isroot(copied_root) + @test islastsibling(copied_root) + for (oldchild, newchild) in zip(otherroot, copied_root) + @test oldchild.parent === otherroot + @test newchild.parent === copied_root + end + + leaf = Node(2) + copied_leaf = copy_subtree(leaf) + @test isleaf(leaf) + @test isleaf(copied_leaf) end @testset "AbstractTrees" begin