You are on page 1of 118

Date: Ex No: 1 DESCRIPTION: A heap is an efficient semi-ordered data structure for storing a collection of orderable data.

The term binary heap and heap are interchangeable in most cases. A heap can be thought of as a tree with parent and child. The main difference between a heap and a binary tree is the heap property. In order for a data structure to be considered a heap, it must satisfy the following condition (heap property): If A and B are elements in the heap and B is a child of A, then key (A) key (B). (This property applies for a min-heap. A max heap would have the comparison reversed). What this tells us is that the minimum key will always remain at the top and greater values will be below it. Due to this fact, heaps are used to implement priority queues which allow quick access to the item with the most priority. Here's an example of a min-heap: MIN-HEAP

A heap is implemented using an array that is indexed from 1 to N, where N is the number of elements in the heap.

At any time, the heap must satisfy the heap property array[n] <= array[2*n] and array[n] <= array[2*n+1] whenever the indices are in the arrays bounds. The operations commonly performed with a heap are

delete-max or delete-min: removing the root node of a max- or min-heap, respectively increase-key or decrease-key: updating a key within a max- or min-heap, respectively insert: adding a new key to the heap merge: joining two heaps to form a valid new heap containing all the elements of both.

Compute the extreme value We will prove that array[1] is the minimum element in the heap. We prove it by seeing a contradiction if some other element is less than the first element. Suppose array[i] is the first instance of the minimum, with array[j] > array[i] for all j < i, and i>2. But by the heap invariant array, array[floor(i / 2)] < = array[i]: this is a contradiction. Therefore, it is easy to compute MIN(heap): MIN(heap) return heap.array[1]; Removing the Extreme Value To remove the minimum element, we must adjust the heap to fill heap.array[1]. This process is called percolation. Basically, we move the hole from node i to

either node 2i or 2i + 1. If we pick the minimum of these two, the heap invariant will be maintained; suppose array[2i] < array[2i + 1]. Then array[2i] will be moved to array[i], leaving a hole at 2i, but after the move array[i] < array[2i + 1], so the heap invariant is maintained. In some cases, 2i + 1 will exceed the array bounds, and we are forced to percolate 2i. In other cases, 2i is also outside the bounds: in that case, we are done. Therefore, here is the remove algorithm: #define LEFT(i) (2*i) #define RIGHT(i) (2*i + 1) REMOVE_MIN(heap) { savemin=arr[0]; arr[0]=arr[--heapsize]; i=0; while(i<heapsize){ minidx=i; if(LEFT(i)<heapsize && arr[LEFT(i)] < arr[i]) minidx=LEFT(i); if(RIGHT(i)<heapsize && arr[RIGHT(i)] < arr[minidx]) minidx=RIGHT(i); if(mindx!=i){ swap(arr[i],arr[minidx]); i=minidx; } else break;

} } Inserting a value into the heap A similar strategy exists for INSERT: just append the element to the array, then fixup the heap-invariants by swapping. For example if we just appended element N, then the only invariant violation possible involves that element, in particular if array[floor(N / 2)] > array[N], then those two elements must be swapped and now the only invariant violation possible is between array[floor(N/4)] and array[floor(N/2)] we continue iterating until N=1 or until the invariant is satisfied. INSERT(heap, element) append(heap.array, element) i = heap.array.length while (i > 1) { if (heap.array[i/2] <= heap.array[i]) break; swap(heap.array[i/2], heap.array[i]); i /= 2; }

AIM: To construct a min-max heap and perform the insert and delete operations in the heap. ALGORITHM: 1. Start the process. 2. The min-max heap must satisfy the heap property. array[n]<=array[2*n] and array[n]<=array[2*n+1] where n is the number of elements in the heap.
3. If array[i] is the first instance of the minimum, with array[j]>array[i]

for all j<I and i>=2,then min(heap) return heap array[1]. 4. The heap must be adjusted to fill heap array in order to remove the minimum element. 5. Move the hole from node i to either node 2i or 2i+1. 6. If array[2i]<array[2i+1] will be moved to array[i],leaving a hole at 2i,but after the move array[i]<array[2i+1],the heap invariant is maintained. 7. Just append the element to the array to do the insert operation. 8. If the element is a maximum value than the elements in the maximum level just swap this element in place of the maximum node. 9. If the element is a minimum value, then it is placed in the min level of the minmax heap. 10.Stop the program. SOURCE CODE: // minheap.java import java.io.*; class Node

{ private int iData; public Node(int key) { iData = key; } public int getKey() { return iData; } public void setKey(int id) { iData = id; } } class minHeap { private Node[] heapArray; private int maxSize; private int currentSize; public minHeap(int mx) { maxSize = mx; currentSize = 0; heapArray = new Node[maxSize]; } public boolean isEmpty() { return currentSize==0; } public boolean insert(int key) { if(currentSize==maxSize) return false; Node newNode = new Node(key);

heapArray[currentSize] = newNode; trickleUp(currentSize++); return true; } public void trickleUp(int index) { int parent = (index-1) / 2; Node bottom = heapArray[index]; while( index > 0 && heapArray[parent].getKey() > bottom.getKey() ) { heapArray[index] = heapArray[parent]; index = parent; parent = (parent-1) / 2; } heapArray[index] = bottom; } public Node remove() { Node root = heapArray[0]; heapArray[0] = heapArray[--currentSize]; trickleDown(0); return root; } public void trickleDown(int index) { int largerChild; Node top = heapArray[index];

while(index < currentSize/2) { int leftChild = 2*index+1; int rightChild = leftChild+1; if(rightChild < currentSize && heapArray[leftChild].getKey() >heapArray[rightChild].getKey()) largerChild = rightChild; else largerChild = leftChild; if( top.getKey() <= heapArray[largerChild].getKey() ) break; heapArray[index] = heapArray[largerChild]; index = largerChild; } heapArray[index] = top; } public void displayHeap() { System.out.print("heapArray: "); for(int m=0; m<currentSize; m++) if(heapArray[m] != null) System.out.print( heapArray[m].getKey() + " "); else System.out.print( "-- "); System.out.println(); int nBlanks = 32; int itemsPerRow = 1;

int column = 0; int j = 0; String dots = "..............................."; System.out.println(dots+dots); while(currentSize > 0) { if(column == 0) for(int k=0; k<nBlanks; k++) System.out.print(' '); System.out.print(heapArray[j].getKey()); if(++j == currentSize) break; if(++column==itemsPerRow) { nBlanks /= 2; itemsPerRow *= 2; column = 0; System.out.println(); } else for(int k=0; k<nBlanks*2-2; k++) System.out.print(' '); } System.out.println("\n"+dots+dots); } } class minHeapAp

{ public static void main(String[] args) throws IOException { int value, value2,choice=0; minHeap theHeap = new minHeap(31); boolean success; while(choice<4) { System.out.println("\t1.Show\n \t2.Insert\n \t3.Remove\n \t4.Exit"); System.out.println("\n Enter the choice"); choice = getInt(); switch(choice) { case 1: theHeap.displayHeap(); break; case 2: System.out.print("Enter value to insert: "); value = getInt(); success = theHeap.insert(value); if( !success ) System.out.println("Can't insert; heap full"); break; case 3: if( !theHeap.isEmpty() ) { theHeap.remove();

System.out.println("Root node has been deleted\n"); } else System.out.println("Can't remove; heap empty"); break; default: break; } } } public static int getInt() throws IOException { InputStreamReader isr = new InputStreamReader(System.in); BufferedReader br = new BufferedReader(isr); String s = br.readLine(); return Integer.parseInt(s); } }

OUTPUT:

RESULT: The program of Min Heap is successfully executed and verified. --------

Date: Ex No: 2 DESCRIPTION: DEAPS

AIM: Construct a Deap to perform the double ended priority queue operations of insert, delete min, delete max. ALGORITHM: 1. Start the process. 2. Using the template class initialize the constant element by specifying the key type. 3. Insert a variable x into the deap. 4. If n is equal to maxsize the deap is full and n is incremented.
5. If n is equal to 1 then d [2] = x this implies insertion into an empty deap. 6. Then P is given n+1 value. When P is the new last position of the deap. 7. There are two cases.if maxheap (p) is TRUE. Now P is a position in the

maxheap.
8. Then i is equated to minparter (p).if key in x is less than key in d[i].then

insert I, x in the maxpartner (p).

deap else insertp,x.

9. If maxheap (p) is FALSE.P is a position in the minheap.i is equated to

10.If the key of x is greater than of d[i] then maxinsert i and x.else mininsert P and x.

