A Binary Tree ADT - PowerPoint PPT Presentation

About This Presentation
Title:

A Binary Tree ADT

Description:

Fields. The definition of a binary tree pretty much requires the following fields: ... I've seen some pretty complicated methods for doing things in the binary tree ... – PowerPoint PPT presentation

Number of Views:205
Avg rating:3.0/5.0
Slides: 28
Provided by: davidleem
Category:
Tags: adt | binary | tree

less

Transcript and Presenter's Notes

Title: A Binary Tree ADT


1
A Binary Tree ADT
2
Fields
  • The definition of a binary tree pretty much
    requires the following fields
  • Object value
  • BinaryTree leftChild
  • BinaryTree rightChild
  • I also wanted to have this additional field
  • BinaryTree parent
  • Should these fields be public, private, or
    somewhere in between?

3
Maintaining control
  • It is the responsibility of any class to ensure
    the safety and validity of its objects
  • Is there any real harm in letting the fields of a
    node in a binary tree be public?
  • In other words, how easily can the binary tree be
    damaged?
  • I claim its quite easy, as I will demonstrate
    shortly
  • In my design, leftChild, rightChild, and parent
    are private, and I provide getters and setters
  • For consistency, the value field should also be
    private

4
Getters and setters
  • Here are the methods we have decided on so far
  • public BinaryTree getLeftChild()
  • public void setLeftChild(BinaryTree child)
  • public BinaryTree getRightChild()
  • public void setRightChild(BinaryTree child)
  • public BinaryTree getParent()
  • public void setParent(BinaryTree parent)
  • We dont want this onewhy not?
  • Have to add parameter to say which child it will
    be
  • We can use setLeftChild or setRightChild instead
  • public Object getValue()
  • public void setValue(Object value)

5
Header nodes
  • I dont like to use a header node for a binary
    tree, because that gets in the way of treating
    the subtrees as binary trees in their own right

6
Constructors
  • There is an obvious three-argument constructor
    that we need
  • public BinaryTree(Object value,
    BinaryTree leftChild,
    BinaryTree rightChild) ...
  • In addition, we need a no-argument constructor
  • This is a requirement for serializable objects
  • public BinaryTree() this(null, null,
    null)
  • Heres a third constructor that I found
    convenient
  • public BinaryTree(Object value)
    this(value, null, null)

7
public void setLeftChild(BinaryTree child)
  • Here is the obvious code for this method
  • public void setLeftChild(BinaryTree newChild)
    leftChild newChild
  • Is there anything wrong with this code?
  • Hint yes

8
Naive setLeftChild
  • Remember that, in this design, a node also has a
    link to its parent
  • This version of setLeftChild does not preserve
    the validity of the data structure

9
public void setLeftChild(BinaryTree child)
  • Here is the improved code for this method
  • public void setLeftChild(BinaryTree newChild)
    leftChild.parent null leftChild
    newChild newChild.parent this
  • Now is this code correct?
  • Is it reasonable to set the left child to null?
  • A binary tree can be empty, so yes
  • What happens if we try to do so?

10
public void setLeftChild(BinaryTree child)
  • Here is even more improved code for this method
  • public void setLeftChild(BinaryTree newChild)
    leftChild.parent null leftChild
    newChild if (newChild ! null)
    newChild.parent this
  • Do you see any more problems?
  • What if the left child was originally null?

11
public void setLeftChild(BinaryTree child)
  • Here is yet another version of this method
  • public void setLeftChild(BinaryTree newChild)
    if (leftChild ! null)
    leftChild.parent null leftChild
    newChild if (newChild ! null)
    newChild.parent this
  • Now is there anything wrong?
  • What if the new child already has a parent?

12
public void setLeftChild(BinaryTree child)
  • And yet again
  • public void setLeftChild(BinaryTree newChild)
    if (leftChild ! null)
    leftChild.parent null leftChild
    newChild if (newChild ! null)
    if (newChild.parent ! null)
    newChild.parent.leftChild null
    newChild.parent this
  • Now is there anything wrong?

13
public void setLeftChild(BinaryTree child)
  • Bad assumption it was previously a left child
  • public void setLeftChild(BinaryTree newChild)
    if (leftChild ! null)
    leftChild.parent null leftChild
    newChild if (newChild ! null)
    if (newChild.parent ! null) if
    (newChild.parent.leftChild this)
    newChild.parent.leftChild null
    else newChild.parent.rightChild
    null newChild.parent
    this
  • Now is there anything wrong?

