Professional Documents
Culture Documents
! This file may be freely used and copied for educational purposes provided
! this notice remains attached. Extracted from "Fortran 95/2003 Explained"
! Oxford University Press (Oxford and New York), ISBN 0-19-852692-X (Hbk)
! and ISBN 0-19-852693-8 (Pbk).
!
!A recurring problem in computing is the need to manipulate a linked
!data structure.
!This might be a simple linked list like the one encountered in Section
!2.13, but often a more general tree structure is required.
!
!The example in this Appendix consists of a module that establishes and
!navigates one or more such trees, organized as a 'forest', and a short
!test program for it. Here, each node is identified by a name and has
!any number of children, any number of siblings, and (optionally) some
!associated real data. Each root node is regarded as having a common
!parent, the 'forest root' node, whose name is 'forest root'. Thus,
!every node has a parent. The module provides facilities for adding a
!named node to a specified parent, for enquiring about all the nodes
!that are offspring of a specified node, for removing a tree or subtree,
!and for performing I/O operations on a tree or subtree.
!
!The user-callable interfaces are:
!
!start:
! must be called to initialize a forest.
!add_node:
! stores the data provided at the node whose parent is specified
! and sets up pointers to the parent and siblings (if any).
!remove_node:
! deallocate all the storage occupied by a complete tree or
! subtree.
!retrieve:
! retrieves the data stored at a specified node and the names of
! the parent and children.
!dump_tree:
! write a complete tree or subtree.
!restore_tree:
! read a complete tree or subtree.
!finish:
! deallocate all the storage occupied by all the trees of the forest.
!
module directory
!
! Strong typing imposed
implicit none
!
! Only subroutine interfaces, the length of the character
! component, and the I/O unit number are public
public :: start, add_node, remove_node, retrieve,
&
dump_tree, restore_tree, finish
private :: find, remove
!
! Module constants
character(len=*), private, parameter :: eot = "End-of-Tree....."
integer, parameter, public :: unit = 4, & ! I/O unit number
max_char = 16 ! length of character
! component
!
! Define the basic tree type
!
!
!
!
!
name of node
stored real data
parent node
next sibling node
first child node
current
! current node
forest_root ! the root of the forest
max_data
! max size of data array
allocatable, target, dimension(:) &
:: names
! for returning list of names
!
!
!
!
!
!
!
!
subroutine find(name)
character(len=*), intent(in) :: name
Make the module variable current point to the node with given name,
or be null if the name is not there.
type(node), pointer
:: root
For efficiency, we search the tree rooted at current, and if this
fails try its parent and so on until the forest root is reached.
if (associated(current)) then
root => current
nullify (current)
else
root => forest_root
end if
do
call look(root)
if (associated(current)) then
return
end if
root => root%parent
if (.not.associated(root)) then
exit
end if
end do
contains
recursive subroutine look(root)
type(node), pointer
:: root
(type(node), intent(in), target :: root is standard conforming too)
Look for name in the tree rooted at root. If found, make the
module variable current point to the node
type(node), pointer
:: child
!
!
!
!
!
!
!
allocate (new_node)
new_node%name = name
if (present(data)) then
allocate(new_node%y(size(data)))
new_node%y = data
max_data = max(max_data, size(data))
else
allocate(new_node%y(0))
end if
!
! If name of parent is not null, search for it.
! If not found, print message.
if (name_of_parent == "") then
current => forest_root
else
call find (name_of_parent)
if (.not.associated(current)) then
print *, "no parent ", name_of_parent, " found for ", name
current => forest_root
end if
end if
new_node%parent => current
new_node%sibling => current%child
current%child => new_node
nullify(new_node%child)
end subroutine add_node
subroutine remove_node(name)
character(len=*), intent(in) :: name
! Remove node and the subtree rooted on it (if any),
! deallocating associated pointer targets.
parent = current%parent%name
! Count the number of children
counter = 0
child => current%child
do
if (.not.associated(child)) then
exit
end if
counter = counter + 1
child => child%sibling
end do
deallocate (names)
allocate (names(counter))
! and store their names
children => names
child => current%child
do i = 1, counter
children(i) = child%name
child => child%sibling
end do
else
nullify(data)
parent = ""
nullify(children)
end if
end subroutine retrieve
!
!
!
!
subroutine dump_tree(root)
character(len=*), intent(in) :: root
Write out a complete tree followed by an end-of-tree record
unformatted on the file unit.
call find (root)
if (associated(current)) then
call tree_out(current)
end if
write(unit = unit) eot, 0, eot
contains
recursive subroutine tree_out (root)
Traverse a complete tree or subtree, writing out its contents
type(node), intent(in) :: root
! root node of tree
Local variable
type(node), pointer
:: child
!
write(unit = unit) root%name, size(root%y), root%y, &
root%parent%name
child => root%child
do
if (.not.associated(child)) then
exit
end if
call tree_out (child)
child => child%sibling
end do
end subroutine tree_out
end subroutine dump_tree
subroutine restore_tree ()
! Reads a subtree unformatted from the file unit.
character(len=max_char)
:: name
integer :: length_y
::
::
::
::
::
::
name
i
data
parent, self
children
siblings
use directory
use tree_print
implicit none
!
! Initialize a tree
call start ()
! Fill it with some data
call add_node("ernest","",(/1.0,2.0/))
call add_node("helen","ernest",(/3.0,4.0,5.0/))
call add_node("douglas","ernest",(/6.0,7.0/))
call add_node("john","helen",(/8.0/))
call add_node("betty","helen",(/9.0,10.0/))
call add_node("nigel","betty",(/11.0/))
call add_node("peter","betty",(/12.0/))
call add_node("ruth","betty")
! Manipulate subtrees
open(unit=unit, form="unformatted", status="scratch",
action="readwrite", position="rewind")
call dump_tree("betty")
call remove_node("betty")
write(unit=*,fmt=*)
call print_tree("ernest")
rewind (unit=unit)
call restore_tree ()
rewind (unit=unit)
write(unit=*,fmt=*)
call print_tree("ernest")
call dump_tree("john")
call remove_node("john")
write(unit=*,fmt=*)
call print_tree("ernest")
rewind (unit=unit)
call restore_tree ()
write(unit=*,fmt=*)
call print_tree("ernest")
! Return storage
call finish ()
end program test
&