11.End the switch statement and end the insert. 12.Stop the process. SOURCE CODE: import java.io.*; public class Deap { int[] deap; int n = 1; public Deap(int maxSize) { deap = new int[maxSize]; } private boolean inMaxHeap(int i) { while (i > 3) { i /= 2; } if (i == 2) return false; return true; } private int maxPartner(int pos) { int offset = 1; int i = pos; while (i > 3) { i /= 2; offset *= 2; } if ((pos + offset) > n) return (pos+offset)/2;

return pos + offset; } private int minPartner(int pos) { int offset = 1; int i = pos; while (i > 3) { i /= 2; offset *= 2; } return pos - offset; } private void minInsert(int at, int key) { for (int parent; (parent = at / 2) != 1 && key < deap[parent]; deap[at] = deap[parent], at = parent) ; deap[at] = key; } private void maxInsert(int at, int key) { for (int parent; (parent = at / 2) != 1 && key > deap[parent]; deap[at] = deap[parent], at = parent) ; deap[at] = key; } public int deleteMax() { int i, j; int key; if (n >= 3) { // if more than 2 elements key = deap[3]; } else {

n--; return deap[2]; } int x = deap[n--]; // while i has child, move larger to i for (i = 3; 2*i <= n; deap[i] = deap[j], i = j) { j = i * 2; if (j+1 <= n) { if (deap[j] < deap[j+1]) { j++; } } } // try to put x at leaf i // find biggest at min partner j = minPartner(i); int biggest = j; if (2*j <= n) { biggest = 2*j; if (((2*j + 1) <= n) && (deap[2*j] < deap[2*j+1])) { biggest++; } } if (x < deap[biggest]) { // x can't put at i, must change with deap[biggest] deap[i] = deap[biggest]; minInsert(biggest, x);

} else { maxInsert(i, x); } return key; } public int deleteMin() { int i, j, key = deap[2], x = deap[n--]; // while i has child, move smaller to i for (i = 2; 2*i <= n; deap[i] = deap[j], i = j) { j = i * 2; if (j+1 <= n && deap[j] > deap[j+1]) { j++; } } // try to put x at leaf i j = maxPartner(i); if (x > deap[j]) { deap[i] = deap[j]; maxInsert(j, x); } else { minInsert(i, x); } return key; } public void insert(int x) { n++; if (n == deap.length) {

System.out.println("The heap is full"); System.exit(1); } if (n == 2) { deap[2] = x; return; } if (inMaxHeap(n)) { int i = minPartner(n); if (x < deap[i]) { deap[n] = deap[i]; minInsert(i, x); } else { maxInsert(n, x); } } else { int i = maxPartner(n); if (x > deap[i]) { deap[n] = deap[i]; maxInsert(i, x); } else { minInsert(n, x); } } } public static int getInt() throws IOException {

InputStreamReader isr = new InputStreamReader(System.in); BufferedReader br = new BufferedReader(isr); String s = br.readLine(); return Integer.parseInt(s); } public void print() { int levelNum = 2; int thisLevel = 0; int gap = 8; for (int i = 2; i <= n; i++) { for (int j = 0; j < gap-1; j++) { System.out.print(" "); } if (thisLevel != 0) { for (int j = 0; j < gap-1; j++) { System.out.print(" "); } } if (Integer.toString(deap[i]).length() == 1) { System.out.print(" "); } System.out.print(deap[i]); thisLevel++; if (thisLevel == levelNum) { System.out.println(); thisLevel = 0; levelNum *= 2;

gap/=2; } } System.out.println(); if (thisLevel != 0) { System.out.println(); } } public static void main(String[] argv)throws Exception { Deap a = new Deap(1024); int value; System.out.println("enter the number of elements"); value=getInt(); int[] data=new int[value]; //int[] data = {4,65,8,9,48,55,10,19,20,30,15,25,50}; for (int i = 0; i <value; i++) { System.out.println("Enter value "+i+""); data[i]=getInt(); } for (int i = 0; i < value; i++) { //System.out.println("Enter value "+i+""); a.insert(data[i]); } System.out.println("initial"); a.print(); System.out.println("delete Min"); a.deleteMin();

a.print(); System.out.println("delete Min"); a.deleteMin(); a.print(); System.out.println("delete Min"); a.deleteMin(); a.print(); System.out.println("delete Max"); a.deleteMax(); a.print(); System.out.println("delete Max"); a.deleteMax(); a.print(); System.out.println("delete Max"); a.deleteMax(); a.print(); }

OUTPUT:

RESULT: The program of Deaps is successfully executed and verified. Date:

Ex No: 3 DESCRIPTION:

LEFTLIST HEAP

A leftist heap is a heap-ordered binary tree which has a very special shape called a leftist tree. One of the nice properties of leftist heaps is that is possible to merge two leftist heaps efficiently. As a result, leftist heaps are suited for the implementation of mergeable priority queues. A leftist tree is a tree which tends to ``lean'' to the left. The tendency to lean to the left is defined in terms of the shortest path from the root to an external node. In a leftist tree, the shortest path to an external node is always found on the right. Every node in binary tree has associated with it a quantity called its null path length which is defined as follows: Definition (Null Path and Null Path Length) Consider an arbitrary node x in some binary tree T. The null path of node x is the shortest path in T from x to an external node of T. The null path length of node x is the length of its null path. Sometimes it is convenient to talk about the null path length of an entire tree rather than of a node: Definition (Null Path Length of a Tree) The null path length of an empty tree is zero and the null path length of a nonempty binary tree is the null path length its root R.

When a new node or sub tree is attached to a given tree, it is usually attached in place of an external node. Since the null path length of a tree is the length of the shortest path from the root of the tree to an external node, the null path length gives

a lower bound on the cost of insertion. For example, the running time for insertion in a binary search tree, A leftist tree is a tree in which the shortest path to an external node is always on the right. This informal idea is defined more precisely in terms of the null path lengths as follows: Definition (Leftist Tree): A leftist tree is a binary tree T with the following properties:
1. Either 2.

; or , where both and , are leftist trees which have null path respectively, such that

lengths

and

AIM:

ALGORITHM:

