-
Notifications
You must be signed in to change notification settings - Fork 59
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request #41 from JuliaCollections/teh/more_examples
Add binary tree examples
- Loading branch information
Showing
7 changed files
with
197 additions
and
27 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,25 @@ | ||
using AbstractTrees | ||
|
||
mutable struct BinaryNode{T} | ||
data::T | ||
parent::BinaryNode{T} | ||
left::BinaryNode{T} | ||
right::BinaryNode{T} | ||
|
||
# Root constructor | ||
BinaryNode{T}(data) where T = new{T}(data) | ||
# Child node constructor | ||
BinaryNode{T}(data, parent::BinaryNode{T}) where T = new{T}(data, parent) | ||
end | ||
BinaryNode(data) = BinaryNode{typeof(data)}(data) | ||
|
||
function leftchild(data, parent::BinaryNode) | ||
!isdefined(parent, :left) || error("left child is already assigned") | ||
node = typeof(parent)(data, parent) | ||
parent.left = node | ||
end | ||
function rightchild(data, parent::BinaryNode) | ||
!isdefined(parent, :right) || error("right child is already assigned") | ||
node = typeof(parent)(data, parent) | ||
parent.right = node | ||
end |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,44 @@ | ||
# This file demonstrates a relatively simple way to implement the AbstractTrees | ||
# interface for a classic binary tree. See "binarytree_infer.jl" for a more performant | ||
# (but laborious) approach. | ||
|
||
if !isdefined(@__MODULE__, :BinaryNode) | ||
include("binarytree_core.jl") | ||
end | ||
|
||
## Things we need to define | ||
function AbstractTrees.children(node::BinaryNode) | ||
if isdefined(node, :left) | ||
if isdefined(node, :right) | ||
return (node.left, node.right) | ||
end | ||
return (node.left,) | ||
end | ||
isdefined(node, :right) && return (node.right,) | ||
return () | ||
end | ||
|
||
## Things that make printing prettier | ||
AbstractTrees.printnode(io::IO, node::BinaryNode) = print(io, node.data) | ||
|
||
## Optional enhancements | ||
# These next two definitions allow inference of the item type in iteration. | ||
# (They are not sufficient to solve all internal inference issues, however.) | ||
Base.eltype(::Type{<:TreeIterator{BinaryNode{T}}}) where T = BinaryNode{T} | ||
Base.IteratorEltype(::Type{<:TreeIterator{BinaryNode{T}}}) where T = Base.HasEltype() | ||
|
||
## Let's test it. First build a tree. | ||
root = BinaryNode(0) | ||
l = leftchild(1, root) | ||
r = rightchild(2, root) | ||
lr = rightchild(3, l) | ||
|
||
print_tree(root) | ||
collect(PostOrderDFS(root)) | ||
@static if isdefined(@__MODULE__, :Test) | ||
@testset "binarytree_easy.jl" begin | ||
@test [node.data for node in PostOrderDFS(root)] == [3, 1, 2, 0] | ||
@test [node.data for node in PreOrderDFS(root)] == [0, 1, 3, 2] | ||
@test [node.data for node in Leaves(root)] == [3, 2] | ||
end | ||
end |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,71 @@ | ||
# This file illustrates how to create inferrable tree-iteration methods in circumstances | ||
# where the children are not naturally indexable. | ||
# See "binarytree_easy.jl" for a simpler approach. | ||
|
||
if !isdefined(@__MODULE__, :BinaryNode) | ||
include("binarytree_core.jl") | ||
end | ||
|
||
## Enhancement of the "native" binary tree | ||
# You might have the methods below even if you weren't trying to support AbstractTrees. | ||
|
||
# Implement iteration over the immediate children of a node | ||
function Base.iterate(node::BinaryNode) | ||
isdefined(node, :left) && return (node.left, false) | ||
isdefined(node, :right) && return (node.right, true) | ||
return nothing | ||
end | ||
function Base.iterate(node::BinaryNode, state::Bool) | ||
state && return nothing | ||
isdefined(node, :right) && return (node.right, true) | ||
return nothing | ||
end | ||
Base.IteratorSize(::Type{BinaryNode{T}}) where T = Base.SizeUnknown() | ||
Base.eltype(::Type{BinaryNode{T}}) where T = BinaryNode{T} | ||
|
||
## Things we need to define to leverage the native iterator over children | ||
## for the purposes of AbstractTrees. | ||
# Set the traits of this kind of tree | ||
Base.eltype(::Type{<:TreeIterator{BinaryNode{T}}}) where T = BinaryNode{T} | ||
Base.IteratorEltype(::Type{<:TreeIterator{BinaryNode{T}}}) where T = Base.HasEltype() | ||
AbstractTrees.parentlinks(::Type{BinaryNode{T}}) where T = AbstractTrees.StoredParents() | ||
AbstractTrees.siblinglinks(::Type{BinaryNode{T}}) where T = AbstractTrees.StoredSiblings() | ||
# Use the native iteration for the children | ||
AbstractTrees.children(node::BinaryNode) = node | ||
|
||
Base.parent(root::BinaryNode, node::BinaryNode) = isdefined(node, :parent) ? node.parent : nothing | ||
|
||
function AbstractTrees.nextsibling(tree::BinaryNode, child::BinaryNode) | ||
isdefined(child, :parent) || return nothing | ||
p = child.parent | ||
if isdefined(p, :right) | ||
child === p.right && return nothing | ||
return p.right | ||
end | ||
return nothing | ||
end | ||
|
||
# We also need `pairs` to return something sensible. | ||
# If you don't like integer keys, you could do, e.g., | ||
# Base.pairs(node::BinaryNode) = BinaryNodePairs(node) | ||
# and have its iteration return, e.g., `:left=>node.left` and `:right=>node.right` when defined. | ||
# But the following is easy: | ||
Base.pairs(node::BinaryNode) = enumerate(node) | ||
|
||
|
||
AbstractTrees.printnode(io::IO, node::BinaryNode) = print(io, node.data) | ||
|
||
root = BinaryNode(0) | ||
l = leftchild(1, root) | ||
r = rightchild(2, root) | ||
lr = rightchild(3, l) | ||
|
||
print_tree(root) | ||
collect(PostOrderDFS(root)) | ||
@static if isdefined(@__MODULE__, :Test) | ||
@testset "binarytree_infer.jl" begin | ||
@test @inferred(map(x->x.data, PostOrderDFS(root))) == [3, 1, 2, 0] | ||
@test @inferred(map(x->x.data, PreOrderDFS(root))) == [0, 1, 3, 2] | ||
@test @inferred(map(x->x.data, Leaves(root))) == [3, 2] | ||
end | ||
end |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
0e2ae9d
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@JuliaRegistrator
register()
0e2ae9d
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Registration pull request created: JuliaRegistries/General/7813
After the above pull request is merged, it is recommended that a tag is created on this repository for the registered package version.
This will be done automatically if Julia TagBot is installed, or can be done manually through the github interface, or via: