Showing posts with label Lab. Show all posts
Showing posts with label Lab. Show all posts

Saturday, 17 June 2017

DSA Lab 10 - Prim's Algorithm

Task:

In this task you have to implement the the prim's algorithm in you "MyGraph" class which you have created in lab 8.


Helping Materiel:

Prim’s Algorithm

Prim’s Algorithm also use Greedy approach to find the minimum spanning tree. In Prim’s Algorithm we grow the spanning tree from a starting position. Unlike an edge in Kruskal's, we add vertex to the growing spanning tree in Prim's.
Algorithm Steps:
  • Maintain two disjoint sets of vertices. One containing vertices that are in the growing spanning tree and other that are not in the growing spanning tree.
  • Select the cheapest vertex that is connected to the growing spanning tree and is not in the growing spanning tree and add it into the growing spanning tree. This can be done using Priority Queues. Insert the vertices, that are connected to growing spanning tree, into the Priority Queue.
  • Check for cycles. To do that, mark the nodes which have been already selected and insert only those nodes in the Priority Queue that are not marked.
Consider the example below:
enter image description here
In Prim’s Algorithm, we will start with an arbitrary node (it doesn’t matter which one) and mark it. In each iteration we will mark a new vertex that is adjacent to the one that we have already marked. As a greedy algorithm, Prim’s algorithm will select the cheapest edge and mark the vertex. So we will simply choose the edge with weight 1. In the next iteration we have three options, edges with weight 2, 3 and 4. So, we will select the edge with weight 2 and mark the vertex. Now again we have three options, edges with weight 3, 4 and 5. But we can’t choose edge with weight 3 as it is creating a cycle. So we will select the edge with weight 4 and we end up with the minimum spanning tree of total cost 7 ( = 1 + 2 +4).
Implementation:
#include <iostream>
#include <vector>
#include <queue>
#include <functional>
#include <utility>

using namespace std;
const int MAX = 1e4 + 5;
typedef pair<long long, int> PII;
bool marked[MAX];
vector <PII> adj[MAX];

long long prim(int x)
{
    priority_queue<PII, vector<PII>, greater<PII> > Q;
    int y;
    long long minimumCost = 0;
    PII p;
    Q.push(make_pair(0, x));
    while(!Q.empty())
    {
        // Select the edge with minimum weight
        p = Q.top();
        Q.pop();
        x = p.second;
        // Checking for cycle
        if(marked[x] == true)
            continue;
        minimumCost += p.first;
        marked[x] = true;
        for(int i = 0;i < adj[x].size();++i)
        {
            y = adj[x][i].second;
            if(marked[y] == false)
                Q.push(adj[x][i]);
        }
    }
    return minimumCost;
}

int main()
{
    int nodes, edges, x, y;
    long long weight, minimumCost;
    cin >> nodes >> edges;
    for(int i = 0;i < edges;++i)
    {
        cin >> x >> y >> weight;
        adj[x].push_back(make_pair(weight, y));
        adj[y].push_back(make_pair(weight, x));
    }
    // Selecting 1 as the starting node
    minimumCost = prim(1);
    cout << minimumCost << endl;
    return 0;
}
Time Complexity:
The time complexity of the Prim’s Algorithm is O((V+E)logV) because each vertex is inserted in the priority queue only once and insertion in priority queue take logarithmic time.


Reference: https://www.hackerearth.com/practice/algorithms/graphs/minimum-spanning-tree/tutorial/

DSA Lab 9 - Kruskal's Algorithm

Task:

In this task you have to implement the kruskal's algorithm for minimal spanning tree. You can use the class "MyGraph" which you have created in your previous lab.


Helping Materiel:



Kruskal’s Algorithm

Kruskal’s Algorithm builds the spanning tree by adding edges one by one into a growing spanning tree. Kruskal's algorithm follows greedy approach as in each iteration it finds an edge which has least weight and add it to the growing spanning tree.
Algorithm Steps:
  • Sort the graph edges with respect to their weights.
  • Start adding edges to the MST from the edge with the smallest weight until the edge of the largest weight.
  • Only add edges which doesn't form a cycle , edges which connect only disconnected components.