SOURCE CODE: import java.io.*; import java.util.Date; import java.util.Random; class Clock { static long now() // returns the current time in miliseconds { return (new Date()).getTime(); } } class IO { static int readInt() { String input = ""; try

{ input = (new BufferedReader( new InputStreamReader(System.in))).readLine(); } catch (java.io.IOException e) { System.out.println("Error while reading"); } return Integer.valueOf(input).intValue(); } } class Node { int key; int npl; Node right; Node left; public Node(int key, Node left, Node right) { this.key = key; this.right = right; this.left = left; } public Node(int key) { this(key, null, null); }

static Node merge(Node u, Node v) { // Assure that the key of u is smallest if (u.key > v.key) { Node dummy = u; u = v; v = dummy; } if (u.right == null) // Hook v directly to u u.right = v; else // Merge recursively u.right = merge(u.right, v); // Conditionally swap children of u if (u.left == null || u.right.npl > u.left.npl) { Node dummy = u.right; u.right = u.left; u.left = dummy; } // Update npl values if (u.right == null) u.npl = 0; else u.npl = min(u.left.npl, u.right.npl) + 1; return u; } static int min(int x, int y) { if (x <= y) return x;

return y; } boolean test_heap() { if (right == null && left == null) return true; if (left == null) return key <= right.key && right.test_heap(); if (right == null) return key <= left.key && left.test_heap(); return key <= min(right.key, left.key) && left.test_heap() && right.test_heap(); } boolean test_npl() { if (right == null || left == null) return npl == 0; return npl == min(left.npl, right.npl) + 1 && left.test_npl() && right.test_npl(); } boolean test_leftist() { if (right == null) return true; if (left == null) return false; return right.npl <= left.npl &&

left.test_leftist() && right.test_leftist(); } void test() { if (test_heap()) System.out.println("Heap property else System.out.println("Heap property if (test_npl()) System.out.println("npl values else System.out.println("npl values if (test_leftist()) System.out.println("Leftist property else System.out.println("Leftist property NOT ok !!!"); } void print(int d) { System.out.println("depth == " + d + ", key == " + key); if (left != null) { System.out.print("Left: "); left.print(d + 1); } if (right != null) { ok"); NOT ok !!!"); ok"); NOT ok !!!"); ok");

System.out.print("Right: "); right.print(d + 1); } } } class LeftistHeap { Node root; public LeftistHeap() { root = null; } public void insert(int key) { if (root == null) root = new Node(key); else root = Node.merge(root, new Node(key)); } public int deleteMin() { if (root == null) { System.out.println("EMPTY HEAP !!!"); return Integer.MAX_VALUE; }

else { int x = root.key; if (root.right == null) // Also covers case of single node root = root.left; else root = Node.merge(root.left, root.right); return x; } } void test() { if (root == null) System.out.println("Empty heap, trivially ok"); else root.test(); } void print() { if (root == null) System.out.println("\nEmpty tree"); else { System.out.println("\nPRINTING ALL NODES:"); System.out.print("Root: "); root.print(0); }

System.out.println(); } } public class LeftistHeapTest { public static void main(String[] args) { System.out.println(); LeftistHeap heap = new LeftistHeap(); System.out.print("Step by step test? (yes = 1) >>> "); if (IO.readInt() == 1) { int c = 0; while (c != 5) { System.out.print("Give operation (inst=1, dlmn=2 test=3 prnt=4 stop=5) >>> "); c = IO.readInt(); if { System.out.print("Give key to insert >>> "); heap.insert(IO.readInt()); } else if (c == 2) System.out.println("Deletemin returns " + heap.deleteMin()); else if (c == 3) heap.test(); (c == 1)

else if (c == 4) heap.print(); } } else // Bulk test { System.out.print("Give n >>> "); int n = IO.readInt(); Random random = new Random(Clock.now()); long t = - Clock.now(); for (int i = 0; i < n; i++) heap.insert(random.nextInt()); t += Clock.now(); if (n <= 100) heap.print(); heap.test(); System.out.println(n + " inserts took " + t + " milliseconds"); t = - Clock.now(); for (int i = 0; i < n; i++) heap.deleteMin(); t += Clock.now(); System.out.println(n + " deletemins took " + t + " milliseconds"); } System.out.println(); } } OUTPUT:

RESULT: The program of Leftlist Heap is successfully executed and verified. -------Date:

Ex No: 4 DESCRIPTION:

AVL TREE

In computer science, an AVL tree is a self-balancing binary search tree, and it is the first such data structure to be invented. In an AVL tree, the heights of the two child sub trees of any node differ by at most one; therefore, it is also said to be height-balanced. Lookup, insertion, and deletion all take O(log n) time in both the average and worst cases, where n is the number of nodes in the tree prior to the operation. Insertions and deletions may require the tree to be rebalanced by one or more tree rotation. The balance factor of a node is the height of its left sub tree minus the height of its right sub tree, and a node with balance factor 1, 0, or -1 is considered balanced. A node with any other balance factor is considered unbalanced and requires rebalancing the tree. The balance factor is either stored directly at each node or computed from the heights of the sub trees. The basic operations of an AVL tree generally involve carrying out the same actions as would be carried out on an unbalanced binary search tree, but modifications are preceded or followed by one or more operations called tree rotations, which help to restore the height balance of the sub trees AVL trees are often compared with red-black trees because they support the same set of operations and because red-black trees also take O (log n) time for the basic operations. AVL trees perform better than red-black trees for lookupintensive applications. The AVL tree balancing algorithm appears in many computer science curricula. After inserting a node, it is necessary to check each of the node's ancestors for consistency with the rules of AVL. For each node checked, if the balance factor remains -1, 0, or 1 then no rotations are necessary. However, if the balance factor

becomes 2 or -2 then the sub tree rooted at this node is unbalanced. If insertions are performed serially, after each insertion, at most two tree rotations are needed to restore the entire tree to the rules of AVL. There are four cases which need to be considered, of which two are symmetric to the other two. Let P be the root of the unbalanced sub tree. Let R be the right child of P. Let L be the left child of P. Right-Right case and Right-Left case: If the balance factor of P is -2, then the right sub tree outweighs the left sub tree of the given node, and the balance factor of the right child (R) must be checked. If the balance factor of R is -1, a left rotation is needed with P as the root. If the balance factor of R is +1, a double left rotation is needed. The first rotation is a right rotation with R as the root. The second is a left rotation with P as the root. Left-Left case and Left-Right case: If the balance factor of P is +2, then the left sub tree outweighs the right sub tree of the given node, and the balance factor of the left child (L) must then checked. If the balance factor of L is +1, a right rotation is needed with P as the root. If the balance factor of L is -1, a double right rotation is needed. The first rotation is a left rotation with L as the root. The second is a right rotation with P as the root. Deletion If the node is a leaf, remove it. If the node is not a leaf, replace it with either the largest in its left sub tree (in order predecessor) or the smallest in its right sub tree (in order successor), and remove that node. The node that was found as

replacement has at most one sub tree. After deletion, retrace the path back up the tree (parent of the replacement) to the root, adjusting the balance factors as needed. As with all binary trees, a node's in-order successor is the left-most child of its right sub tree, and a node's in-order predecessor is the right-most child of its left sub tree. In either case, this node will have zero or one children. Delete it according to one of the two simpler cases above. In addition to the balancing described above for insertions, if the balance factor for the tree is 2 and that of the right sub tree is 0, a left rotation must be performed on P. The mirror of this case is also necessary. The retracing can stop if the balance factor becomes -1 or 1 indicating that the height of that sub tree has remained unchanged. If the balance factor becomes 0 then the height of the sub tree has decreased by one and the retracing needs to continue. If the balance factor becomes -2 or 2 then the sub tree is unbalanced and needs to be rotated to fix it. If the rotation leaves the sub trees balance factor at 0 then the retracing towards the root must continue since the height of this sub tree has decreased by one. This is in contrast to an insertion where a rotation resulting in a balance factor of 0 indicated that the sub trees height has remained unchanged. The time required is O (log n) for lookup, plus a maximum of O (log n) rotations on the way back to the root, so the operation can be completed in O (log n) time. Lookup Lookup in an AVL tree is performed exactly as in an unbalanced binary search tree. Because of the height-balancing of the tree, a lookup takes O(log n) time. No special provisions need to be taken, and the tree's structure is not modified by lookups. (This is in contrast to splay tree lookups, which do modify their tree's structure.)

If each node additionally records the size of its sub tree (including itself and its descendants), then the nodes can be retrieved by index in O (log n) time as well. Once a node has been found in a balanced tree, the next or previous node can be obtained in amortized constant time. (In a few cases, about 2*log (n) links will need to be traversed. In most cases, only a single link needs to be traversed. On average, about two links need to be traversed.)

AIM: ALGORITHM:

1. Start the program.


2. Create a class NODE, containing an element and two self referential pointers

LEFT_CHILD and RIGHT_CHILD. 3. Create a class AVL, containing an ROOT of class NODE and also define the ADT operations to be performed on AVL tree.
4. To INSERT an element in the AVL tree, start comparing from root node

then traverse either left or right sub tree. Find the exact position and place the element.
5. After any changes in AVL tree, the balance factor is calculate should be any

Of (-1, 0, 1).If the tree is not balanced then do the any of these rotations. (LL Rotations, RR rotation, LR rotation, RL rotation). 6. Similarly, during DELETION operation, delete the element if found in the tree, Then again calculate balance factor and do necessary operations. If given element not found in tree, give the error message. 7. To DISPLAY, contents of AVL tree, use INORDER traversal by using recursion function then display the elements. 8. Stop the program. SOURCE CODE: package s.avl; import java.util.Collection; import java.util.Iterator; import java.util.LinkedList; import java.util.List; import java.util.NoSuchElementException; import java.util.Set; public class AVLTree implements Tree

{ private Node root; private int size = 0; private boolean removed = false; private boolean iterator = false; private boolean contains = false; private final int THREE = 3; private final int TWO = 2; private final int ONE = 1; private final int ZERO = 0; public boolean add(Object e) { if(e == null) throw new IllegalArgumentException(); if(iterator) return false; if(contains(e)) return false; root = add(new Node(e), root); size++; return true; } private Node add(Node newNode, Node currentNode) { if(currentNode == null) {

currentNode = newNode; return currentNode; } else if ((Comparable) newNode.element).compareTo (Comparable) currentNode. element) < 0 ) { currentNode.left = add(newNode, currentNode.left); } else { currentNode.right = add(newNode, currentNode.right); } // This could be trying to insert something equal! currentNode = balance(currentNode); //currentNode = balance (currentNode); updateHeight(currentNode); return currentNode; } public boolean contains(Object element) { contains = false; contains(new Node(element), root); return contains; } private void contains(Node lookFor, Node currentNode) {

if(currentNode == null) return; //System.out.println(currentNode.element + " lf: " + lookFor.element); //System.out.println(((Comparable)lookFor.element).compareTo( (Co mparable) currentNode.element)); If (((Comparable)currentNode.element).compareTo( (Comparable)lookFor.element )0) { contains = true; return; } else if (((Comparable)lookFor.element).compareTo( (Comparable) currentNode.element ) < 0 ) { contains(lookFor, currentNode.left); } else { contains(lookFor, currentNode.right); } return; } public boolean remove(Object element) { if(element == null) throw new IllegalArgumentException(); removed = false;

root = remove(new Node(element), root); size--; return removed; } private Node balance(Node n) { int leftHeight = getHeight(n.left); int rightHeight = getHeight(n.right); int difference = Math.abs(leftHeight - rightHeight); if(difference > 1) { if(leftHeight > rightHeight) { if(getHeight(n.left.left) < getHeight(n.left.right)) { Node temp = n.left.right; System.out.println("Double rotate left right"); rotateLeft(n.left); rotateRight(n); return temp; } else { Node temp = n.left; System.out.println("Single rotate right"); rotateRight(n); return temp;

} } else if(leftHeight < rightHeight) { if(getHeight(n.right.right) < getHeight(n.right.left)) { Node temp = n.right.left; System.out.println("Double rotate right left"); rotateRight(n.right); rotateLeft(n); return temp; } else { Node temp = n.right; System.out.println("Single rotate left"); rotateLeft(n); return temp; } } } return n; } private void rotateRight(Node n) { System.out.println("Rotating " + n.element); Node temp = n.left;

n.left = temp.right; temp.right = n; updateHeight(n); updateHeight(temp); } private void rotateLeft(Node n) { System.out.println("Rotating " + n.element); Node tempNode = n.right; Node temp = n.right; n.right = temp.left; temp.left = n; updateHeight(n); updateHeight(temp); } private void updateHeight(Node n) { if(n.left == null && n.right == null) n.height = 0; else if(getHeight(n.left) >= getHeight(n.right)) n.height = getHeight(n.left) + 1; else n.height = getHeight(n.right) + 1; } private Node findMin(Node n) { if(n.left != null)

n = findMin(n.left); return n; } private Node findMax(Node n) { if(n.right != null) n = findMin(n.right); return n; } public void clear() { root = null; size = 0; } public boolean isEmpty() { if(root == null) return true; return false; } public Iterator iterator() { iterator = true; return new NodeIterator(); } public int size() {

return size; } public Object[] toArray() { NodeIterator i = new NodeIterator(); Object[] elements = new Object[i.size()]; int index = 0; while(i.hasNext()) elements[index++] = i.next(); return elements; } private int getHeight(Node n) { if(n == null) return -1; return n.height; } private class Node implements BinaryTreeNode { private Node left = null; private Node right = null; private Node parent = null; private int height = 0; private Object element; public Node(Object e) { element = e;

} public Object getData() { return this.element; } public int getHeight() { return this.height; } public BinaryTreeNode getLeftChild() { return this.left; } public BinaryTreeNode getRightChild() { return this.right; } } private class NodeIterator implements Iterator<Node> { private int numElements = 0; private int currentIndex = 0; private List<Node> elements = new LinkedList<Node>(); public NodeIterator() { numElements = preorder(root); }

public boolean hasNext() { if(numElements > currentIndex) return true; iterator = false; return false; } public Node next() { if(hasNext()) return elements.get(currentIndex++); throw new NoSuchElementException(); } private int preorder(Node n) { numElements++; elements.add(n); if(n.left != null) preorder(n.left); if(n.right != null) preorder(n.right); return numElements; } public int size() { return numElements; }

public void remove() { throw new UnsupportedOperationException(); } } public BinaryTreeNode getRootNode() { return (BinaryTreeNode)root; }

OUTPUT:

RESULT: The program of AVL Tree is successfully executed and verified. -------Date: Ex No: 5 B TREE

DESCRIPTION: Tree structures support various basic dynamic set operations including Search, Predecessor, Successor, Minimum, Maximum, Insert, and Delete in time proportional to the height of the tree. Ideally, a tree will be balanced and the height will be log n where n is the number of nodes in the tree. To ensure that the height of the tree is as small as possible and therefore provide the best running time, a balanced tree structure like a red-black tree, AVL tree, or b-tree must be used. When working with large sets of data, it is often not possible or desirable to maintain the entire structure in primary storage (RAM). Instead, a relatively small portion of the data structure is maintained in primary storage, and additional data is read from secondary storage as needed. Unfortunately, a magnetic disk, the most common form of secondary storage, is significantly slower than random access memory (RAM). In fact, the system often spends more time retrieving data than actually processing data. B-trees are balanced trees that are optimized for situations when part or all of the tree must be maintained in secondary storage such as a magnetic disk. Since disk accesses are expensive (time consuming) operations, a b-tree tries to minimize the number of disk accesses. For example, a b-tree with a height of 2 and a branching factor of 1001 can store over one billion keys but requires at most two disk accesses to search for any node The Structure of B-Trees Unlike a binary-tree, each node of a b-tree may have a variable number of keys and children. The keys are stored in non-decreasing order. Each key has an associated child that is the root of a sub tree containing all nodes with keys less than or equal to the key but greater than the preceeding key. A node also has an

additional rightmost child that is the root for a sub tree containing all keys greater than any keys in the node. A B tree has a minimum number of allowable children for each node known as the minimization factor. If t is this minimization factor, every node must have at least t - 1 keys. Under certain circumstances, the root node is allowed to violate this property by having fewer than t - 1 keys. Every node may have at most 2t - 1 keys or, equivalently, 2t children. Since each node tends to have a large branching factor (a large number of children), it is typically necessary to traverse relatively few nodes before locating the desired key. If access to each node requires a disk access, then a b-tree will minimize the number of disk accesses required. The minimzation factor is usually chosen so that the total size of each node corresponds to a multiple of the block size of the underlying storage device. This choice simplifies and optimizes disk access. Consequently, a b-tree is an ideal data structure for situations where all data cannot reside in primary storage and accesses to secondary storage are comparatively expensive (or time consuming). Height of B-Trees For n greater than or equal to one, the height of an n-key b-tree T of height h with a minimum degree t greater than or equal to 2,

For a proof of the above inequality, refer to Cormen, Leiserson, and Rivest pages 383-384. The worst case height is O(log n). Since the "branchiness" of a b-tree can be large compared to many other balanced tree structures, the base of the logarithm tends to

be large; therefore, the number of nodes visited during a search tends to be smaller than required by other tree structures. Although this does not affect the asymptotic worst case height, b-trees tend to have smaller heights than other trees with the same asymptotic height. Operations on B-Trees The algorithms for the search, create, and insert operations are shown below. Note that these algorithms are single pass; in other words, they do not traverse back up the tree. Since b-trees strive to minimize disk accesses and the nodes are usually stored on disk, this single-pass approach will reduce the number of node visits and thus the number of disk accesses. Simpler double-pass approaches that move back up the tree to fix violations are possible. Since all nodes are assumed to be stored in secondary storage (disk) rather than primary storage (memory), all references to a given node be be preceeded by a read operation denoted by Disk-Read. Similarly, once a node is modified and it is no longer needed, it must be written out to secondary storage with a write operation denoted by Disk-Write. The algorithms below assume that all nodes referenced in parameters have already had a corresponding Disk-Read operation. New nodes are created and assigned storage with the Allocate-Node call. The implementation details of the Disk-Read, Disk-Write, and Allocate-Node functions are operating system and implementation dependent. B-Tree-Search(x, k) i <- 1 while i <= n[x] and k > keyi[x] do i <- i + 1 if i <= n[x] and k = keyi[x]

then return (x, i) if leaf[x] then return NIL else Disk-Read(ci[x]) return B-Tree-Search(ci[x], k) The search operation on a b-tree is analogous to a search on a binary tree. Instead of choosing between a left and a right child as in a binary tree, a b-tree search must make an n-way choice. The correct child is chosen by performing a linear search of the values in the node. After finding the value greater than or equal to the desired value, the child pointer to the immediate left of that value is followed. If all values are less than the desired value, the rightmost child pointer is followed. Of course, the search can be terminated as soon as the desired node is found. Since the running time of the search operation depends upon the height of the tree, B-Tree-Search is O(logt n). B-Tree-Create(T) x <- Allocate-Node() leaf[x] <- TRUE n[x] <- 0 Disk-Write(x) root[T] <- x The B-Tree-Create operation creates an empty b-tree by allocating a new root node that has no keys and is a leaf node. Only the root node is permitted to have these properties; all other nodes must meet the criteria outlined previously. The B-TreeCreate operation runs in time O(1).

B-Tree-Split-Child(x, i, y) z <- Allocate-Node() leaf[z] <- leaf[y] n[z] <- t - 1 for j <- 1 to t - 1 do keyj[z] <- keyj+t[y] if not leaf[y] then for j <- 1 to t do cj[z] <- cj+t[y] n[y] <- t - 1 for j <- n[x] + 1 downto i + 1 do cj+1[x] <- cj[x] ci+1 <- z for j <- n[x] downto i do keyj+1[x] <- keyj[x] keyi[x] <- keyt[y] n[x] <- n[x] + 1 Disk-Write(y) Disk-Write(z) Disk-Write(x) If is node becomes "too full," it is necessary to perform a split operation. The split operation moves the median key of node x into its parent y where x is the ith child of y. A new node, z, is allocated, and all keys in x right of the median key are moved to z. The keys left of the median key remain in the original node x. The new node, z, becomes the child immediately to the right of the median key that was

moved to the parent y, and the original node, x, becomes the child immediately to the left of the median key that was moved into the parent y. The split operation transforms a full node with 2t - 1 keys into two nodes with t - 1 keys each. Note that one key is moved into the parent node. The B-Tree-SplitChild algorithm will run in time O(t) where t is constant. B-Tree-Insert(T, k) r <- root[T] if n[r] = 2t - 1 then s <- Allocate-Node() root[T] <- s leaf[s] <- FALSE n[s] <- 0 c1 <- r B-Tree-Split-Child(s, 1, r) B-Tree-Insert-Nonfull(s, k) else B-Tree-Insert-Nonfull(r, k) B-Tree-Insert-Nonfull(x, k) i <- n[x] if leaf[x] then while i >= 1 and k < keyi[x] do keyi+1[x] <- keyi[x] i <- i - 1 keyi+1[x] <- k n[x] <- n[x] + 1 Disk-Write(x)

else while i >= and k < keyi[x] do i <- i - 1 i <- i + 1 Disk-Read(ci[x]) if n[ci[x]] = 2t - 1 then B-Tree-Split-Child(x, i, ci[x]) if k > keyi[x] then i <- i + 1 B-Tree-Insert-Nonfull(ci[x], k) To perform an insertion on a b-tree, the appropriate node for the key must be located using an algorithm similiar to B-Tree-Search. Next, the key must be inserted into the node. If the node is not full prior to the insertion, no special action is required; however, if the node is full, the node must be split to make room for the new key. Since splitting the node results in moving one key to the parent node, the parent node must not be full or another split operation is required. This process may repeat all the way up to the root and may require splitting the root node. This approach requires two passes. The first pass locates the node where the key should be inserted; the second pass performs any required splits on the ancestor nodes. Since each access to a node may correspond to a costly disk access, it is desirable to avoid the second pass by ensuring that the parent node is never full. To accomplish this, the presented algorithm splits any full nodes encountered while descending the tree. Although this approach may result in unecessary split operations, it guarantees that the parent never needs to be split and eliminates the need for a second pass up the tree. Since a split runs in linear time, it has little effect on the O(t logt n) running time of B-Tree-Insert.

Splitting the root node is handled as a special case since a new root must be created to contain the median key of the old root. Observe that a b-tree will grow from the top. B-Tree-Delete Deletion of a key from a b-tree is possible; however, special care must be taken to ensure that the properties of a b-tree are maintained. Several cases must be considered. If the deletion reduces the number of keys in a node below the minimum degree of the tree, this violation must be corrected by combining several nodes and possibly reducing the height of the tree. If the key has children, the children must be rearranged. AIM:

ALGORITHM: 1. Start the program 2. Create a class NODE, containing an element and two self referential pointers LEFT_CHILD and RIGHT_CHILD. 3. Create a class BST, containing a ROOT of the class NODE and also define the ADT operations to be performed on the Binary Search Tree. 4. To INSERT an element, get the element from the user and then compare the element with root then travel either left or right sub tree. 5. Repeat the step 4, to find the position of the element and then insert the element in the Tree at appropriate position. 6. To DELETE an element from the tree, get the element from the user then traverse along the tree.

7. If the given element is found, then delete the given element also place its sub tree at appropriate node in the tree. Otherwise, display error message Given element is not found. 8. To FIND an element in the tree, start from root node, if the given element is lesser than root node, traverse along left sub tree, and otherwise traverse along right sub tree and so on. If the given element is found, return the element otherwise return NULL. 9. To display contents of Binary Search Tree, use INORDER traversal by using recursion function the display the elements. 10.Stop the program. SOURCE CODE: package org.javaldap.btree; /****************************************************************** import java.lang.*; import java.util.Enumeration; import org.javaldap.server.syntax.*; /** * Main Class BTree * For creating a fully BTree with all Methods and Attributs **/ public class BTree { int order; BTNode root; /** * Constructor

* creates the root of a btree */ public BTree(int order) { this.order=order; root=new BTNode(order, null); } public boolean containsKey(String key) { if (get(key) != null) return true; return false; } public boolean containsKey(DirectoryString ds) { if (get(ds) != null) return true; return false; } /* * main delet methode * for recursiv coding */ KeyNode deleteNode(BTNode btnode, Comparator key) { // get information needed SearchResult tmpResult = searchObj(btnode, key); BTNode delBTNode = tmpResult.getBTNode(); if (delBTNode == null) { return null; } int keyIndex = tmpResult.getKeyIndex(); KeyNode returnNode = delBTNode.getKeyNode(keyIndex);

// is a leaf ********************************** if (delBTNode.isLeaf) { if (delBTNode.nKey > order - 1) // we can delete KeyNode directly { delBTNode.extractKeyNode(keyIndex); } else // we need to get more keys so that we can delete it { BTNode parentBTNode = delBTNode.parent; int parentIndex = 0; while (parentBTNode.getBTNode(parentIndex) != delBTNode) parentIndex++; if (parentIndex == parentBTNode.nKey) { BTNode leftBTNode = parentBTNode.getBTNode(parentIndex - 1); if (leftBTNode.nKey > order - 1) { delBTNode.kArray[keyIndex]= parentBTNode.getKeyNode(parentIndex); parentBTNode.kArray[parentIndex] = leftBTNode.getKeyNode(leftBTNode.nKey - 1); deleteNode(leftBTNode, 1).getKey()); } else { delBTNode.mergeWithBTNode(); } } else { leftBTNode.getKeyNode(leftBTNode.nKey -

BTNode rightBTNode = parentBTNode.getBTNode(parentIndex + 1); if (rightBTNode.nKey > order - 1) { delBTNode.kArray[keyIndex] = parentBTNode.getKeyNode(parentIndex); parentBTNode.kArray[parentIndex] = rightBTNode.getKeyNode(0); deleteNode(rightBTNode, rightBTNode.getKeyNode(0).getKey()); } else { delBTNode.mergeWithBTNode(); } } } } else // is internal node ********************* { //try predecesor // get the node to exchange and delete it at leaf position BTNode preBTNode = delBTNode.getBTNode(keyIndex); while (!preBTNode.isLeaf) { preBTNode = preBTNode.getBTNode(preBTNode.nKey); } // swap nodes KeyNode tmpKeyNode = preBTNode.getKeyNode(preBTNode.nKey - 1); preBTNode.kArray[preBTNode.nKey - 1] = delBTNode.kArray[keyIndex]; delBTNode.kArray[keyIndex] = tmpKeyNode; deleteNode(preBTNode, 1).getKey()); } return returnNode; preBTNode.getKeyNode(preBTNode.nKey -

} /** * deletes the object stored with the given key **/ public KeyNode deleteObj(Comparator key) { return deleteNode(root, key); } public Object get(Long key) { return getKeyObject(new LongComparator(key)); } public Object get(String key) { return getKeyObject(new StringComparator(key)); } public Object get(DirectoryString key) { return getKeyObject(new DirectoryStringComparator(key)); } /** * returns the object stored behind the given key */ public Object getKeyObject(Comparator key) { SearchResult result=searchObj(root, key); if(result.getBTNode()==null) return null; else return (result.getBTNode().getKeyNode(result.getKeyIndex())).getObj(); } /**

* insert a object with the given key into the tree */ public void insertObj(Comparator key, Object data) { KeyNode keyNode = new KeyNode(key, data); BTNode btNode = root; while (!btNode.isLeaf) { int i=0; while(keyNode.getKey().compareTo(btNode.kArray[i].getKey()) > 0) { i++; if (i == btNode.nKey) break; } btNode = btNode.btnArray[i]; } btNode.insert(keyNode); if (root.nKey == order*2-1) root.split(); } public Enumeration keys() { return new BTreeEnumeration(this,true); } public void put(Long key, Object val) { insertObj(new LongComparator(key),val); } public void put(String key, Object val) { insertObj(new StringComparator(key),val); } public void put(DirectoryString key, Object val) { insertObj(new DirectoryStringComparator(key),val);

} public void remove(String key) { deleteObj(new StringComparator(key)); } public void remove(DirectoryString key) { deleteObj(new DirectoryStringComparator(key)); } /* * returns null in the btnode part and -1 in the keyIndex * if the specified key doesn't exist */ SearchResult searchObj(BTNode btnode, Comparator key) { SearchResult resultObj=new SearchResult(null, -1); int i=0; boolean keyNotInNode=false; boolean keyFound=false; while(!keyNotInNode && !keyFound) { if(btnode.getKeyNode(i) != null && key.compareTo(btnode.getKeyNode(i).getKey())<0) { keyNotInNode=true; if(!btnode.isLeaf) resultObj=searchObj(btnode.getBTNode(i), key); } else if(btnode.getKeyNode(i) keyFound=true; resultObj=new SearchResult(btnode, i);//key found != null && key.compareTo(btnode.getKeyNode(i).getKey())==0) {

} else if(i<(btnode.nKey-1))i++; else if(btnode.getKeyNode(i) keyNotInNode=true; if(!btnode.isLeaf) resultObj=searchObj(btnode.getBTNode(i+1), key); } else keyNotInNode=true; } return resultObj; } public Enumeration values() { return new BTreeEnumeration(this,false); } } != null && key.compareTo(btnode.getKeyNode(i).getKey())>0) {

OUTPUT:

RESULT: The program of B Tree is successfully executed and verified. --------

Date: Ex No: 6 DESCRIPTION: A heap is an efficient semi-ordered data structure for storing a collection of orderable data. The term binary heap and heap are interchangeable in most cases. A heap can be thought of as a tree with parent and child. The main difference between a heap and a binary tree is the heap property. In order for a data structure to be considered a heap, it must satisfy the following condition (heap property): If A and B are elements in the heap and B is a child of A, then key(A) key(B). (This property applies for a min-heap. A max heap would have the comparison reversed). What this tells us is that the minimum key will always remain at the top and greater values will be below it. Due to this fact, heaps are used to implement priority queues which allows quick access to the item with the most priority. Here's an example of a min-heap: TRIES

A heap is implemented using an array that is indexed from 1 to N, where N is the number of elements in the heap. At any time, the heap must satisfy the heap property array[n] <= array[2*n] and array[n] <= array[2*n+1] whenever the indices are in the arrays bounds. The operations commonly performed with a heap are

delete-max or delete-min: removing the root node of a max- or min-heap, respectively increase-key or decrease-key: updating a key within a max- or min-heap, respectively insert: adding a new key to the heap merge: joining two heaps to form a valid new heap containing all the elements of both.

Compute the extreme value We will prove that array[1] is the minimum element in the heap. We prove it by seeing a contradiction if some other element is less than the first element. Suppose array[i] is the first instance of the minimum, with array[j] > array[i] for all j < i,

and

. But by the heap invariant array, array[floor(i / 2)] < = array[i]: this is a

contradiction. Therefore, it is easy to compute MIN(heap): MIN(heap) return heap.array[1]; Removing the Extreme Value To remove the minimum element, we must adjust the heap to fill heap.array[1]. This process is called percolation. Basically, we move the hole from node i to either node 2i or 2i + 1. If we pick the minimum of these two, the heap invariant will be maintained; suppose array[2i] < array[2i + 1]. Then array[2i] will be moved to array[i], leaving a hole at 2i, but after the move array[i] < array[2i + 1], so the heap invariant is maintained. In some cases, 2i + 1 will exceed the array bounds, and we are forced to percolate 2i. In other cases, 2i is also outside the bounds: in that case, we are done. Therefore, here is the remove algorithm: #define LEFT(i) (2*i) #define RIGHT(i) (2*i + 1) REMOVE_MIN(heap) { savemin=arr[0]; arr[0]=arr[--heapsize]; i=0; while(i<heapsize){ minidx=i; if(LEFT(i)<heapsize && arr[LEFT(i)] < arr[i])

minidx=LEFT(i); if(RIGHT(i)<heapsize && arr[RIGHT(i)] < arr[minidx]) minidx=RIGHT(i); if(mindx!=i){ swap(arr[i],arr[minidx]); i=minidx; } else break; } } Inserting a value into the heap A similar strategy exists for INSERT: just append the element to the array, then fixup the heap-invariants by swapping. For example if we just appended element N, then the only invariant violation possible involves that element, in particular if array[floor(N / 2)] > array[N], then those two elements must be swapped and now the only invariant violation possible is between array[floor(N/4)] and array[floor(N/2)] we continue iterating until N=1 or until the invariant is satisfied. INSERT(heap, element) append(heap.array, element) i = heap.array.length while (i > 1) { if (heap.array[i/2] <= heap.array[i]) break;

swap(heap.array[i/2], heap.array[i]); i /= 2; }

