Solution4BSTandHEAPS

advertisement
PROGRAMMING II – ABSTRACT DATA TYPES
Unassessed Coursework 4: Binary Search Trees and Heaps
The aims of this coursework is to practice:
 using Binary Search Trees (BST) by writing examples of higher level procedures and using
them in small problems.
 using heaps by writing examples of access procedures, higher level procedures and small
problem applications.
1. Assume the Java type declaration for the dynamic implementation of a BST given in Slide 3 of
the lecture nodes on BST, with searchkey of type Integer and value of type String. Give the Java
implementation of the following access procedure using recursion:
public String retrieve(int searchKey)
//post: Returns the item in the BST whose search key equals searchKey.
//Returns null if no such item exists
2. Assume the availability of an ADT List of integers, with access procedures isEmpty, add,
remove, get, and the availability of an ADT BinarySearchTree<String Integer> with its own
access procedures, including the access procedures getLeftSubTree and getRightSubTree. Write
the Java implementation of the following high-level procedures, using recursion:
public List TreetoList(BinarySearchTree<String, Integer> myTree).
//post: Returns a list containing the item values in the tree in descending
//order.
public List getOdd(BinarySearchTree<String, Integer> myTree)
//post: Returns a list containing the odd (i.e. not divisible by 2) values in
//the tree in ascending order.
3. The following Abstract Data Type QueueTrees consists of a queue of Binary Search Trees. The
queue’s node includes a value of type char, and the tree’s node includes a search key of type
Integer and a value of type String as illustrated in the picture below.
QueueTrees
last first
5
A
2
B
.
.
T
Name
11
10
Name
Name
7
Name
Name
20
Name
(a) Give the Java type declarations for this ADT QueueTrees including the type
declarations of all the data structures needed to implement it.
(b) Assume now the existence of a class BinarySearchTree that implements an ADT
BinarySearchTree. Give the new type declaration for QueueTrees.
(c) Using your answer to part (b), give the Java implementation of the following access
procedure. Include all additional access procedures needed to implement this access
procedure.
public void AddNewTNode(Integer SearchKey, String NewName){
//pre: Takes newName and a key value searchKey.
//post: insert a new node with the given name and search key in the tree
//referenced by the first node in the queue.
4. Consider the static implementation of an ADT Heap illustrated diagrammatically in slide 6 of
the lecture notes on Heaps. Assume the elements included in the heap to be of type Integer.
(a) Give the Java data structure declaration for such type of implementation, assuming the
maximum size of the heap to be equal to 100.
(b)Implement the constructor for creating an empty heap, and the access procedures
isEmpty( ) and heapInsert(Integer newItem). Provide also an appropriate
HeapException method.
5. In slide 9 of the lecture notes on Heaps, I gave the pseudocode of the procedure heapRebuild.
Assume now this procedure to be an auxiliary procedure of a class Heap that implements a heap.
Using the Java data structure declaration you have given in question 4(a), give the Java
implementation of auxiliary procedure heapRebuild, declared as follows:
protected void heapRebuild(Integer[ ] items, int root, size)
//pre “root” is the index of the semi-heap’s root that has to be placed at
//the proper position.
6. Assume the existence of a class Heap that implements an ADT heap of elements of type T.
Implement an ADT PriorityQueue, of elements also of type T, that uses the class Heap as
underlying data structure, and has the access procedures defined by the following interface. For
simplicity, ignore the cases of exception.
public interface PQInterface<T>{
}
public boolean pqisEmpty();
//pre: none
//post: Insert newItem in the priority queue at its proper position.
public void pqInsert(T newItem)
//pre: none
//post: Retrieve and delete the item with highest priority.
public T pqDelete( )
7. Assume the existence of a class Heap that implements an ADT heap of elements of type Integer.
Give the Java implementation of the following high-level procedure. If you use any auxiliary
procedure, give also its implementation.
public Heap ChangeItem(Heap myHeap, Integer Item, newItem)
//pre: myHeap is not empty
//post: returns a new heap equal to myHeap but with Item replaced by
//newItem, if Item is in myHeap.
8. Assume an hash table of just integers, that uses the hash function h(x) = x mod 7 and a separate
chaining strategy for resolving conflicts. What does the hash table loop like after the following
insertions occur?
8, 10, 24, 15, 32, 17
9. Consider the following two hash functions:
h1(key) = key div 250
h2(key) = key mod 250
where the possible key range is the set of integers 1, 2, 3,…, 1000. Assume the hash table to be
an array of size 250, where each item is capable of holding 2 items, and to use an open
addressing scheme to resolve collisions. For each of the functions h1 and h2, show the
distribution of the keys among the table after the following insertions are performed:
(a) 1,2,3,…,250 are added to an empty table
(b) 5, 10, 15, 20, …, 980, 985, 990, 995, 1000 are added to an empty table.
(c) What conclusion can you draw from this example about the selection of a hash
function?
PROGRAMMING II – ABSTRACT DATA TYPES
Unassessed Coursework 4 ANSWERS: Binary Search Trees and Heaps
1.
public String retrieve(int searchKey){
return retrieveItem(root, new Integer(searchKey));
}//end retrieve
private String retrieveItem(TreeNode<Integer, String> tNode, Integer Key) {
if (tNode == null) {
return = null;
}
else{ if (Key.equals(tNode.getKey( )){
String nodeValue = tNode.getValue( );}
else { if (Key.compareTo(tNode.getKey( )) < 0) {
nodeValue = retrieveItem(tNode.getLeft( ), Key);
}
else{
nodeValue = retrieveItem(tNode.getRight( ), Key);\
}}
return nodeValue;
}
}// end retrieveItem
2.
public List TreetoList(BinarySearchTree<String, Integer> myTree)
{ List newlist = new List( );
return TreeListCons(myTree, newlist); }
private List TreeListCons(BinarySearchTree<String, Integer> myTree, List
mylist){
if (myTree.isEmpty( )){
return mylist;
}
else{ mylist = TreeListCons(myTree.getLeftSubTree( ), mylist);
Integer item = myTree.getRoot( );
mylist.add(1, item.intValue( ));
mylist = TreeListCons(myTree.getRightSubTree( ), mylist);
return mylist;
}
}
public List getOdd(BinarySearchTree<String, Integer> myTree){
List newlist = new List( );
return getOddCons(myTree, newlist);}
public List getOddCons(BinarySearchTree<String, Integer> myTree, List mylist){
if (myTree.isEmpty( )){
return mylist;
}
else{ mylist = getOddCons(myTree.getLeftSubTree( ), mylist);
if((myTree.getRoot( )).intValue( )%2 != 0) {
mylist.add(mylist.size( )+1, (myTree.getRoot( )).intValue( ));}
mylist = getOddCons(myTree.getRightSubTree( ), mylist);
return mylist;
}
}
3.
(a)
(b)
1. class TreeNode<K,V>{
}
private K key;
private V value;
private TreeNode<K,V> left;
private TreeNode<K,V> right;
… // methods definitions;
2. class BST<K extends
}
1. class TreeNode<K,V>{
}
class QueueNode{
private BinarySearchTree
<Integer, String> tree;
private char item;
private QueueNode next;
….// methods definitions
}
2.
Comparable<K>,V>{
private TreeNode<K,V> root;
… // methods definitions
3. class QueueNode{
private BST<Integer, String> tree;
private char item;
private QueueNode next;
….// methods definitions
}
4. class Queue{
}
private QueueNode first;
private QueueNode last;
….// methods definitions
5. class QueueTrees
}
private Queue fullstructure;
….//methods definitions
private K key;
private V value;
private TreeNode<K,V> left;
private TreeNode<K,V> right;
… // methods definitions;
3. class Queue{
}
private QueueNode first;
private QueueNode last;
….// methods definitions
4. class QueueTrees
}
private Queue fullstructure;
….//methods definitions
(c)
public void AddNewTNode(Integer searchKey, String newName){
//pre: Takes newName and a search key value SearchKey
//post: insert a new node with the given name and search key in the tree
//pointed by the first node in the queue
QueueNode myqueueElement = fullstructure.getFrontNode( );
BinarySearchTree<Integer, String> mytree = myqueueElement.getTree( );
mytree.insert(searchKey, newName);
}
public QueueNode getFrontNode( ){
//This is an access procedure of the class Queue
return first;
}
public BinarySearchTree getTree( ){
//This is an access procedure of the class QueueNode
return tree;
}
Note: we don’t need to give the implementation of insert because we are assuming that
there is already an implementation of a BinarySearchtre ADT with its access procedures.
4.
(a)
(b)
public class Heap<Integer>{
private int max_heap = 100;
private Integer[ ] items;
private int size;
// access procedures
}
//maximum size of the heap
//array of heap items
//number of items in the heap
public Heap( ){
items = (T[ ]) new Object[max_heap];
size = 0;
}
public boolean isEmpty( ){
return size = = 0;
}
public void heapInsert(Integer newItem) throws HeapException{
if (size < Max_Heap){
item[size] = newItem;
int place = size;
int parent = (place –1)/2;
while ( (parent >=0) && (items[place].compareTo(items[parent])>0){
Integer temp = item[place];
items[place] = items[parent];
items[parent] = temp;
place = parent;
parent = (place-1)/2;
}//end while
else { throw new HeapException(“HeapException: Heap full”); }
}//end heapInsert
public class HeapException extends RuntimeException{
public HeapException(String s){
super(s);
}//end constructor
} //end HeapException
5.
protected void heapRebuild(Integer[ ] items, int root, int size){
int child = 2*root+1;
if( child < size){//root is not a leaf, so it has a left child at position child
int rightChild = child+1;
if ((rightChild < size) && (items[rightChild].compareTo(items[child]) > 0)){
child = rightChild;
}
if (items[root].compareTo(items[child]) < 0){
Integer temp = items[root];
items[root] = items[child];
items[child] = temp;
heapRebuild(items, child, size);}
}
}
6.
public class PriorityQueue<T extends Comparable<T>> implements
PQInterface{
private Heap<T> h;
public PriorityQueue( ){
h = new Heap( );}
public boolean pqisEmpty( ){
return h.isEmpty( );}
public void pqInsert(T newItem){
h.heapInsert(newItem);}
public T pqDelete( ){
return h.heapDelete( );}
}
NOTE: In the above implementation of the method “pqInsert”, we have ignored the fact
that heapInsert may throw an exception when the heap is full. This is because I have asked
in the question to not consider the cases of exception. A full implementation of the method
“pqInsert” would have to use “try” and “catch” in order to try the operation “heapInsert”
and catch a possible exception, and then itself throw an exception error.
public Heap ChangeItem(Heap myHeap, Integer item, Integer newItem){
Heap auxheap = new Heap( );
boolean done = false;
do{
Integer temp = myHeap.heapDelete( );
if (! temp.equals(item)){ auxheap.heapInsert(temp); }
else { auxheap.heapInsert(newItem);
done = true; }
}while (! (done || myHeap.isEmpty( )) );
heapCopy(myHeap, auxheap);
return auxheap;
7.
}
public void heapCopy(Heap fromHeap, Heap toHeap){
Integer temp;
while(!fromHeap.isEmpty( )){
toHeap.heapInsert(fromHeap.heapDelete( ));
}
}
8.
0
1
2
3
4
5
6
15
8
17
32
24
10
9.
(a)
1. Consider the function h1:
1 2 3 4 5 6 7 8
0
1
2
3
50
24
248 249 250
123 124
Only the first and second element will be at theirn own hash position, all the other will be
included in the table by linearly probing along the array. In particular:
1, 2 are at their hash position,
3, 4 are at their probed position 1
5, 6 are at their pobed position 2, etc…
2. Consider the function h2:
0
1
2
3
1
2
3
4
24
248 249 250
24
248 249
In this case all the elements are inserted at their own proper hash positions.
(b)
1. Consider the function h1:
5 10 15 20 25 30 35 40 ……
0
1
2
3
250
990 995 1000
24
98 99
248 249
Only 5 and 10 will be at their own position, all the other will be included in the table by
linearly probing along the array.
2. Consider the function h2:
5
0
1
2
3
10 15 20 245 250 255
5
10
495
500
745 995
1000
245
The picture above shows only some of the allocations in the table. In particular:
all the elements from 5 to 500 are allocated at their own hash positions (these are half
of the keys values). The other elements are probed along the table.
(c) Conclusion:
1) If the hash function uses some kind of division method, the “mod function is better
than the div function.
2) Moreover, when using the mod function make sure that the number of positions in the
table (i..e the size of the table) is a prime number. For instance in the above case, we
were able only to assign half of the givens equence of numbers at their respective
hash positions essentially because the sequence of numbers was given by the
expression m* i*5, where i= 0,1,2,3,…..and the number 5 is a factor of the size of the
table.
249
Download