So now the question is how to check if 2 vertices are connected or not ?
This could be done using DFS which starts from the first vertex, then check if the second vertex is visited or not. But DFS will make time complexity large as it has an order of O(V+E) where V is the number of vertices, E is the number of edges. So the best solution is "Disjoint Sets":
Disjoint sets are sets whose intersection is the empty set so it means that they don't have any element in common.
Consider following example:
enter image description here
In Kruskal’s algorithm, at each iteration we will select the edge with the lowest weight. So, we will start with the lowest weighted edge first i.e., the edges with weight 1. After that we will select the second lowest weighted edge i.e., edge with weight 2. Notice these two edges are totally disjoint. Now, the next edge will be the third lowest weighted edge i.e., edge with weight 3, which connects the two disjoint pieces of the graph. Now, we are not allowed to pick the edge with weight 4, that will create a cycle and we can’t have any cycles. So we will select the fifth lowest weighted edge i.e., edge with weight 5. Now the other two edges will create cycles so we will ignore them. In the end, we end up with a minimum spanning tree with total cost 11 ( = 1 + 2 + 3 + 5).
Implementation:
#include <iostream>
#include <vector>
#include <utility>
#include <algorithm>

using namespace std;
const int MAX = 1e4 + 5;
int id[MAX], nodes, edges;
pair <long long, pair<int, int> > p[MAX];

void initialize()
{
    for(int i = 0;i < MAX;++i)
        id[i] = i;
}

int root(int x)
{
    while(id[x] != x)
    {
        id[x] = id[id[x]];
        x = id[x];
    }
    return x;
}

void union1(int x, int y)
{
    int p = root(x);
    int q = root(y);
    id[p] = id[q];
}

long long kruskal(pair<long long, pair<int, int> > p[])
{
    int x, y;
    long long cost, minimumCost = 0;
    for(int i = 0;i < edges;++i)
    {
        // Selecting edges one by one in increasing order from the beginning
        x = p[i].second.first;
        y = p[i].second.second;
        cost = p[i].first;
        // Check if the selected edge is creating a cycle or not
        if(root(x) != root(y))
        {
            minimumCost += cost;
            union1(x, y);
        }    
    }
    return minimumCost;
}

int main()
{
    int x, y;
    long long weight, cost, minimumCost;
    initialize();
    cin >> nodes >> edges;
    for(int i = 0;i < edges;++i)
    {
        cin >> x >> y >> weight;
        p[i] = make_pair(weight, make_pair(x, y));
    }
    // Sort the edges in the ascending order
    sort(p, p + edges);
    minimumCost = kruskal(p);
    cout << minimumCost << endl;
    return 0;
}
Time Complexity:
In Kruskal’s algorithm, most time consuming operation is sorting because the total complexity of the Disjoint-Set operations will be O(ElogV), which is the overall Time Complexity of the algorithm.



Reference: This content is taken from https://www.hackerearth.com/practice/algorithms/graphs/minimum-spanning-tree/tutorial/ 

Sunday, 21 May 2017

DSA Lab 8: Graph Data Structure, DFS, BFS

Task:

Implement the class "MyGraph" as discussed in class. For this you have to write a class "MyNode" and create whole graph class using this node class. Your class contains all necessary functions with the additions of these functions:

  • display_DFS()        //this will display the whole tree in depth first manner
  • display_BFS()        //this will display the whole tree in breath first manner
  • MyGraph()        //this is the constructor, it will create graph as shown in following example

Helping Materiel:
Depth First Search (DFS) algorithm traverses a graph in a depthward motion and uses a stack to remember to get the next vertex to start a search, when a dead end occurs in any iteration.
Depth First Travesal
As in the example given above, DFS algorithm traverses from A to B to C to D first then to E, then to F and lastly to G. It employs the following rules.
  • Rule 1 − Visit the adjacent unvisited vertex. Mark it as visited. Display it. Push it in a stack.
  • Rule 2 − If no adjacent vertex is found, pop up a vertex from the stack. (It will pop up all the vertices from the stack, which do not have adjacent vertices.)
  • Rule 3 − Repeat Rule 1 and Rule 2 until the stack is empty.
StepTraversalDescription
1.Depth First Search Step OneInitialize the stack.
2.Depth First Search Step TwoMark S as visited and put it onto the stack. Explore any unvisited adjacent node from S. We have three nodes and we can pick any of them. For this example, we shall take the node in an alphabetical order.
3.Depth First Search Step ThreeMark A as visited and put it onto the stack. Explore any unvisited adjacent node from A. Both S and D are adjacent to A but we are concerned for unvisited nodes only.
4.Depth First Search Step FourVisit D and mark it as visited and put onto the stack. Here, we have B and C nodes, which are adjacent to D and both are unvisited. However, we shall again choose in an alphabetical order.
5.Depth First Search Step FiveWe choose B, mark it as visited and put onto the stack. Here B does not have any unvisited adjacent node. So, we pop B from the stack.
6.Depth First Search Step SixWe check the stack top for return to the previous node and check if it has any unvisited nodes. Here, we find D to be on the top of the stack.
7.Depth First Search Step SevenOnly unvisited adjacent node is from D is C now. So we visit C, mark it as visited and put it onto the stack.
As C does not have any unvisited adjacent node so we keep popping the stack until we find a node that has an unvisited adjacent node. In this case, there's none and we keep popping until the stack is empty.