AIM: To construct a min-max heap and perform the insert and delete operations in the heap. ALGORITHM: 11.Start the process. 12.The min-max heap must satisfy the heap property. array[n]<=array[2*n] and array[n]<=array[2*n+1] where n is the number of elements in the heap. 13.If array[i] is the first instance of the minimum, with array[j]>array[i] for all j<I and i>=2,then min(heap) return heap array[1]. 14.The heap must be adjusted to fill heap array in order to remove the minimum element. 15.Move the hole from node i to either node 2i or 2i+1. 16.If array[2i]<array[2i+1] will be moved to array[i],leaving a hole at 2i,but after the move array[i]<array[2i+1],the heap invariant is maintained. 17.Just append the element to the array to do the insert operation. 18.If the element is a maximum value than the elements in the maximum level just swap this element in place of the maximum node.

19.If the element is a minimum value, then it is placed in the min level of the minmax heap. 20.Stop the program. SOURCE CODE: // minheap.java import java.io.*; class Node { private int iData; public Node(int key) { iData = key; } public int getKey() { return iData; } public void setKey(int id) { iData = id; } } class minHeap { private Node[] heapArray; private int maxSize; private int currentSize; public minHeap(int mx) { maxSize = mx; currentSize = 0; heapArray = new Node[maxSize];

} public boolean isEmpty() { return currentSize==0; } public boolean insert(int key) { if(currentSize==maxSize) return false; Node newNode = new Node(key); heapArray[currentSize] = newNode; trickleUp(currentSize++); return true; } public void trickleUp(int index) { int parent = (index-1) / 2; Node bottom = heapArray[index]; while( index > 0 && heapArray[parent].getKey() > bottom.getKey() ) { heapArray[index] = heapArray[parent]; index = parent; parent = (parent-1) / 2; } heapArray[index] = bottom; } public Node remove() { Node root = heapArray[0];

heapArray[0] = heapArray[--currentSize]; trickleDown(0); return root; } public void trickleDown(int index) { int largerChild; Node top = heapArray[index]; while(index < currentSize/2) { int leftChild = 2*index+1; int rightChild = leftChild+1; if(rightChild < currentSize && heapArray[leftChild].getKey() >heapArray[rightChild].getKey()) largerChild = rightChild; else largerChild = leftChild; if( top.getKey() <= heapArray[largerChild].getKey() ) break; heapArray[index] = heapArray[largerChild]; index = largerChild; } heapArray[index] = top; } public void displayHeap() { System.out.print("heapArray: ");

for(int m=0; m<currentSize; m++) if(heapArray[m] != null) System.out.print( heapArray[m].getKey() + " "); else System.out.print( "-- "); System.out.println(); int nBlanks = 32; int itemsPerRow = 1; int column = 0; int j = 0; String dots = "..............................."; System.out.println(dots+dots); while(currentSize > 0) { if(column == 0) for(int k=0; k<nBlanks; k++) System.out.print(' '); System.out.print(heapArray[j].getKey()); if(++j == currentSize) break; if(++column==itemsPerRow) { nBlanks /= 2; itemsPerRow *= 2; column = 0; System.out.println(); }

else for(int k=0; k<nBlanks*2-2; k++) System.out.print(' '); } System.out.println("\n"+dots+dots); } } class minHeapAp { public static void main(String[] args) throws IOException { int value, value2,choice=0; minHeap theHeap = new minHeap(31); boolean success; while(choice<4) { System.out.println("\t1.Show\n \t2.Insert\n \t3.Remove\n \t4.Exit"); System.out.println("\n Enter the choice"); choice = getInt(); switch(choice) { case 1: theHeap.displayHeap(); break; case 2: System.out.print("Enter value to insert: "); value = getInt();

success = theHeap.insert(value); if( !success ) System.out.println("Can't insert; heap full"); break; case 3: if( !theHeap.isEmpty() ) { theHeap.remove(); System.out.println("Root node has been deleted\n"); } else System.out.println("Can't remove; heap empty"); break; default: break; } } } public static int getInt() throws IOException { InputStreamReader isr = new InputStreamReader(System.in); BufferedReader br = new BufferedReader(isr); String s = br.readLine(); return Integer.parseInt(s); } }