14
How much is enough?
  • What if the new child is already a node elsewhere
    in the binary tree?
  • Do we need to search the tree to find out?
  • This could be a somewhat expensive searchO(n)
  • All our previous modifications have been O(1),
    that is, constant time
  • I think that this is a problem only if the new
    child is an ancestor of the node it is to be
    added to
  • This is an O(log n) search, if the tree is
    balanced
  • Is this worth doing?
  • Its a judgment callhow safe does our code need
    to be?
  • The answer depends on what the code is for

15
Getters and setters
  • Getters and setters are annoying to write,
    especially when they dont seem to add any value
    to the code
  • There are two purposes
  • To prevent careless or malicious access to the
    object
  • Youve just seen an example of this
  • To preserve flexibility, in case you might want
    to change the object some time in the future
  • For example, if we did not originally have the
    parent link, the following code would have been
    enough
  • public void setLeftChild(BinaryTree newChild)
    leftChild newChild

16
Taking stock
  • Are the constructors and mutators (setXXX
    methods) adequate to construct any binary tree?
  • Yes, provided you start from the root and build
    the binary tree by working downwards
  • However, there isnt much support for changing an
    existing binary tree
  • Can we access all the data in the tree?
  • Yes, with the getXXX methods
  • However, it might be nice to provide convenience
    methods for testing if we are at the root or a
    leaf

17
Convenience accessor methods
  • Its easy enough to test if we are at a root
    (parentnull) or at a leaf (leftChildnull
    rightChildnull), but this is so commonly needed
    that we might as well supply the methods
  • public boolean isRoot()
  • public boolean isLeaf()
  • Besides, using these methods makes the code more
    readable

18
Changing the binary tree
  • Ive seen some pretty complicated methods for
    doing things in the binary tree
  • The kind of changes that are needed in any given
    program are probably very problem-specific
  • What I think we need is not a collection of
    complicated methods, but some very simple methods
    we can put together in complex ways
  • Heres what I have
  • / Breaks the connection between this node and
    its parent. /public void detach() ...

19
detach()
  • After all weve been through with setLeftChild,
    detach is pretty trivial
  • public void detach() if (parent ! null)
    if(parent.leftChild this)
    parent.leftChild null else
    parent.rightChild null parent
    null

20
Using existing methods
  • It is frequently advantageous to use some of the
    methods of a class when implementing other
    methods
  • public void setLeftChild(BinaryTree newChild)
    if (leftChild ! null) leftChild.detach()
    if (newChild ! null) newChild.detach()
    leftChild newChild if (newChild ! null)
    newChild.parent this

21
Serialization methods
  • Since the binary tree needs to be serialized, I
    added the following two methods
  • public static BinaryTree load(String fileName)
    throws IOException
  • public void save(String fileName) throws
    IOException

22
Other input-output methods
  • Its always a good idea to write the following
    method (simplifies debugging)
  • public String toString()
  • Because a binary tree isnt terribly easy to read
    when its shown linearly, I also wrote the
    following method to give me a nicely indented
    tree
  • public void print()

23
toString
  • public String toString() if (isLeaf())
    return value.toString() StringBuffer buffer
    new StringBuffer() buffer.append(""
    value ", ") if (leftChild null)
    buffer.append("null") else
    buffer.append(leftChild.toString())
    buffer.append(", ") if (rightChild null)
    buffer.append("null") else
    buffer.append(rightChild.toString())
    buffer.append("") return buffer.toString()

24
print()
  • toString is handy for producing condensed,
    single-line output, but doesnt show the shape of
    the binary tree
  • To keep track of indentation, we need either a
    global variable (bad) or a parameter (OK)
  • I dont want the user to have to supply this
    parameter, so
  • public void print() print("")
    private void print(String indent) ...

25
print(String indent)
  • private void print(String indent)
    System.out.println(indent value) if
    (isLeaf()) return if (leftChild
    null) System.out.println(indent "
    " "null") else
    leftChild.print(indent " ") if
    (rightChild null)
    System.out.println(indent " " "null")
    else rightChild.print(indent
    " ")

26
Final comments
  • I didnt think of everything when I first wrote
    setLeftChildmy first version was pretty sloppy
  • Maybe there are still some problems Ive
    overlooked
  • No program is ever perfect
  • Corrections are, as always, welcome
  • I took some care because this is intended as an
    example of ADT design
  • For just using it in the Animals! program, I
    wouldnt have been so fussy
  • However, even for just one program, using setters
    and getters is always a good idea
  • Its impressively hard to tell beforehand how
    much a program is going to be used

27
The End
Write a Comment
User Comments (0)
About PowerShow.com