Tree Traversal

Traversal is a process to visit all the nodes of a tree and may print their values too. Because, all nodes are connected via edges (links) we always start from the root (head) node. That is, we cannot randomly access a node in a tree. There are three ways which we use to traverse a tree −
  • In-order Traversal
  • Pre-order Traversal
  • Post-order Traversal
Generally, we traverse a tree to search or locate a given item or key in the tree or to print all the values it contains.

In-order Traversal

In this traversal method, the left subtree is visited first, then the root and later the right sub-tree. We should always remember that every node may represent a subtree itself.
If a binary tree is traversed in-order, the output will produce sorted key values in an ascending order.
In Order Traversal
We start from A, and following in-order traversal, we move to its left subtree BB is also traversed in-order. The process goes on until all the nodes are visited. The output of inorder traversal of this tree will be −
D → B → E → A → F → C → G

Algorithm

Until all nodes are traversed −
Step 1 − Recursively traverse left subtree.
Step 2 − Visit root node.
Step 3 − Recursively traverse right subtree.

Pre-order Traversal

In this traversal method, the root node is visited first, then the left subtree and finally the right subtree.
Pre Order Traversal
We start from A, and following pre-order traversal, we first visit A itself and then move to its left subtree BB is also traversed pre-order. The process goes on until all the nodes are visited. The output of pre-order traversal of this tree will be −
A → B → D → E → C → F → G

Algorithm

Until all nodes are traversed −
Step 1 − Visit root node.
Step 2 − Recursively traverse left subtree.
Step 3 − Recursively traverse right subtree.

Post-order Traversal

In this traversal method, the root node is visited last, hence the name. First we traverse the left subtree, then the right subtree and finally the root node.
Post Order Traversal
We start from A, and following pre-order traversal, we first visit the left subtree BB is also traversed post-order. The process goes on until all the nodes are visited. The output of post-order traversal of this tree will be −
D → E → B → F → G → C → A

Algorithm

Until all nodes are traversed −
Step 1 − Recursively traverse left subtree.
Step 2 − Recursively traverse right subtree.
Step 3 − Visit root node.

DSA Lab 7: Binary Search Tress

Task:

We have implemented binary search algorithm in previous labs. We we have to implement the binary search tree class "MyBinarySearchTree". Your class should contain all necessary functions in addition to these functions:

  • insert(int x);        //it will create new node of integer 'x' and insert new node in the tree
  • search(int x);        //it will search integer 'x' in the BST (binary search tree) and return the True or False
  • displayPath(int x);        //it will search integer 'x' in the BST (binary search tree) and return the complete path to it from root node this integer
Note: Obviously you have to implement "MyNode" class for BST implementation.

DSA Lab 6: Trees and their traversals

Task:

Implement the class "MyTree" as discussed in class (your tree should be a binary tree - each node have 2 children). For this you have to write a class "MyNode" and create whole tree class using this node class. Your class contains all necessary functions with the additions of these functions:

  • display_DFS()        //this will display the whole tree in depth first manner
  • display_BFS()        //this will display the whole tree in breath first manner
  • MyTress()        //this is the constructor, it will take array of integers and create the whole tree with these integers

Friday, 21 April 2017

DSA Lab Assignment 1 - Time and space complexity of different data structures & algorithms

Q 1:

Write the time and space complexity of the following data structures:

  • Array
  • Stack
  • Queue
  • LinkedList
  • HashTable
  • BinarySearchTree
  • AVL
Also write the time complexity of Insertions, Deletion and Access operations of above mentioned data structures.


Q 2:

Write the time and space complexity of the following algorithms:
  • Quick Sort
  • Selection Sort
  • Bubble Sort
  • Merge Sort
  • Insertion Sot
  • Linear Search
  • Binary Search

DSA Lab 4 - Recursion & Sorting Algorithems

Task 1:

Implement the following algorithms recursively:

  • sumOfArray()      // This function will take an integer array as input and output its sum.
  • computeFactorial()    //This function will take an integer as input and output its factorial
  • displayFibonacciSeries()    //This function will take an integer as input and output that many terms of fibonacci series. e.g input = 6 then output = 1 1 2 3 5 8