OUTPUT:

RESULT:

The program of Tries is successfully executed and verified. --------

Date: Ex No: 7 DESCRIPTION: Quick sort is a fast sorting algorithm, which is used not only for educational purposes, but widely applied in practice. On the average, it has O(n log n) complexity, making quick sort suitable for sorting big data volumes. The idea of the algorithm is quite simple and once you realize it, you can write quick sort as fast as bubble sort. The divide-and-conquer strategy is used in quick sort. Below the recursion step is described:
1. Choose a pivot value. We take the value of the middle element as pivot

QUICK SORT

value, but it can be any value, which is in range of sorted values, even if it doesn't present in the array.
2. Partition. Rearrange elements in such a way, that all elements which are

lesser than the pivot go to the left part of the array and all elements greater than the pivot, go to the right part of the array. Values equal to the pivot can stay in any part of the array. Notice, that array may be divided in non-equal parts.
3. Sort both parts. Apply quicksort algorithm recursively to the left and the

right parts.

Partition algorithm in detail There are two indices i and j and at the very beginning of the partition algorithm i points to the first element in the array and j points to the last one. Then algorithm moves i forward, until an element with value greater or equal to the pivot is found. Index j is moved backward, until an element with value lesser or equal to the pivot is found. If i j then they are swapped and i steps to the next position (i + 1), j steps to the previous one (j - 1). Algorithm stops, when i becomes greater than j. After partition, all values before i-th element are less or equal than the pivot and all values after j-th element are greater or equal to the pivot. Example. Sort {1, 12, 5, 26, 7, 14, 3, 7, 2} using quick sort.

