Data Structures for Representing Trees

advertisement
Tree representation and tree
search
- Ed. 2. and 3.: Chapter 6
- Ed. 4.: Chapter 10
Data Structures for Representing
Trees
Recall that we can use arrays or linked
lists to implement sequences.
B
T
c
b
1
2
3
How can a tree be represented in a
program?
4
Since a binary tree is an ordered tree and has levels, it is
convenient to assign a number to each node.
1
2
3
4
8
5
9
10
6
11
12
7
13
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
14
15
Formally, for every node v of a tree T, let p(v) be the integer
defined as follows.
 If v is the root of T, then p(v) = 1.
 If v is the left child of the node u, then p(v) = 2p(u)
 If v is the right child of the node u, then p(v) = 2p(u) + 1.
2 u p(u)=2
2p(u)=4
p(u)=4
2p(u)+1=5
4
5
2p(u)+1=9
2p(u)=8 8
8
4
9
10
9
11
The function p() is called a level numbering of the nodes in a
binary tree T.
In general, the numbers for nodes may not be consecutive
when the number of nodes at some level does not reach its
maximum.
1
2
3
4
5
10
7
11
14
15
With a level numbering of the nodes, it is convenient to use a
vector S to represent a tree.
Recall that we use ranks to access elements in a vector. So we
can place the node v in a tree T at rank p(v).
1
2
3
4
5
10
1
2
3
7
11
4
5
14
7
10 11
15
14 15
We can also use a linked structure to represent a tree. In this
case, the node v of a tree T is represented by an object with
four references.
parent
left
right
element
providence
root
Chicago
Seattle
5
size
Baltimore
Baltimore
Chicago
New York
Providence
Seattle
New York
Class BTNode
public class BTNode implements Position {
private Object element;
private BTNode left, right, parent;
public BTNode() {}
public BTNode( Object o, BTNode u, BTNode v, BTNode w ) {
setElement( o );
setParent( u );
setLeft( v ):
setRight( w );
}
public Object element() { return element; }
public void setElement( Object o ) { element = o; }
public BTNode getLeft() { return left; }
public void setLeft( BTNode v ) { left = v; }
public BTNode getRight() { return right; }
public void setRight( BTNode v ) { right = v; }
public BTNode getParent() { return parent; }
public void setParent( BTNode v ) { parent = v; }
}
Interface Hierarchy for Positions
Position
element();
DNode
element(){…};
getNext(){…};
getPrev(){…};
setNext(){…};
setPrev(){…};
setElement(){…};
BTNnode
element(){…};
getLeft(){…};
getRight(){…};
setLeft(){…};
setRight(){…};
getParent(){…};
setElement(){…};
Class LinkedBinaryTree
Additional methods are supported.
expandExternal(v): Transform the external node v into an internal node
by creating two new external nodes and making them
the left and right children of v, respectively; an error
condition occurs if v is an internal node.
Input: Position; Output: None
v
v
removeAboveExternal(w): Remove the external node w together with its
parent v, replacing v with the sibling of w; this
operation generates an error condition if w is an
internal node or w is the root.
Input: Position; Output: None
v
z
z
w
public class LinkedBinaryTree implements BinaryTree {
private Position root;
private int size;
public LinkedBinaryTree() {
root = new BTNode(null, null, null, null);
size = 1;
}
public int size() { return size; }
public boolean isEmpty() { return ( size == 0 ); }
public boolean isInternal( Position v ) {
return ((( BTNode )v ).getLeft() != null &&
(( BTNode )v ).getRight() != null );
}
public boolean isExternal( Position v ) {
return ((( BTNode )v ).getLeft() == null &&
(( BTNode )v ).getRight() == null );
}
public boolean isRoot( Position v ) {
return ( v == root());
}
public Position root() { return root; }
public ArrayPositionIterator positions() {
Position [] positions = new Position[ size() ];
inorderPositions( root(), positions, 0 );
return new ArrayPositionIterator( positions );
}
Here inorderPositions() returns inorder positions in the array
positions. The constructor ArrayPositionIterator() creates an
object of array-based position iterator.
public Position leftChild( Position v ) {
return (( BTNode )v ).getLeft();
}
public Position rightChild( Position v ) {
return (( BTNode )v ).getRight();
}
public Position sibling( Position v ) {
Position p = parent( v );
Position lc = leftChild( p );
if( v == lc )
return rightChild( p );
else
return lc;
}
p=paren(v)
lc=leftChild(p)
v
rightChild(p)
public Position parent( Position v ) {
return (( BTNode )v ).getParent();
}
public Object replaceElement( Position v, Object o ) {
Object temp = (( BTNode )v ).element();
(( BTNode )v ).setElement( o );
return temp;
}
public void swapElements( Position v, Position w ) {
Object temp = w.element();
(( BTNode )w ).setElement( v.element());
(( BTNode )v ).setElement( temp );
}
public void expandExternal( Position v ) {
if( isExternal( v )) {
(( BTNode )v ).setLeft( new BTNode( null,
( BTNode )v, null, null ));
(( BTNode )v ).setRight( new BTNode( null,
( BTNode )v, null, null ));
size += 2;
}
}
v
v
public void removeAboveExternal( Position v ) {
if( isExternal( v )) {
BTNode p = ( BTNode )parent( v );
BTNode s = ( BTNode )sibling( v );
if( isRoot( p )) {
s.setParent( null );
root = s;
} else {
BTNode g = ( BTNode )parent( p );
if( p == leftChild( g ))
g.setLeft( s );
else
g.setRight( s );
s.setParent( g );
}
size -= 2;
}
public Iterator elements() { }
}
g
p
s
g
s
v
public class ArrayPositionIterator implements Iterator {
protected Position a[]; // the underlying array
protected Position cur;
int i = 0;
// the current (next) position
public ArrayPositionIterator() { } // default constructor
public ArrayPositionIterator(Position[] L) {
// preferred constructor
a = L;
if (a[0] == null) cur = null; // array is empty
else cur = a[i];
// start with the first position
}
public boolean hasNext() { return (cur != null); }
public Position next() throws NoSuchElementException {
if (!hasNext())
throw new NoSuchElementException("No next position");
Position toReturn = cur;
if (cur == a[i+1]) cur = null;
// no positions left
else cur = a[i+1];
i++; // move cursor to the next position
return toReturn;
}
}
protected void inorderPosition (Position v, Positions[] pos, int i)
throws InvalidPositionException {
if (hasLeft(v))
inorderPosition(left(v), pos, i); // recurse on left child
pos[i] := v; i := i + 1;
//if (((BTPosition)v).element() instanceof Integer)
// System.out.print(((Integer)((BTPosition)v).element()).intValue() + " ");
//else System.out.print(((Character)((BTPosition)v).element()).charValue() + " ");
if (hasRight(v))
inorderPosition(right(v), pos, i); // recurse on right child
}
-
/
+
*
+
3
+
-
3
1
9
*
2
-
3
5
6
7
4
(((( 3 + 1 ) * 3 ) / (( 9 - 5 ) + 2 )) - (( 3 * ( 7 - 4 )) + 6 ))
Each node has a value associated with it.


If a node is external, then its value is that of its variable or constant.
If a node is internal, then its value is defined by applying its operation to the
values of its children.
IspectableContainer
size
isElement
Elements
IspectablePositionContainer
positions
PositionContainer
swapElement
replaceElement
Tree
InspectableTree
root, parent, children, isRoot
isInternal, isExternal
InspectableBinaryTree
leftChild, rightChild, sibling
BinaryTree
imple.
LinkedBinaryTree
… …, replaceElement, swapElement, expandExternal,
removeAboveExternal
A Linked Structure for General
Trees
We can extend the linked structure for
binary tree to represent general trees.
parent
element
childrenContainer
An object of node has three references:
Parent, childrenContainer and element.
Example:
New York
Baltimore
Chicago
Providence
Seattle
Data Structure Exercises 12.1
Preorder Traversal
r
T
Recall that we can visit the
nodes in a binary tree with
inorder traversal.
What if the tree is not a
binary tree?
u
v
Are there any other ways
to visit the nodes
systematically?
Assume we have a tree T (not necessarily a binary tree).
preorder traversal of T: The root of T is visited first and then
the subtrees rooted at its children are traversed recursively. If
the tree is ordered, then the subtrees are traversed according to
the order of the children.
The action of visiting a node:
When we visit each node of T, what do we do?
We can do anything that makes sense such as incrementing a
counter or some complex computation based on the element at
each node.
Example: Preorder traversal of a book structure
Paper
Title Abstract
1.1
Ch. 1
1.2
Ch. 2
2.1
2.2
Ch. 3
2.3
3.1
3.2
References
Algorithm preorder(T,v):
perform the “visit” action for node v
for each child w of v
call preorder(T,w)
v
postorder(T,w)
w
postorder(T,v)
A Java implementation of preorder traversal for printing the elements.
In this case, the action of visiting a node is printing the element.
public static String preorderPrint( InspectableTree T, Position v ) {
String s = v.element().toString();
PositionIterator children = T.children( v );
while( children.hasNext())
s += " " + preorderPrint( T, children.nextPosition());
return s;
}
Example:
What is the string that preorderPrint(T,v) returns?
Sales
Domestic
Canada
v
International
S. America
Overseas
After visiting the node v:
s = “Sales” + “ ” + s1 + “ ” + s2
Sales
Domestic
Canada
v
International
S. America
Overseas
s = “Sales” + “ ” + s1 + “ ” +
s1 = “Domestic”
Sales
Domestic
Canada
v
International
S. America
Overseas
s2
s = “Sales Domestic” + “ ” + s2
s2 = “International” + “ ” + s21 + “ ” +
s22 + “ ” + s23
Sales
Domestic
Canada
v
International
S. America
Overseas
s = “Sales Domestic International” + “ ” +
s21 + “ ” s22 + “ ” s23
s21 = “Canada”
Sales
Domestic
Canada
v
International
S. America
Overseas
s = “Sales Domestic International Canada”
+ “ ” +s22 + “ ” + s23
s22 = “S.America”
Sales
Domestic
Canada
v
International
S. America
Overseas
s = “Sales Domestic International Canada
S.America” + “ ” + s23
s23 = “Oversea”
Sales
Domestic
Canada
v
International
S. America
Overseas
s = “Sales Domestic International Canada
S.America Oversee”
Preorder Traversal of a Binary
Tree
Since a binary tree is just a special case of trees, the algorithm
for preorder traversal of a binary tree is very similar.
Algorithm binaryPreorder(T,v):
perform the “visit” action for node v
if v is an internal node
call binaryPreorder(T, T.leftChild( v ))
call binaryPreorder(T, T.rightChild( v ))
Preorder Traversal Using Stack
S.push(root);
preorder
While (S is not empty) do
{
x := S.pop( );
access x;
let x1, …, xk be the children of x;
for i = k to 1 do
{S.push(xi);}
}
traversal
breadth-first
Q.enqueue(root);
While (Q is not empty) do
{
x := Q.dequeue( );
access x;
let x1, …, xk be the children of x;
for i = 1 to k do
{Q.enqueue(xi);}
}
traversal
Load a tree from disk into main
memory
File:
a
b
e
c
f
g
d
a; b, c, d.
b; e, f.
e;
f;
c; g.
g;
d;
a
b
c
a
d
b
e
e
f
g
public class Node1
{ String x;
Node2 y;
}
public class Node2
{ Node1 x;
Node2 y;
}
f
c
g
d
Access 0th in the file to find the root of the tree;
S.push(root, null);
while (S is not empty) do
{ x := S.pop( );
generate a node n for x.node_info;
if x.point_to_parent is not null
then generate links between n and x.pointer_to_parent;
Access the corresponding line in the file
to find the children of x;
let x1, …, xk be the children of x;
a; b, c, d.
for j = k to 1 do
b; e, f.
S.push(xj, n);
}
e;
stack S:
node_info Pointer_to_parent
f;
c; g.
g;
d;
(*Assume that the nodes are stored in preorder in the
file.*)
i := 0;
Access 0th line in the file to find the root of the tree;
S.push(root, null);
while (S is not empty) do
{ x := S.pop( );
generate a node n for x.node_id;
if x.point_to_parent is not null
then generate links between n and x.pointer_to_parent;
Access the ith line in the file to find the children
of x;
let x1, …, xk be the children of x;
for j = k to 1 do
S.push(xj, n);
i := i + 1;
}
XML File
<book>
<title>
“The Art of Programming”
</title>
<author>
“D. Knuth”
</author>
<year>
“1969”
</year>
</book>
<book>
<title>
<author>
“The Art of “D. Knuth”
Programming”
<year>
“1969”
XML File
Read a file into a character array A:
< b o o k > < t i t l e > “ T h e
stack S:
node_value Pointer_to_node
A r t …
XML File
Algorithm:
Scan array A;
If A[i] is ‘<’ and A[i+1] is a character then {
generate a node x for A[i.e.],
where A[j] is ‘>’ directly after A[i];
let y = S.top().pointer_to_node;
make x be a child of y; S.push(A[i..j], x);
If A[i] is ‘ ‘‘ ’, then {
genearte a node x for A[i.e.],
where A[j] is ‘ ’’ ’ directly after A[i];
let y = S.top().pointer_to_node;
make x be a child of y;
If A[i] is ‘<’ and A[i+1] is ‘/’, then S.pop();
Download