Task 2:

Implement the following sorting algorithms recursively:
  • mergeSort()
  • quickSort()
Note: we have implemented these sorting algorithms before in lab 2. This time we have to implement them recursively. 

Sunday, 2 April 2017

DSA Lab 2 - Implementation of Sorting and searching algorithms

Task # 1:
Implement the following sorting algorithms:

  • Selection sort
  • Insertion sort
  • Quick sort
  • Merge sort
  • bubble sort
Note: Your Implementation should contain a class named "mySort". You have to write a separate function of all above mentioned sorting algorithms in your class "mySort". Then you can call and test your algorithms in Main as "mySort.selectionSort()". In your main function you have to take input from a file "input.txt" and show the results on console.

Task # 2:

Implement the following sorting algorithms:

  • Binary Search
Your have to perform binary search on strings this time. (Hint: convert word into number by adding up the ASCII code of each letter in the word.)

Note: Your Implementation should contain a class named "mySearch". You have to write a separate function of binary search algorithm in your class "mySearch". Then you can call and test your algorithms in Main as "mySearch.binarySearch()". In your main function you have to take input from a file "input.txt" and show the results on console.

Sunday, 19 March 2017

DSA LAB 1 | 19-3-2017

Highlights of this lab:

In this lab,  you will:
  • See the definition of a pointer.
  • Observe the basic pointer operators.
  • Master the mechanism for simple pointer manipulation.
  • Realize how to use pointers to pass parameters by reference.
  • Recognize how to use pointers with structures.
  • Learn how pointers are used in conjunction with dynamic data .
  • Discover what happens when a pointer goes into the unknown!

Definition of a Pointer.

Pointers are a type of variable that allow you to specify the address of a variable. They provide a convenient means of passing arguments to functions and for referring to more complex datatypes such as structures. They are also essential if you want to use dynamic data in the free store area. (That was a free look ahead to the dynamic data topic covered later in these notes.)You won't always know the specific value in a pointer, but you won't care as long as it contains the address of the variable you are after. You need to declare and initialize pointers just as you would other variables, but there are special operators that you need to use.

Pointer Operators.

Here is a table showing the special characters used in C++ to declare and use pointers.
*
dereference operator,
indirection operator
This is used to declare a variable as a pointer.
It is also used when you want to access the value pointed to by the pointer variable.
&
reference operator,
address-of operator
Use before a variable to indicate that you mean the address of that variable. You'll often see this in a function header where the parameter list is given.
->
member selection operatorThis is used to refer to members of structures

Simple Pointer Use.

We'd better look at some examples to make this clear.First, we'll declare two ordinary integers, and also pointers to those integers.
int  alpha  = 5;
int  beta  = 20;
int* alphaPtr =  &alpha;
int* betaPtr =  &beta;
The characters Ptr in the pointer variable name have no special significance. They are simply a memory aid for the programmer. Let's look more closely at one of the pointer declarations.
int* alphaPtr =  &alpha;
The first part int*, tells the compiler to declare a pointer for integers. alphaPtr will be the name of that pointer. In the last part of that statement, &alpha; specifies that the address of the variable alpha is what should be assigned to the pointer variable.An aside here: It is also permissable to position the asterisk closer to the pointer variable name,
i.e. int  *alphaPtr.   However the convention seems to be moving towards placing the asterisk closer to the datatype.
Try to visualize memory after these declarations, thinking of the pointer variable as not having a particular value, simply links to the variables to which they had been assigned.
Now let's look at a trivial example of how to access this data. 
*alphaPtr += 5;
*betaPtr += 5;

After these statements, it is only the contents of the alpha and beta variables that would be changed.
You might say, "What's the big deal here? I could just as easily have written this:"
alpha += 5;
beta += 5;

True, but typically pointers aren't used in such a simple manner. We just showed this to illustrate the use of pointer syntax.

Using Pointers to Pass Parameters by Reference.

A more realistic example of pointer use is to see how pointers can be used in passing parameters to a function by reference. In other words, you want to pass the addresses of the data to a function rather than the values of the data.Let's look at both pass by value and pass by reference to make sure we understand the difference. There is a little example in the C++ Syntax Web Pages (the section on Pointers) that illustrates how parameters are passed by value. Here's what that looks like:
 int a = 5;
 int b = 9;
 exchange(a,b);    // main pgm function call
 ...
 void exchange(int x, int y) // pass by value
 {
     int temp;
     temp = x;
     x = y;
      y = temp;
     return;
 }