AIM:

ALGORITHM: 1. Start the program. 2. Input the number of elements and the value of the individual elements. 3. Set the a[0] element as pivot element .The index 0 of array a is Lower bound lb and the index a[n-1] is the Upper bound ub

4. Compare with pivot element ,then divide into sublist elements 5. Continue the above steps for each and every node. 6. Display the sorted list of elements. 7. Stop the program. SOURCE CODE: import java.io.*; public class Quick { public static void main(String a[]) throws IOException { // int array[] = {12,9,4,99,120,1,3,10,13}; int i,n=0; BufferedReader br = new BufferedReader(newInputStreamReader(System.in)); System.out.println("Enter the no of elements"); n=Integer.parseInt(br.readLine()); int array[]=new int[n]; System.out.println("Enter the elements one by one:\n"); for(i=0;i<n;i++) { System.out.println("Enter the element" +(i+1)); array[i]=Integer.parseInt(br.readLine()); } System.out.println(" Quick Sort\n\n"); System.out.println("Values Before the sort:\n"); for(i = 0; i < array.length; i++) System.out.print( array[i]+" ");

System.out.println(); quickSort(array,0,array.length-1); System.out.print("Values after the sort:\n"); for(i = 0; i <array.length; i++) System.out.print(array[i]+" "); System.out.println(); System.out.println("PAUSE"); } public static int partition(int arr[], int left, int right) { int i = left, j = right; int tmp; int pivot = arr[(left + right) / 2]; while (i <= j) { while (arr[i] < pivot) i++; while (arr[j] > pivot) j--; if (i <= j) { tmp = arr[i]; arr[i] = arr[j]; arr[j] = tmp; i++; j--; }

} return i; } public static void quickSort(int arr[], int left, int right) { int index = partition(arr, left, right); if (left < index - 1) quickSort(arr, left, index - 1); if (index < right) quicksort (arr, index, right); } }

OUTPUT:

RESULT: The program of Quick Sort is successfully executed and verified. --------

Date: Ex No: 8 DESCRIPTION: Convex Hull using Grahams scan algorithm In mathematics, the convex hull or convex envelope for a set of points X in a real vector space V is the minimal convex set containing X. In computational geometry, it is common to use the term "convex hull" for the boundary of the minimal convex set containing a given non-empty finite set of points in the plane. Unless the points are collinear, the convex hull in this sense is a simple closed polygonal chain. The Graham scan is a method of computing the convex hull of a finite set of points in the plane with time complexity O (n log n). It is named after Ronald Graham, who published the original algorithm in 1972. The algorithm finds all vertices of the convex hull ordered along its boundary. It may also be easily modified to report all input points that lie on the boundary of their convex hull. The first step in this algorithm is to find the point with the lowest ycoordinate. If there is a tie, the point with the lowest x-coordinate out of the tie breaking candidates should be chosen. Call this point P. This step takes O(n), where n is the number of points in question. Next, the set of points must be sorted in increasing order of the angle they and the point P make with the x-axis. Any general-purpose sorting algorithm is appropriate for this, for example heapsort (which is O(n log n)). In order to speed up the calculations, it is not actually necessary to calculate the actual angle these points make with the x-axis; instead, it suffices to calculate the cotangent of this angle: it is a monotonically decreasing function in the domain in question (which is 0 to 180 degrees, due to the first step) and may be calculated with simple arithmetic. CONVEX HULL

The algorithm proceeds by considering each of the points in the sorted array in sequence. For each point, it is determined whether moving from the two previously considered points to this point is a "left turn" or a "right turn". If it is a "right turn", this means that the second-to-last point is not part of the convex hull and should be removed from consideration. This process is continued for as long as the set of the last three points is a "right turn". As soon as a "left turn" is encountered, the algorithm moves on to the next point in the sorted array. (If at any stage the three points are collinear, one may opt either to discard or to report it, since in some applications it is required to find all points on the boundary of the convex hull.)

Again, determining whether three points constitute a "left turn" or a "right turn" does not require computing the actual angle between the two line segments, and can actually be achieved with simple arithmetic only. For three points (x1,y1), (x2,y2) and (x3,y3), simply compute the direction of the cross product of the two vectors defined by points (x1,y1), (x2,y2) and (x1,y1), (x3,y3), characterized by the sign of the expression (x2 x1)(y3 y1) (y2 y1)(x3 x1). If the result is 0, the points are collinear; if it is positive, the three points constitute a "left turn", otherwise a "right turn". This process will eventually return to the point at which it started, at which point the algorithm is completed and the stack now contains the points on the convex hull in counterclockwise order.

AIM: To construct a min-max heap and perform the insert and delete operations in the heap.

ALGORITHM: 1. Start the program. 2. Take S is a set of points in the plane. 3. Let P be a starting and ending point of S.

4. Start the point of S according to the angle substented by the point and P with the X axis.
5. Begin with P1=P and take three successive points. 6. If Pi,Pi+1, Pi+2 Left turn, then print lie on the hull, else goto step 9.

7. Move to the next three points in the list by setting Pi=Pi+1.


8. If Pi P, then goto step6. 9. Delete Pi+1 from the list and move one point behind in the list by settings P i =

Pi-1.
10. If Pi P, then goto step6.

11.Print the convex hull points. 12.Stop the program.

SOURCE CODE: import java.awt.*; import java.awt.geom.*; import javax.swing.*; import java.util.*; class CHull { //Returns the determinant of the point matrix //This determinant tells how far p3 is from vector p1p2 and on which side it is static int distance(Point p1, Point p2, Point p3) { int x1 = p1.x; int x2 = p2.x; int x3 = p3.x;

int y1 = p1.y; int y2 = p2.y; int y3 = p3.y; return x1*y2 + x3*y1 + x2*y3 - x3*y2 - x2*y1 - x1*y3; } //Returns the points of convex hull in the correct order static ArrayList<Point> cHull(ArrayList<Point> array) { int size = array.size(); if (size < 2) return null; Point l = array.get(0); Point r = array.get(size - 1); ArrayList<Point> path = new ArrayList<Point>(); path.add(l); cHull(array, l, r, path); path.add(r); cHull(array, r, l, path); return path; } static void cHull(ArrayList<Point> points, Point l, Point r, ArrayList<Point> path) { if (points.size() < 3) return; int maxDist = 0; int tmp; Point p = null; for (Point pt : points) {

if (pt != l && pt != r) { tmp = distance(l, r, pt); if (tmp > maxDist) { maxDist = tmp; p = pt; } } } ArrayList<Point> left = new ArrayList<Point>(); ArrayList<Point> right = new ArrayList<Point>(); left.add(l); right.add(p); for (Point pt : points) { if (distance(l, p, pt) > 0) left.add(pt); else if (distance(p, r, pt) > 0) right.add(pt); } left.add(p); right.add(r); cHull(left, l, p, path); path.add(p); cHull(right, p, r, path); } } //The panel that will show the CHull class in action class DrawPanel extends JPanel

{ public void paintComponent(Graphics g) { super.paintComponent(g); Graphics2D g2 = (Graphics2D) g; int size = 80; int rad = 4; Random r = new Random(); ArrayList<Point> array = new ArrayList<Point>(size); for (int i = 0; i < size; i++) { int x = r.nextInt(350) + 15; int y = r.nextInt(350) + 15; array.add(new Point(x,y)); g2.draw(new Ellipse2D.Double(x-2,y-2,rad,rad)); } Collections.sort(array, new Comparator<Point>() { public int compare (Point pt1, Point pt2) { int r = pt1.x - pt2.x; if (r != 0) return r; else return pt1.y - pt2.y; } }); ArrayList<Point> hull = CHull.cHull(array); Iterator<Point> itr = hull.iterator(); Point prev = itr.next(); Point curr = null;

while (itr.hasNext()) { curr = itr.next(); g2.drawLine(prev.x, prev.y, curr.x, curr.y); prev = curr; } curr = hull.get(0); g2.drawLine(prev.x, prev.y, curr.x, curr.y); } } public class CHullExample extends JFrame { public CHullExample() { setSize(400,400); setLocation(100,100); setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); DrawPanel dp = new DrawPanel(); Container cp = this.getContentPane(); cp.add(dp); } public static void main(String[] args) { new CHullExample().setVisible(true); } } OUTPUT:

RESULT: The program of Convex Hull is successfully executed and verified. -------Date: Ex No: 9 DESCRIPTION: The knapsack problem or rucksack problem is a problem in combinatorial optimization: Given a set of items, each with a weight and a value, determine the number of each item to include in a collection so that the total weight is less than a given limit and the total value is as large as possible. It derives its name from the problem faced by someone who is constrained by a fixed-size knapsack and must fill it with the most useful items. KNAPSACK USING DYNAMIC PROGRAMMING

The problem often arises in resource allocation with financial constraints. A similar problem also appears in combinatorics, complexity theory, cryptography and applied mathematics. The decision problem form of the knapsack problem is the question "can a value of at least V be achieved without exceeding the weight W?" n the following, we have n kinds of items, 1 through n. Each kind of item j has a value pj and a weight wj. We usually assume that all values and weights are nonnegative. The maximum weight that we can carry in the bag is W. The most common formulation of the problem is the 0-1 knapsack problem, which restricts the number xj of copies of each kind of item to zero or one. Mathematically the 0-1-knapsack problem can be formulated as:

maximize subject to

The bounded knapsack problem restricts the number xj of copies of each kind of item to a maximum integer value bj. Mathematically the bounded knapsack problem can be formulated as:

maximize subject to The unbounded knapsack problem places no upper bound on the number of copies of each kind item. Of particular interest is the special case of the problem with these properties:

it is a decision problem, it is a 0-1 problem, for each kind of item, the weight equals the value: wj = pj.

Notice that in this special case, the problem is equivalent to this: given a set of nonnegative integers, does any subset of it add up to exactly W? Or, if negative weights are allowed and W is chosen to be zero, the problem is: given a set of integers, does any subset add up to exactly 0? This special case is called the subset sum problem. In the field of cryptography the term knapsack problem is often used to refer specifically to the subset sum problem. If multiple knapsacks are allowed, the problem is better thought of as the bin packing problem.

AIM: To construct a min-max heap and perform the insert and delete operations in the heap. ALGORITHM:

SOURCE CODE: public class Knapsack {

public static void main(String args[]) { int N = Integer.parseInt(args[0]); int P = Integer.parseInt(args[1]); // maximum profit int W = Integer.parseInt(args[2]); // maximum weight int[] profit = new int[N+1]; int[] weight = new int[N+1]; // generate random instance, items 1..N for (int n = 1; n <= N; n++) { profit[n] = (int) (Math.random() * P); weight[n] = (int) (Math.random() * W); } // opt[n][w] = max profit of packing items 1..n with weight limit w // sol[n][w] = true if opt solution to pack items 1..n with weight limit w // includes item n int[][] opt = new int[N+1][W+1]; boolean[][] sol = new boolean[N+1][W+1]; for (int n = 1; n <= N; n++) { for (int w = 1; w <= W; w++) { int option1 = opt[n-1][w]; // don't take item n int option2 = Integer.MIN_VALUE; // take item n if (weight[n] < w) option2 = weight[n] + opt[n-1][w-weight[n]]; opt[n][w] = Math.max(option1, option2); sol[n][w] = (option2 > option1); } } // determine which items to take boolean[] take = new boolean[N+1];

for (int n = N, w = W; n > 0; n--) { if (sol[n][w]) { take[n] = true; w = w - weight[n]; } else } // print results System.out.println("item" + "\t" + "profit" + "\t" + "weight" + "\t" + "take"); for (int n = 1; n <= N; n++) System.out.println(n + "\t" + profit[n] + "\t" + weight[n] + "\t" + take[n]); System.out.println(); } OUTPUT: { take[n] = false; }

RESULT: The program of Knapsack using Dynamic Programming is successfully executed and verified. -------Date: Ex No: 10 DESCRIPTION: GRAPH COLORING USING BACKTRACKING

AIM:

ALGORITHM:

SOURCE CODE: //knapsacking using backtracking import java.io.*; class graphc { static int nv; static int ne; static boolean m[][]; static int rang[]; static int maxcolor=0; static void input() throws Exception { BufferedReader br=new BufferedReader(new InputStreamReader(System.in)); System.out.println(No.of vertices); int nv=Integer.parseInt(br.readLine()); m=new boolean[nv][nv]; rang=new int[nv]; rang[nv-1]=1; System.out.println(Enter no.of edges); int ne=Integer.parseInt(br.readLine()); for(int i=0;i<ne;i++) { System.out.println(Start v);

int s=Integer.parseInt(br.readLine()); System.out.println(End v); int e=Integer.parseInt(br.readLine()); m[e][s]=true; m[s][e]=true; } } static void color() { for(int i=0;i<m.length;i++) { System.out.println( We try to assign Node + i + color +(rang[i])); if(!ispossible(i)) { System.out.println( We cannot assign. Backtracking ); rang[i]++; i; } else { System.out.println( We succesfully assign + i + color +(rang[i])); } } } static void print() { for(int i=0;i<m.length;i++)

System.out.print(Node+i+ ); System.out.println(); for(int i=0;i<m.length;i++) System.out.print((rang[i])+ ); System.out.println(); } static boolean ispossible(int j) { for(int i=0;i<m.length;i++) { if(m[i][j] && rang[i]==rang[j]) return false; } return true; } public static void main (String args[]) throws Exception { input(); color(); print(); } }