Simple, direct - right? Well yes, but the values of a and b in the main program have not been changed! If that is what you really wanted to do, you should have used pointers to pass the parameters by reference.To do this, you need to change the function prototype and header to
void exchange(int & x, int & y)
Here is what the whole program looks like.
#include <string.h>
#include <iostream>
     using namespace std;


void exchange (int& x, int& y);

     int main ()
     {
 int a = 5;
        int b = 9;

        cout << "This program exchanges 2 values." << endl;
        cout << "Values before the exchange:" << endl;
 cout << "a= " << a << " b= " << b << endl;

        exchange(a, b);  // code that calls the function

        cout << "Values after the exchange:" << endl;
 cout << "a= " << a << " b= " << b << endl;
     }


// function for passing by reference 

     void exchange (int& x, int& y)
     {
        int temp;

        temp = x;
        x = y;
        y = temp;
        return;
     } // end exchange

Now, when the function is executed, the values of a and b will be changed in the main program. Next we'll look at how pointers are used with C++ structures.

Pointers and Structures

Let's start here by looking at an example of the structure STUDENT.
 struct STUDENT // define the structure
 {
     char name[20];
     int id;
     int mark[3];
 };
 ....
 void main()
 {
     STUDENT stu; // declare an instance of the structure
You could simply pass the address of that instance directly to a function by coding:
 function_name(&stu);
You could also add a pointer declaration to reference that instance.
 STUDENT *    stuPtr  = &stu;
The general syntax to declare a pointer and associate it with the instance of a structure is this:
 structure_name  *    pointer_name   =  & instance_name;
Now, using this pointer to reference the structure instance, we could write:
 (*stuPtr).id   =  1999;
The *, (the indirection operator), tells the compiler to use what stuPtr is pointing to. The parentheses are necessary because you want the compiler to evaluate the address in stuPtr before that value is connected to the id member delimeted by the dot operator. This is because the dot operator normally takes precedence over the indirection operator. (Remember order of precedence and order of evaluation in an expression? If not, grab your text and review these topics.)The syntax get awkward here though. i.e. (*stuPtr).id    While that form of reference is technically correct, it is somewhat cumbersome, so C++ also allows another, easier form of reference.
 stuPtr->id = 1999;
This form eliminates the parentheses in a dot expression. We'll see more of this in the programming exercise for this week's lab exercise. The next section of these notes explains how pointers are necessary for a C++ construct called dynamic data.

Dynamic Data and Pointers.

Dynamic data items are called dynamic because they are created and deleted at run time. There are two operators used to perform these functions.
new datatypeUsed to allocate a dynamic variable.
e.g. int *TmpPtr = new int;
delete pointerUsed to deallocate a dynamic variable.
e.g. delete TmpPtr;
The new operator is used to create dynamic data variables in the so-called free store, available in memory for this purpose. Free space is also referred to as the heap. (Even guru's have been known to let their hair down sometimes.) A couple of points to remember when you use the new statement.
  1. You can't directly name a dynamic data variable as you can other regular variables. If you can't name it, then how do you reference it? The answer is that you do this with a pointer.
  2. When the new operation is executed, it returns a pointer to the location of the variable space in the free store.
So let's look again at that example of using new.
int* TmpPtr   =  new  int;
The first part, int* TmpPtr, declares an integer pointer named tmpPtr. The second part, new int, creates a space in the free store, and returns a pointer to that space. The returned pointer is assigned to TmpPtr. This is typical of C++, i.e. you can accomplish a lot in a single line of code.You can declare arrays in free store as well as simple variables.
e.g. int* WeightPtr = new int [3];
To use this dynamic array element you could code:
 WeightPtr[1] = 17;  // Note: the "*" is not needed in an array reference.
We'll see more of this in the programming exercise for this week's lab exercise. The whole idea of using dynamic data is to economize on memory space. So when you've finished with a piece of dynamic data you should release the space with the delete statement.
delete TmpPtr;
delete [] WeightPtr;
This releases space in the free store, but does not delete the pointer. Be careful here! If you try to use the pointer again, after the delete statement, you don't know what address will be in the pointer.Beware the dreaded segmentation fault, core dump! (See the next section for details.)To safeguard an inadvertent overwrite of a critical area in memory, it is advisable to set pointers to NULL after you delete the associated dynamic data space. e.g.
TmpPtr = NULL;
WeightPtr = NULL;




this lab is taken from => ftp://ftp.cs.uregina.ca/pub/class/115/10-pointers/Longpointers.html
you can view the link for more details.