OUTPUT:

RESULT: The program of Graph coloring using Backtracking is successfully executed and verified. --------

Date: Ex No: 1 DESCRIPTION: A heap is an efficient semi-ordered data structure for storing a collection of orderable data. The term binary heap and heap are interchangeable in most cases. A heap can be thought of as a tree with parent and child. The main difference between a heap and a binary tree is the heap property. In order for a data structure to be considered a heap, it must satisfy the following condition (heap property): If A and B are elements in the heap and B is a child of A, then key(A) key(B). MIN-HEAP

(This property applies for a min-heap. A max heap would have the comparison reversed). What this tells us is that the minimum key will always remain at the top and greater values will be below it. Due to this fact, heaps are used to implement priority queues which allows quick access to the item with the most priority. Here's an example of a min-heap:

A heap is implemented using an array that is indexed from 1 to N, where N is the number of elements in the heap. At any time, the heap must satisfy the heap property array[n] <= array[2*n] and array[n] <= array[2*n+1] whenever the indices are in the arrays bounds. The operations commonly performed with a heap are

delete-max or delete-min: removing the root node of a max- or min-heap, respectively increase-key or decrease-key: updating a key within a max- or min-heap, respectively insert: adding a new key to the heap

merge: joining two heaps to form a valid new heap containing all the elements of both.

Compute the extreme value We will prove that array[1] is the minimum element in the heap. We prove it by seeing a contradiction if some other element is less than the first element. Suppose array[i] is the first instance of the minimum, with array[j] > array[i] for all j < i, and . But by the heap invariant array, array[floor(i / 2)] < = array[i]: this is a contradiction. Therefore, it is easy to compute MIN(heap): MIN(heap) return heap.array[1]; Removing the Extreme Value To remove the minimum element, we must adjust the heap to fill heap.array[1]. This process is called percolation. Basically, we move the hole from node i to either node 2i or 2i + 1. If we pick the minimum of these two, the heap invariant will be maintained; suppose array[2i] < array[2i + 1]. Then array[2i] will be moved to array[i], leaving a hole at 2i, but after the move array[i] < array[2i + 1], so the heap invariant is maintained. In some cases, 2i + 1 will exceed the array bounds, and we are forced to percolate 2i. In other cases, 2i is also outside the bounds: in that case, we are done. Therefore, here is the remove algorithm: #define LEFT(i) (2*i) #define RIGHT(i) (2*i + 1) REMOVE_MIN(heap)

{ savemin=arr[0]; arr[0]=arr[--heapsize]; i=0; while(i<heapsize){ minidx=i; if(LEFT(i)<heapsize && arr[LEFT(i)] < arr[i]) minidx=LEFT(i); if(RIGHT(i)<heapsize && arr[RIGHT(i)] < arr[minidx]) minidx=RIGHT(i); if(mindx!=i){ swap(arr[i],arr[minidx]); i=minidx; } else break; } } Inserting a value into the heap A similar strategy exists for INSERT: just append the element to the array, then fixup the heap-invariants by swapping. For example if we just appended element N, then the only invariant violation possible involves that element, in particular if array[floor(N / 2)] > array[N], then those two elements must be swapped and now the only invariant violation possible is between array[floor(N/4)] and array[floor(N/2)] we continue iterating until N=1 or until the invariant is satisfied.

INSERT(heap, element) append(heap.array, element) i = heap.array.length while (i > 1) { if (heap.array[i/2] <= heap.array[i]) break; swap(heap.array[i/2], heap.array[i]); i /= 2; }

AIM: To construct a min-max heap and perform the insert and delete operations in the heap. ALGORITHM: 21.Start the process. 22.The min-max heap must satisfy the heap property. array[n]<=array[2*n] and array[n]<=array[2*n+1] where n is the number of elements in the heap. 23.If array[i] is the first instance of the minimum, with array[j]>array[i] for all j<I and i>=2,then min(heap) return heap array[1]. 24.The heap must be adjusted to fill heap array in order to remove the minimum

element. 25.Move the hole from node i to either node 2i or 2i+1. 26.If array[2i]<array[2i+1] will be moved to array[i],leaving a hole at 2i,but after the move array[i]<array[2i+1],the heap invariant is maintained. 27.Just append the element to the array to do the insert operation. 28.If the element is a maximum value than the elements in the maximum level just swap this element in place of the maximum node. 29.If the element is a minimum value, then it is placed in the min level of the minmax heap. 30.Stop the program. SOURCE CODE: // minheap.java import java.io.*; class Node { private int iData; public Node(int key) { iData = key; } public int getKey() { return iData; } public void setKey(int id) { iData = id; } } class minHeap { private Node[] heapArray;

private int maxSize; private int currentSize; public minHeap(int mx) { maxSize = mx; currentSize = 0; heapArray = new Node[maxSize]; } public boolean isEmpty() { return currentSize==0; } public boolean insert(int key) { if(currentSize==maxSize) return false; Node newNode = new Node(key); heapArray[currentSize] = newNode; trickleUp(currentSize++); return true; } public void trickleUp(int index) { int parent = (index-1) / 2; Node bottom = heapArray[index]; while( index > 0 && heapArray[parent].getKey() > bottom.getKey() ) { heapArray[index] = heapArray[parent]; index = parent;

parent = (parent-1) / 2; } heapArray[index] = bottom; } public Node remove() { Node root = heapArray[0]; heapArray[0] = heapArray[--currentSize]; trickleDown(0); return root; } public void trickleDown(int index) { int largerChild; Node top = heapArray[index]; while(index < currentSize/2) { int leftChild = 2*index+1; int rightChild = leftChild+1; if(rightChild < currentSize && heapArray[leftChild].getKey() >heapArray[rightChild].getKey()) largerChild = rightChild; else largerChild = leftChild; if( top.getKey() <= heapArray[largerChild].getKey() ) break; heapArray[index] = heapArray[largerChild];

index = largerChild; } heapArray[index] = top; } public void displayHeap() { System.out.print("heapArray: "); for(int m=0; m<currentSize; m++) if(heapArray[m] != null) System.out.print( heapArray[m].getKey() + " "); else System.out.print( "-- "); System.out.println(); int nBlanks = 32; int itemsPerRow = 1; int column = 0; int j = 0; String dots = "..............................."; System.out.println(dots+dots); while(currentSize > 0) { if(column == 0) for(int k=0; k<nBlanks; k++) System.out.print(' '); System.out.print(heapArray[j].getKey()); if(++j == currentSize) break;

if(++column==itemsPerRow) { nBlanks /= 2; itemsPerRow *= 2; column = 0; System.out.println(); } else for(int k=0; k<nBlanks*2-2; k++) System.out.print(' '); } System.out.println("\n"+dots+dots); } } class minHeapAp { public static void main(String[] args) throws IOException { int value, value2,choice=0; minHeap theHeap = new minHeap(31); boolean success; while(choice<4) { System.out.println("\t1.Show\n \t2.Insert\n \t3.Remove\n \t4.Exit"); System.out.println("\n Enter the choice"); choice = getInt(); switch(choice)

{ case 1: theHeap.displayHeap(); break; case 2: System.out.print("Enter value to insert: "); value = getInt(); success = theHeap.insert(value); if( !success ) System.out.println("Can't insert; heap full"); break; case 3: if( !theHeap.isEmpty() ) { theHeap.remove(); System.out.println("Root node has been deleted\n"); } else System.out.println("Can't remove; heap empty"); break; default: break; } } } public static int getInt() throws IOException {

InputStreamReader isr = new InputStreamReader(System.in); BufferedReader br = new BufferedReader(isr); String s = br.readLine(); return Integer.parseInt(s); } }

OUTPUT:

RESULT: The program of Min Heap is successfully executed and verified. --------

You might also like