DSA Infoway MasterPPT
DSA Infoway MasterPPT
For example : When the problem statement says that write an algorithm to sort
numbers.
Following is the strategy that you need to follow to solve an unknown problem:
1. Try to simplify the task in hand.
2. Think of a suitable data-structure.
3. Think about similar problems you have already solved.
Complexities
1. The solution should be fast and should have reasonable memory requirement.
2. You should be able to do Big-O analysis.
3. Sometime taking some bit more space saves a lot of time and make your
algorithm much faster.
Coding
1. Now, after capturing all the constraints of the problem, deriving few
solutions, evaluating the complexities of the various solutions, you can pick one
solution to do final coding.
2. Never ever, jump into coding before discussing constraints, Idea generation
and complexity
3. Small functions need to be created so that the code is clean and managed.
Testing
1. Once coding is done ,it is a good practice that you go through your code line by
line with some small test case. This is just to make sure your code is working as
it is supposed to work.
Algorithm analysis: Algorithm analysis helps us to determine which algorithm
is most efficient in terms of time and space consumed.
• Best case
○ Defines the input for which the algorithm takes the least time (fastest time to
complete).
○ Input is the one for which the algorithm runs the fastest.
• Average case
○ Provides a prediction about the running time of the algorithm.
○ Run the algorithm many times, using many different inputs that come from some
distribution that generates these inputs, compute the total running time (by adding
the individual times), and divide by the number of trials.
○ Assumes that the input is random.
For a given algorithm, we can represent the best, worst and average cases in
the form of expressions. As an example, let f(n) be the function which
represents the given algorithm.
void function(int n)
void funtion(int n)
{
{
int i, count =0;
for(int I = 1;i<=n ; i++)
for(i=1 ; i*i <=n ; i++)
for(int j = 1; j <= n ; j+=i)
count ++;
printf(“*”);
}
}
3
int fun(int n) {
int i = 0, j = 0, k = 0, m = 0;
for (i = 0; i<n ; i++)
for(j = I; j<n ; j++)
for(k=j+1 ; k<n ; k++)
m+=1;
return m;
}
Time complexity with examples:
3 disks = 8 times
5 disks
25 times
Data Structures
Data Type:
• A data type defines a domain of allowed values and the operations that can be
performed on those values. For example int, float, char data types are provided in C
• If an application needs to use a data type which is not provided as primitive data type
of the language, then it is programmer's responsibility to specify the values and
operations for that data type and implement it. For example data type for date is not
provided in C, and we need dates to be stored and processed in our program then we
need to define and implements the date data type.
Abstract Data Type:
• ADT is a concept that defines a data type logically. It specifies a set of data and
collection of operations that can be performed on that data.
•ADT only mentions what operations are to be performed but not how these operations
will be implemented.
•It does not specify how data will be organized in memory and what algorithms will be
used for implementing operations.
•ADT is just like a black box which hides the inner structure and design of the data type.
Example of ADT:
List ADT
A list contains elements of same type arranged in sequential order and following operations
can be performed on the list:
ADT is logical view of data and the operations to manipulate the data while Data
Structures is the actual representation of data in memory and the algorithms to
manipulate the data
ADT is a logical description while Data Structure is concrete
ADT is what is to be done and data structure is how to do it.
ADT is used by client program.
Advantages of Data Structures are-
Efficiency
Reusability
Abstraction
List of DS:
•Array
•searching and sorting algorithms
•Stack
•time complexity and space complexity
•Queue
•Linked List
•Binary Tree
•BST
•Hash
•Graph
Algorithm classification
• Algorithms that use a similar problem-solving approach can be
grouped together
• The purpose is not to be able to classify an algorithm as one type or
another, but to highlight the various ways in which a problem can be
attacked
A short list of categories
• Algorithm types we will consider include:
• Approximate solutions:
· Coin exchange problem
Simple recursive algorithms I
• A simple recursive algorithm:
• Solves the base cases directly
• Recurs with a simpler subproblem
• Does some extra work to convert the solution to the simpler subproblem into
a solution to the given problem
Example recursive algorithms
• To count the number of elements in a list:
• If the list is empty, return zero; otherwise,
• Step past the first element, and count the remaining elements in the list
• Add one to the result
• To test if a value occurs in a list:
• If the list is empty, return false; otherwise,
• If the first thing in the list is the given value, return true; otherwise
• Step past the first element, and test whether the value occurs in the
remainder of the list
Backtracking algorithms
• Backtracking algorithms are based on a depth-first recursive search
• A backtracking algorithm:
• Tests to see if a solution has been found, and if so, returns it; otherwise
• For each choice that can be made at this point,
• Make that choice
• Recur
• If the recursion returns a solution, return it
• If no choices remain, return failure
• Example: searching key of a lock from available bunch of keys.
Divide and Conquer
• Divide-and-Conquer algorithms works by recursively breaking down a
problem into two or more subproblems (divide), until these sub
problems become simple enough so that can be solved directly
(conquer).
• The solution of these sub problems is then combined to give a solution
of the original problem.
• Divide-and-Conquer algorithms involve basic three steps
• Divide the problem into smaller problems.
• Conquer by solving these problems.
• Combine these results together.
• In divide-and-conquer the size of the problem is reduced by a factor
(half, one-third etc.), While in decrease-and-conquer the size of the
problem is reduced by a constant.
Divide and Conquer
• Examples of divide-and-conquer algorithms:
· Merge-Sort algorithm (recursion)
· Quicksort algorithm (recursion)
· Computing the length of the longest path in a binary tree (recursion)
· Computing Fibonacci numbers (recursion)
Example: {-2, 11, -4, 13, -5, 2} → 20 and {1, -3, 4, -2, -1, 6} → 7
Note: The algorithms doesn’t work if the input contains all negative
numbers. It returns 0 if all numbers are negative.
Example: {-2, 11, -4, 13, -5, 2} → 20 and {1, -3, 4, -2, -1, 6} → 7
• Subset Sum
Randomized algorithms
• A randomized algorithm uses a random number at least once during
the computation to make a decision
• Example: In Quicksort, using a random number to choose a pivot
• Example: Trying to factor a large prime by choosing random numbers as
possible divisors
Thank You!!!!!
Recursion
Recursive function
• A recursive function is a function that calls itself, directly or indirectly.
• A recursive function consists of two parts:
Termination Condition and Body (which include recursive expansion).
Winding phase: It begins when the recursive function is called for the
first time, and each recursive call continues the winding phase.
In this phase function keeps on calling itself and no return statements
are executed.
This phase terminates when the terminating condition becomes true in
a call
Recursive function
fun(n+1);
sysout(n); //backward recursive
return;
}
Properties of recursive algorithm
1) A recursive algorithm must have a termination condition.
2) A recursive algorithm must change its state, and move towards the
termination condition. Without termination condition, the recursive
function may run forever and will finally consume all the stack
memory
3) A recursive algorithm must call itself.
P s v main()
{
int arr[]= {10,20,30,40,50,60,70,80,90,100};
display(arr,0);
}
P s v main()
{
int arr[]= {10,20,30,40,50,60,70,80,90,100};
sysout(“Sum = “+ sum(arr,0));
}
disp(ll.getHead()); list.setHead(reverse(list.getHead());
sysout(list);
LinkedList and recursive function
int length(listNode *p) int sum_nodes(listNode *p)
{ {
if(p == null) return 0; if(p == null) return 0;
sysout(ll.length(ll.getHead())); sysout(ll.sum_nodes(ll.getHead());
package for_DSA;
import java.util.Scanner;
class listNodeInt {
private int data;
private listNodeInt next;
public listNodeInt()
{
data=0;
next=null;
}
public listNodeInt(int d)
{
data=d;
next=null;
}
class linkedlist_int{
protected listNodeInt head;
public linkedlist_int()
{
head=null;
}
if(head==null)
{
head=new_node;
return;
}
listNodeInt iter=head;
while(iter.getNext()!=null)
iter=iter.getNext();
iter.setNext(new_node);
return;
}
new_node.setNext(head);
head=new_node;
return;
}
if(head==null)
{
head=new_node;
return;
}
if(pos==1)
{
new_node.setNext(head);
head=new_node;
return;
}
listNodeInt iter=head;
new_node.setNext(iter.getNext());
iter.setNext(new_node);
return;
}
while(iter.getNext().getNext()!=null)
iter=iter.getNext();
deletable = iter.getNext();
iter.setNext(null);
d=deletable.getData();
deletable=null;
return d;
}
if(iter.getNext()!=null)
{
deletable=iter.getNext();
d=deletable.getData();
iter.setNext(iter.getNext().getNext());
}
else
System.out.print("\n Invalid position.. cannot
delete...\n");
return d;
}
new_node.setNext(iter.getNext());
iter.setNext(new_node);
return;
}
str=str+"\n";
return str;
}
choice = sc.nextInt();
switch(choice)
{
case 1:
System.out.print("Enter data to insert : ");
data=sc.nextInt(); //20
ll.insert_first(data);
break;
case 2:
System.out.print("Enter data to insert : ");
data=sc.nextInt();
ll.insert_last(data);
break;
case 3:
System.out.print("Enter data to insert : ");
data=sc.nextInt();
System.out.print("Enter position : ");
pos=sc.nextInt();
ll.insert_at_pos(data, pos);
break;
case 4:
System.out.print("Enter data to insert : ");
data=sc.nextInt();
System.out.print("Enter data before which to be
inserted : ");
pos=sc.nextInt();
ll.insert_before(data, pos);
break;
case 5:
data = ll.delete_first();
System.out.print("Data deleted : " + data
+"\n");
break;
case 6:
data = ll.delete_last();
System.out.print("Data deleted : " + data
+"\n");
break;
case 7:
System.out.print("Enter position to delete : ");
pos=sc.nextInt();
data = ll.delete_by_pos(pos);
System.out.print("Data deleted : " + data
+"\n");
break;
case 8:
System.out.print(ll);
break;
case 9: break;
default: System.out.print("Invalid choice..\n");
}//end of switch
}while(choice!=9);
sc.close();
}//end of main
}
1. count number of nodes in SinglyLL
return cnt;
}
return iter;
}
return iter.getData();
}
while(iter!=null)
{
sysout(iter.getData());
if(iter.getNext()==null)
break;
iter = iter.getNext().getNext();
}
}
while(iter!=null)
{
deletable = iter.getNext();
if(deletable!=null)
iter.setNext(deletable.getNext());
iter=iter.getNext();
deletable = null;
}
}
prev=null;
curr=head;
while(curr!=null)
{
next = curr.getNext();
curr.setNext(prev);
prev = curr;
curr = next;
}
head=prev;
}
___________________________________________
stack using LL
class SListNodeChar
{
char ch;
SListNodeChar next;
public SListNodeChar()
{
ch = ' ';
next = null;
}
public SListNodeChar(char c)
{
ch = c;
next = null;
}
class StackLL {
SListNodeChar top;
if(top == null)
{
top = new_node;
return;
}
new_node.setNext(top);
top = new_node;
return;
}
if(top==null)
{
sysout("Stack underflow...");
return d;
}
d = top.getData();
deletable = top;
top = top.getNext();
deletable = null;
return d;
}
if(top==null)
{
sysout("Stack underflow...");
return d;
}
d = top.getData();
return d;
}
class QueueLL{
SListNode front;
if(front==null)
{
front = new_node;
return;
}
iter = front;
while(iter.getNext()!=null)
iter=iter.getNext();
iter.setNext(new_node);
return;
}
if(front==null)
{
retrun d;
}
d=front.getData();
deletable = front;
front = front.getNext();
deletable = null;
return d;
}
import java.util.Scanner;
class SListNode{
int data;
SListNode next;
public SListNode() {
data = 0;
next = null;
}
public SListNode(int d) {
data = d;
next = null;
}
public int getData() {
return data;
}
public void setData(int d) {
data = d;
}
public SListNode getNext() {
return next;
}
public void setNext(SListNode n) {
next = n;
}
class CircularLL {
SListNode last;
public CircularLL()
{
last = null;
}
if(last == null)
{
last = new_node;
last.setNext(last);
return;
}
new_node.setNext(last.getNext());
last.setNext(new_node);
return;
}
new_node.setNext(last.getNext());
last.setNext(new_node);
last = new_node;
return;
}
if(last == null)
{
str="Empty..";
return str;
}
iter = last.getNext();
do {
str = str + "->" + iter.getData();
iter = iter.getNext();
}while(iter!=last.getNext());
str = str + "\n";
return str;
}
if(pos==1)
{
if(last == null)
{
last = new_node;
last.setNext(last);
return;
}
else
{
new_node.setNext(last.getNext());
last.setNext(new_node);
return;
}
}
iter=last.getNext();
if((i==pos-1)&&(iter.getNext()!=last.getNext()))
{
new_node.setNext(iter.getNext());
iter.setNext(new_node);
return;
}
}
}
if(last.getNext()==last)
{
last.setNext(null);
d=last.getData();
last=null;
return d;
}
last.setNext(deletable.getNext());
d=deletable.getData();
deletable = null;
return d;
}
choice = sc.nextInt();
switch(choice)
{
case 1:
System.out.print("Enter data to insert :
");
data=sc.nextInt(); //20
ll.insert_first(data);
break;
case 2:
System.out.print("Enter data to insert :
");
data=sc.nextInt();
ll.insert_last(data);
break;
case 3:
System.out.print("Enter data to insert :
");
data=sc.nextInt();
System.out.print("Enter position : ");
pos=sc.nextInt();
ll.insert_by_pos(data, pos);
break;
case 4:
//System.out.print("Enter data to insert :
");
//data=sc.nextInt();
data=ll.del_first();
System.out.print("Data deleted : " + data
+"\n");
break;
case 5:
System.out.print(ll);
break;
case 6: break;
default: System.out.print("Invalid
choice..\n");
}//end of switch
}while(choice!=6);
}
}
_________________________________________
Doubly LinkedList
package Infoway_code;
import java.util.Scanner;
class DblyNode {
int data;
DblyNode prev, next;
public DblyNode()
{
data = 0;
prev = next = null;
}
public DblyNode(int d)
{
data = d;
prev = next = null;
}
int getData()
{
return data;
}
DblyNode getPrev()
{
return prev;
}
DblyNode getNext()
{
return next;
}
void setData(int d)
{
data = d;
}
void setPrev(DblyNode p)
{
prev = p;
}
void setNext(DblyNode n)
{
next = n;
}
}
class DblyLinkedList{
DblyNode head;
insert_last(val);
}
void insert_last(int d)
{
DblyNode new_node = new DblyNode(d);
if(head == null)
{
head = new_node;
return;
}
while(iter.getNext() != null)
iter = iter.getNext();
new_node.setPrev(iter);
iter.setNext(new_node);
return;
}
void insert_first(int d)
{
DblyNode new_node = new DblyNode(d);
if(head == null)
{
head = new_node;
return;
}
new_node.setNext(head);
head.setPrev(new_node);
head = new_node;
return;
}
if(head==null)
{
System.out.println("Empty..");
return;
}
if(head.getData() == d)
{
new_node.setNext(head);
head.setPrev(new_node);
head=new_node;
return;
}
DblyNode iter = head;
while((iter.getData()!=d)&&(iter!=null))
iter = iter.getNext();
if(iter==null)
{
System.out.println("Not found..");
return;
}
new_node.setPrev(iter.getPrev());
new_node.setNext(iter);
iter.getPrev().setNext(new_node);
iter.setPrev(new_node);
return;
}
while(iter!=null)
{
str = str + "-> " +iter.getData();
iter = iter.getNext();
}
str = str + "\n";
return str;
}
if(p==1)
{
del = head;
head = head.getNext();
if( head !=null) {
head.setPrev( null );
}
d=del.getData();
del=null;
return d;
}
int i;
DblyNode iter = head;
for( i = 1; i < p; i++ ) {
iter = iter.getNext();
if( iter == null ) {
return d;
}
}
iter.getPrev().setNext(iter.getNext());
if(iter.getNext()!=null)
iter.getNext().setPrev(iter.getPrev());
del = iter;
d = del.getData();
del = null;
return d;
}
}
}
Stack and Queue
Data Structure: Stack
A stack is a simple data structure used for storing data
A stack is an ordered list in which insertion and deletion are done at one end,
called top.
The last element inserted is the first one to be deleted. Hence, it is called the Last
in First out (LIFO) or First in Last out (FILO) list.
Operations on stack
Direct applications
• Balancing of symbols
• Infix-to-postfix conversion
• Evaluation of postfix expression
• Implementing function calls (including recursion)
• Finding of spans (finding spans in stock markets, refer to Problems section)
• Page-visited history in a Web browser [Back Buttons]
• Undo sequence in a text editor
• Matching Tags in HTMLand XML
Indirect applications
• Auxiliary data structure for other algorithms (Example: Tree traversal algorithms)
Implementation: There are many ways of implementing stack ADT.
• Simple array based implementation
• Dynamic array based implementation
• Linked lists implementation
Performance:
Data Structure: Queue
A queue is a data structure used for storing data (similar to Linked Lists and
Stacks).
Definition: A queue is an ordered list in which insertions are done at one end
(rear) and deletions are done at other end (front).
Direct applications
• Operating systems schedule jobs (with equal priority) in the order of arrival
(e.g., a print queue).
• Simulation of real-world queues such as lines at a ticket counter or any other
first-come first-served scenario requires a queue.
• Multiprogramming.
• Asynchronous data transfer (file IO, pipes, sockets).
• Waiting times of customers at call center.
• Determining number of cashiers to have at a supermarket.
Indirect applications
• Auxiliary data structure for algorithms (Example: Tree traversal algorithms)
Implementation: There are many ways of implementing queue ADT.
• Simple array based implementation
• Dynamic array based implementation
• Linked lists implementation
Performance:
Circular Queue ADT
We reuse the array indexes in circular fashion to insert elements in queue.
We treat the last element and the first array elements as contiguous.
package for_DSA; /* Stack of int data */
import java.util.Scanner;
class intStack{
private int arr[];
private int top;
public intStack()
{
arr=new int[10];
top=-1;
}
public intStack(int s)
{
arr=new int[s];
top=-1;
}
return;
}
return data;
}
public int peek()
{
int data=-999;
if(top==-1)
System.out.print("Stack underflow.. can not perform
peek..\n");
else
data=arr[top];
return data;
}
return str;
}//end of toString
}//end of class
_______________________________________________________________
import java.util.Scanner;
class Student{
private int rno;
String name;
float marks;
public Student(int rno, String name, float marks) {
super();
this.rno = rno;
this.name = name;
this.marks = marks;
}
@Override
public String toString() {
return "Student [rno=" + rno + ", name=" + name + ", marks=" +
marks + "]";
}
public int getRno() {
return rno;
}
public void setRno(int rno) {
this.rno = rno;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public float getMarks() {
return marks;
}
public void setMarks(float marks) {
this.marks = marks;
}
class studentStack{
private Student arr[];
private int top;
public studentStack()
{
arr=new Student[10];
top=-1;
}
public studentStack(int s)
{
arr=new Student[s];
top=-1;
}
return;
}
return data;
}
return str;
}//end of toString
}//end of class
___________________________________________________________________
import java.util.Scanner;
class intQueue {
private int arr[];
private int front,rear,size;
public intQueue()
{
front=rear=-1;
size=10;
arr=new int[size];
}
public intQueue(int s)
{
front=rear=-1;
size=s;
arr=new int[size];
}
if(front==-1)
front=0;
rear=rear+1;
arr[rear]=d;
return;
}
str=str+"\n";
return str;
}
}//end of class
_______________________________________________________________________
import java.util.Scanner;
class intCircularQueue{
private int arr[];
private int front,rear,size;
public intCircularQueue()
{
front=rear=-1;
size=10;
arr=new int[size];
}
public intCircularQueue(int s)
{
front=rear=-1;
size=s;
arr=new int[size];
}
if(front==-1)
front=0;
if(rear==size-1)
rear=0;
else
rear=rear+1;
arr[rear]=d;
return;
}
d=arr[front];
return d;
}//end of del
i=front;
if(front<=rear)
{
while(i<=rear)
{
str=str+" "+arr[i];
i=i+1;
}
}
else
{
while(i<=size-1)
{
str = str +" "+arr[i];
i=i+1;
}
i=0;
while(i<=rear)
{
str = str +" "+arr[i];
i=i+1;
}
}//end of else
str=str+"\n";
return str;
}
}//end of class
• Node
• Edge
• Root
• Path
• Children
• Parent
• Sibling
• Subtree
• Leaf Node
Terminology
• Node
• Edge
• Root
• Path
• Children
• Parent
• Sibling
• Subtree
• Leaf Node
Terminology
• Node
• Edge
• Root
• Path
• Children
• Parent
• Sibling
• Subtree
• Leaf Node
Terminology
• Node
• Edge
• Root
• Path
• Children
• Parent
• Sibling
• Subtree
• Leaf Node
Terminology
• Node
• Edge
• Root
• Path
• Children
• Parent
• Sibling
• Subtree
• Leaf Node
Terminology
• Node
• Edge
• Root
• Path
• Children
• Parent
• Sibling
• Subtree
• Leaf Node
Terminology
• Node
• Edge
• Root
• Path
• Children
• Parent
• Sibling
• Subtree
• Leaf Node
Terminology
• Node
• Edge
• Root
• Path
• Children
• Parent
• Sibling
• Subtree
• Leaf Node
Terminology
• Node
• Edge
• Root
• Path
• Children
• Parent
• Sibling
• Subtree
• Leaf Node
Terminology
• Node
• Edge
• Root
• Path
• Children
• Parent
• Sibling
• Subtree
• LeafNode
Degree
• Complete / Perfect
Binary Tree
• Every internal node has
exactly 2 children.
• All the leaf nodes are at
the same level.
Types of Binary Trees
• Smaller values in
its left sub tree
• Larger values in
its right sub tree
BST Traversal
• Preorder Traversal-
100 , 20 , 10 , 30 , 200 , 150 , 300
• Inorder Traversal-
10 , 20 , 30 , 100 , 150 , 200 , 300
• Postorder Traversal-
10 , 30 , 20 , 150 , 300 , 200 , 100
Spanning Tree
A spanning tree is a sub-graph of an
undirected connected graph, which
includes all the vertices of the graph
with a minimum possible number of
Spanning edges.
For a complete graph with N vertices, the number of spanning trees is:
N ^(N - 2)
For example:
• The minimum spanning tree from a graph is found using the following algorithms:
• Prim's Algorithm
• Kruskal's Algorithm
Kruskal's algorithm
Let U be the node nearest to the inserted one which has an imbalance.
insertion in the left subtree of the left child of U
insertion in the right subtree of the left child of U
insertion in the left subtree of the right child of U
insertion in the right subtree of the right child of U
BF = 2-2 = 0 BF = 1-3 =-2
BF = 1-0 =1 BF = 2-0 =2
BF = 1-0 =1 BF = 1-0 =1
BF = 0-0 = 0
BF = 0-0 = 0
BF = 1-0 =1
BF = 0
RL rotation
Multiway Search Tree:
1. Disk structure
2. How data is stored
3. What is indexing
4. Multilevel indexing
5. M-Way tree
6. B tree
7. B+ tree
block
RAM
Keys – 2 keys
Children – maximum 3, so this is 3-way search tree
Show the records of all students whose name starts from alphabet 'C'
Show the records of all students total marks > 275
______________________________________________
iter1=iter1.getNext();
iter2=iter2.getNext();
}
return res;
}
_________________________________________________________
class BTNode {
private int data;
private BTNode left, right;
class BinaryTree {
private BTNode root;
BTNode ref;
if(root == null)
{
root = new_node;
return;
}
q.add(root);
while(!q.isEmpty())
{
ref = q.remove();
if(ref.getLeft() == null)
{
ref.setLeft(new_node);
return;
}
else
q.add(ref.getLeft());
if(ref.getRight() == null)
{
ref.setRight(new_node);
return;
}
else
q.add(ref.getRight());
}
}
q.add(ref);
while(!q.isEmpty())
{
ref = q.remove();
sysout(ref.getData() + " ");
if(ref.getLeft()!=null)
q.add(ref.getLeft());
if(ref.getRight()!=null)
q.add(ref.getRight());
}
}
bt.setRoot(bt.createNode(10));
bt.getRoot().setRight(bt.createNode(20));
bt.getRoot().setLeft(bt.createNode(7));
bt.preOrder();
}
class BTNodeQueueNode {
BTNode data;
BTNodeQueueNode
sum leaf node, sum non leaf nodes, find min value, find max value
count level, mirror image, isIdentical
q.add(iter);
while(!q.isEmpty())
{
iter = q.remove();
if((iter.getLeft() == null) && (iter.getRight() == null))
{
sysout(" "+iter.getData());
sum = sum + iter.getData();
}
if(iter.getLeft()!=null)
q.add(iter.getLeft());
if(iter.getRight()!=null)
q.add(iter.getRight());
}//end of loop
return sum;
}
q.add(iter);
while(!q.isEmpty())
{
iter = q.remove();
if(iter.getLeft()!=null)
q.add(iter.getLeft();
if(iter.getRight()!=null)
q.add(iter.getRight());
}
// write function for max
q.add(iter);
q.add(dummy);
while(!q.isEmpty())
{
iter = q.remove();
if(iter.getData()==-999)
{
level++;
q.add(dummy);
iter=q.remove();
}
if(iter.getLeft()!=null)
q.add(iter.getLeft();
if(iter.getRight()!=null)
q.add(iter.getRight());
}
return level;
}
q.add(iter);
while(!q.isEmpty())
{
iter = q.remove();
swap(iter);
if(iter.getLeft()!=null)
q.add(iter.getLeft();
if(iter.getRight()!=null)
q.add(iter.getRight());
}
return;
}//end of function
q1.add(iter1);
q2.add(iter2);
if(iter1.getData() != iter2.getData())
return false;
if(iter1.getLeft()!=null)
q1.add(iter1.getLeft();
if(iter1.getRight()!=null)
q1.add(iter1.getRight());
if(iter2.getLeft()!=null)
q2.add(iter2.getLeft();
if(iter2.getRight()!=null)
q2.add(iter2.getRight());
}
__________________________________________________________________
bt.insert(60);
class BST_Rec {
BTNode root;
public BST_Rec()
{
root=null;
}
else
sysout("\n Duplicate data...";
return ptr;
}
visit.preOrder(r.getRight());
}
else return r;
}
return min_BST(r.getLeft());
}
bst.insert(20);
bst.insert(25);
bst.insert(15);
bst.insert(35);
bst.insert(22);
bst.insert(32);
bst.insert(8);
bst.insert(10);
bst.insert(18);
}
public void insert(int d)
{
BTNode ptr, par;
while(ptr!=null)
{
par = ptr;
if(d < ptr.getData())
ptr = ptr.getLeft();
else
{
sysout("Duplicate data...");
return;
}
}
ptr = new BTNode(d);
return;
while(ptr!=null)
{
if( d == ptr.getData())
return ptr;
else if( d < ptr.getData())
ptr = ptr.getLeft();
else ptr = ptr.getRight();
}
sysout("Not found...");
return null;
}
while(ptr.getLeft()!=null)
ptr = ptr.getLeft();
return ptr.getData();
}
if(r == null)
{
sysout("Empty...");
return null;
}
if( d < r.getData()) // delete from left subtree
r.setLeft(del_node_BST(r.getLeft(),d));
else
{
if(r.getLeft() != null && r.getRight() != null)
{
succ = r.getRight();
while(succ.getLeft()!=null)
succ = succ.getLeft();
r.setData(succ.getData());
r.setRight(del_node_BST(r.getRight(),succ.getData();
}
else
{
deletable = r;
if(r.getLeft() != null) // only left child
r = r.getLeft();
else if(r.getRight() != null) // only right child
r = r.getRight();
else
r = null;
deletalbe= null;
}
}
return r;
}//end of function
h_left = find_ht(ptr.getLeft());
h_right = find_ht(ptr.getRight());
Binary search
mid = (low+high)/2;
while((arr[mid]!=key)&&(low<high))
{
if(key < arr[mid])
high = mid - 1;
else
low = mid + 1;
if(arr[mid] == key)
return mid;
else
return -999;
}
while(low<=high)
{
mid = (low+high)/2;
__________________________________________________
Infix Postfix Prefix
A + B * C + D ===> ABC*+D+ ++A*BCD
public Conversion(String s)
{
exp = new String(S);
}
case '+' :
case '-' :
case '*' :
case '/' :
case '%' :
case '^' : while((!st.isEmpty() && (prece(st.peek() >=
prece(symbol))
{
post[p++] = st.pop();
}
st.push(symbol);
break;
while(!st.isEmpty())
post[p++] = st.pop();
case '+' :
case '-' :
case '*' :
case '/' :
case '%' :
case '^' : while((!st.isEmpty() && (prece(st.peek() >
prece(symbol))
{
pre[p++] = st.pop();
}
st.push(symbol);
break;
while(!st.isEmpty())
pre[p++] = st.pop();
//reverse pre
return p;
}
pre = prefix.toCharArray();
switch(pre[i])
{
case '+' : res = b + a; break;
case '-' : res = b - a; break;
case '+' : res = b * a; break;
case '+' : res = b / a; break;
case '+' : res = b % a; break;
case '+' : res = pow(b,a); break;
}
st.push(res);
}//end of else
}//end of for
return st.pop();
}//end of fucntion
Sorting
Types of sorting
• Internal Sorting: If the data to be sorted in small and can be kept in
main memory and sorting is performed, then it is called as internal
sorting.
• By Memory Usage: Some sorting algorithms are such, that they need
O(1) or O(logn) memory to create auxiliary locations for sorting the
data temporarily.
3. Repeat this process for all the elements until the entire array is
sorted This algorithm is called selection sort since it repeatedly selects
the smallest element.
Performance of selection sort
• Worst case complexity : O(n2 )
• Best case complexity : O(n2 )
• Average case complexity : O(n2 )
• Worst case space complexity: O(1) auxiliar
Insertion Sort
• It is a simple and efficient comparison sort.
• Each iteration removes an element from the input data and inserts it
into the correct position in the list being sorted.
• The choice of the element being removed from the input is random
and this process is repeated until all input elements have gone
through.
Advantages
• Simple implementation
• Efficient for small data
• Adaptive: If the input list is presorted [may not be completely] then
insertions sort takes O(n + d), where d is the number of inversions
• Practically more efficient than selection and bubble sorts, even
though all of them have O(n 2 ) worst case complexity
• Stable: Maintains relative order of input data if the keys are same •
In-place: It requires only a constant amount O(1) of additional memory
space
Performance of insertion sort
• Worst case complexity : O(n2 )
• Best case complexity : O(n2 )
• Average case complexity : O(n2 )
• Worst case space complexity: O(n2 ) O(1) auxiliar
Merge Sort
• Merge sort is based divide and conquer strategy.
• Can be implemented as external sorting, when the dataset is so big that it
is impossible to load the whole dataset into memory, here sorting is done
in chunks.
• Merging is the process of combining two sorted files to make one bigger
sorted file.
• Selection is the process of dividing a file into two parts: k smallest elements
and n – k largest elements.
• Selection and merging are opposite operations
○ selection splits a list into two lists
○ merging joins two files to make one file
Performance
Heapify: Heapify the root element again so that we have the highest element at
root.
public static void Bubble_sort(int arr[],int n)
{
int i,j,t;
int flag = 0;
for(i=0;i<=n;i++)
{
flag=0;
for(j=0;j<n-i;j++)
{
if(arr[j] > arr[j+1])
{
flag=1;
t=arr[j];
arr[j] = arr[j+1];
arr[j+1] = t;
}
}
if(flag==0)
break;
sysout("\n pass" + i +" ");
display(arr,n);
}
}
for(i=1;i<=n;i++)
{
k=arr[i];
for(j=i-1;j>=0 && k<arr[j];j--)
arr[j+1] = arr[j];
arr[j+1]=k;
}//end of outer loop
}
_____________________________________________________________
arr[10] = {12,23,44,56,67,78,88,99,-999};
brr[10] = {2,4,5,78,90,890,5678,-999};
tar
while(arr[i]!=-999)
{
res[tar] = arr[i];
tar++; i++;
}
while(brr[j]!=-999)
{
res[tar] = brr[j];
tar++; j++;
}
___________________________________________________
k=low1;
}
}
public static void copy(int arr[], int temp[], int low,int high)
{
int i;
for(i=low; i<=high;i++)
arr[i] = temp[i];
}
____________________________________________________________________
Quick sort
48 44 19 59 72 80 42 65 82 8 95 68
pivot=arr[low];
left=low;
right =high;
arr[low] = arr[right];
arr[right] =pivot;
return right;
}// end of function
if(low>=high) return;
pivloc = partition(arr,low,high);
QuickSort(arr,low,pivloc-1);
QuickSort(arr,pivloc+1, high);
}
public static void Bubble_sort(int arr[],int n)
{
int i,j,t;
int flag = 0;
for(i=0;i<n;i++)
{
flag=0;
for(j=0;j<n-i;j++)
{
if(arr[j] > arr[j+1])
{
flag=1;
t=arr[j];
arr[j] = arr[j+1];
arr[j+1] = t;
}
}
if(flag==0)
break;
sysout("\n pass" + i +" ");
display(arr,n);
}
}
for(i=1;i<=n;i++)
{
k=arr[i];
arr[j+1]=k;
}//end of outer loop
}
_____________________________________________________________
arr[10] = {12,23,44,56,67,78,88,99,-999};
brr[10] = {2,4,5,78,90,890,5678,-999};
tar
while(arr[i]!=-999)
{
res[tar] = arr[i];
tar++; i++;
}
while(brr[j]!=-999)
{
res[tar] = brr[j];
tar++; j++;
}
___________________________________________________
k=low1;
merge_Ver2(arr,temp,low,mid,mid+1,high);
copy_arr(arr,temp,low,high);
}
}
public static void copy(int arr[], int temp[], int low,int high)
{
int i;
for(i=low; i<=high;i++)
arr[i] = temp[i];
}
____________________________________________________________________
Quick sort
48 44 19 59 72 80 42 65 82 8 95 68
pivot=arr[low];
left=low;
right =high;
arr[low] = arr[right];
arr[right] =pivot;
return right;
}// end of function
public static void QuickSort(int arr[], int low,int high)
{
int pivloc;
if(low>=high) return;
pivloc = partition(arr,low,high);
QuickSort(arr,low,pivloc-1);
QuickSort(arr,pivloc+1, high);
}
Hashing, Hash Function and
Hash Table
What is Hashing
• Hashing is a technique that is used to uniquely identify a specific
object from a group of similar objects.
• Examples of how hashing is used in our lives:
• In universities, each student is assigned a unique roll number that can be used
to retrieve information about them.
• In libraries, each book is assigned a unique number that can be used to
determine information about the book
• Hashing is the solution that can be used in almost all such situations
and worst case complexity of hashing is still O(n) (better than BST
which is O(logn)), but it gives O(1) on the average.
What is Hashing (Cond…)
• Here we use hash function that converts a given input number or any
other key to a smaller number and uses the small number as index in
a table called hash table.
• Hash Function
• Hash function maps a big number or string to a small integer that can be used
as index in hash table
• Hash Table
• An array that stores pointers to records corresponding to a given input
number
HashTable ADT
For understanding the use of hash tables, let us consider the following
example:
Give an algorithm for printing the first repeated character if there are
duplicated elements in it. Let us think about the possible solutions.
The simple and brute force way of solving is: given a string, for each
character check whether that character is repeated or not.
1) Hash Table
2) Hash Functions
3) Collisions
There are many hash functions, but this is the minimum that it should
do. Various hash generation logics will be added to this function to
generate a better hash.
Characteristics of Good Hash Functions
A good hash function should have the following
characteristics:
• Minimize collision
• Be easy and quick to compute
• It should provide a uniform distribution of hash values
• Use all the information provided in the key
• Have a high load factor for a given set of keys
Load factor = Number of elements in Hash-Table / Hash-Table size
The process of storing objects using a hash function is as follows:
Collision is the condition where two records needs to be stored in the same
location, which is not possible.
Understand Collision
Collision Handling
• The process of finding an alternate location is called collision
resolution
• Therefore, to maintain the performance of a hash table, it is
important to manage collisions through various collision
resolution techniques.
• Open addressing
• Linear Probing
• Quadratic Probing
• Double Hashing
• Closed addressing
Linear Probing
• The function for rehashing is the following:
One of the problems with linear probing is that table items tend to
cluster together in the hash table. This means that the table contains
groups of consecutively occupied locations that are called clustering.
Open Addressing (Linear)
Quadratic Probing
• The interval between probes increases proportionally to the hash
value
• The problem of Clustering can be eliminated if we use the quadratic
probing method.
• In quadratic probing, we start from the original hash location i. If a
location is occupied, we check the locations i + 12 , i +22 , i + 32 , i + 42
• The function for rehashing is the following:
rehash(key) = (n + k2 )% tablesize
Double Hashing
• The interval between probes is computed by another hash function.
Double hashing reduces clustering in a better way.
class Employee {
int empno;
String ename;
float sal;
int age;
public Employee(int empno, String ename, float sal, int age)
{
super();
this.empno = empno;
this.ename = ename;
this.sal = sal;
this.age = age;
}
public int getEmpno() {
return empno;
}
public void setEmpno(int empno) {
this.empno = empno;
}
public String getEname() {
return ename;
}
public void setEname(String ename) {
this.ename = ename;
}
public float getSal() {
return sal;
}
public void setSal(float sal) {
this.sal = sal;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
}
1
package for_DSA;
import java.util.Scanner;
class Hash_DoubleHashing{
Record table[];
public Hash_DoubleHashing()
{
table = new Record[10];
for(int i=0;i<10;i++)
{
table[i] = new Record();
table[i].status = type_of_record.EMPTY;
}
for(int i=0;i<10;i++)
System.out.print(table[i].status);
}
public Hash_DoubleHashing(int size)
{
table = new Record[size];
for(int i=0;i<size;i++)
table[i].status = type_of_record.EMPTY;
}
location = h;
h1 = hash1(key);
1
return;
}
location = (h+i*h1)%10;
}
System.out.print("Record can't be inserted : Table
overFlow\n\n");
}
int search(int key)
{
int i, h, location;
h = hash(key);
location = h;
for( i=1; i<=9; i++ )
{
if( table[location].status ==
type_of_record.EMPTY )
return -1;
if( table[location].info.getEmpno() == key)
return location;
location = ( h + i ) % 10;
}
return -1;
}
public void del(int key)
{
int location = search(key);
if(location == -1)
System.out.print("Key not found\n");
else
table[location].status = type_of_record.DELETED;
}/*End of del()*/
public int hash(int key)
{
return (key%10);
}
2
System.out.print(" "+ table[i].info.age);
}
else if(table[i].status== type_of_record.DELETED)
System.out.print("Deleted\n");
else
System.out.print("Empty\n");
}
}
}
hl.del(9889);
hl.display();
hl.insert(new Employee(9889,"Palu",56000f,56));
System.out.println("\n\n");
hl.display();
sc.close();
}
3
package for_DSA;
import java.util.Scanner;
class Record {
Employee info;
type_of_record status;
}
class Hash_LinearProbing{
Record table[];
public Hash_LinearProbing()
{
table = new Record[10];
for(int i=0;i<10;i++)
{
table[i] = new Record();
table[i].status = type_of_record.EMPTY;
}
for(int i=0;i<10;i++)
System.out.print(" "+table[i].status);
}
public Hash_LinearProbing(int size)
{
table = new Record[size];
for(int i=0;i<size;i++)
table[i].status = type_of_record.EMPTY;
}
location = h;
for( i=1; i<=9; i++ )
{
if(table[location].status == type_of_record.EMPTY
|| table[location].status == type_of_record.DELETED)
{
table[location].info = emprec;
table[location].status =
type_of_record.OCCUPIED;
System.out.print("Record inserted\n\n");
1
return;
}
if(table[location].info.getEmpno() == key)
{
System.out.print("Duplicate key\n\n");
return;
}
location = ( h + i) % 10;
}
System.out.print("Record can't be inserted : Table
overFlow\n\n");
}
int search(int key)
{
int i, h, location;
h = hash(key);
location = h;
for( i=1; i<=9; i++ )
{
if( table[location].status ==
type_of_record.EMPTY )
return -1;
if( table[location].info.getEmpno() == key)
return location;
location = ( h + i ) % 10;
}
return -1;
}
public void del(int key)
{
int location = search(key);
if(location == -1)
System.out.print("Key not found\n");
else
table[location].status = type_of_record.DELETED;
}/*End of del()*/
public int hash(int key)
{
return (key%10);
}
2
"+table[i].info.getEmpno()+" " +table[i].info.getEname());
hl.del(9889);
hl.display();
hl.insert(new Employee(9889,"Palu",56000f,56));
System.out.println("\n\n");
hl.display();
sc.close();
}
3
package for_DSA;
import java.util.Scanner;
class Hash_QuadrticProbing{
Record table[];
public Hash_QuadrticProbing()
{
table = new Record[10];
for(int i=0;i<10;i++)
{
table[i] = new Record();
table[i].status = type_of_record.EMPTY;
}
for(int i=0;i<10;i++)
System.out.print(" "+table[i].status);
}
public Hash_QuadrticProbing(int size)
{
table = new Record[size];
for(int i=0;i<size;i++)
{
table[i] = new Record();
table[i].status = type_of_record.EMPTY;
}
}
location = h;
for( i=1; i<=9; i++ )
{
if(table[location].status == type_of_record.EMPTY
|| table[location].status == type_of_record.DELETED)
{
table[location].info = emprec;
table[location].status =
type_of_record.OCCUPIED;
System.out.print("Record inserted\n\n");
return;
}
if(table[location].info.getEmpno() == key)
{
1
System.out.print("Duplicate key\n\n");
return;
}
location = ( h + i*i) % 10;
}
System.out.print("Record can't be inserted : Table
overFlow\n\n");
}
int search(int key)
{
int i, h, location;
h = hash(key);
location = h;
for( i=1; i<=9; i++ )
{
if( table[location].status ==
type_of_record.EMPTY )
return -1;
if( table[location].info.getEmpno() == key)
return location;
location = ( h + i*i ) % 10;
}
return -1;
}
public void del(int key)
{
int location = search(key);
if(location == -1)
System.out.print("Key not found\n");
else
table[location].status = type_of_record.DELETED;
}/*End of del()*/
public int hash(int key)
{
return (key%10);
}
2
else if(table[i].status== type_of_record.DELETED)
System.out.print("Deleted\n");
else
System.out.print("Empty\n");
}
}
}
public class Hash_QuadrticProbingMain {
hl.del(9889);
hl.display();
hl.insert(new Employee(9889,"Palu",56000f,56));
System.out.println("\n\n");
hl.display();
sc.close();
3
Graphs
What is a graph?
A Graph is represented by G where G = (V, E), where V is a
finite set of points called Vertices and E is a finite set of
Edges.
Each edge is a connecting line of two vertices and is denoted
by a pair (u, v) where u, v belongs to set of vertices V.
A graph can be of 2 types
Formal definition of graphs
A graph G is defined as follows:
G=(V,E)
V(G): a finite, nonempty set of vertices
E(G): a set of edges (pairs of vertices)
Undirected graphs
When the edges in a graph have no direction, the graph is
called undirected. The graph below has 4 vertices and 5
edges
V0 V1
V3 V2
V0 V1
V4
V3 V2
Cycle: A Cycle is a path that starts and ends at the same vertex
and include at least one vertex. There has to be at least 3
vertices to form a cycle in undirected graph
Sink: A vertex, which has no outgoing edge but has incoming edges
is called as a sink
Vertex V3 is sink
Graph terminology
Pendent vertex: A vertex in a digraph is pendent if its indegree
is 1 and outdegree is 0
V1 is isolated
Loop: A self loop is an edge that connects a vertex to itself.
Loop at V1
Planar graph: A graph which can drawn on plane paper without any
two edges intersecting each other.
V0 is predecessor of V1
and V1 is successor of V0
Graph terminology
Regular graph: A graph in which each vertex is adjacent to the
same number of vertices.
Null graph: A graph which has only isolated vertices is called Null
graph.
Graph terminology
What is the number of edges in a complete undirected graph
with N vertices?
N * (N-1) / 2
2
O( N )
Graph terminology (cont.)
What is the number of edges in a complete
directed graph with N vertices?
N * (N-1)
2
O( N )
Graph terminology (cont.)
Connected graph: An undirected graph is said to be connected
if there is a path from any vertex to any other vertex, or any
vertex is reachable from any other vertex.
Graph terminology (cont.)
Graph terminology (cont.)
Disconnected undirected graph:
Graph terminology (cont.)
Connected components: An undirected graph which is not
connected may have different parts of the graph which are
connected. These parts are called as connected components.
Bridge: If on removing an edge from a connected graph, the
graph becomes disconnected then that edge is called as bridge.
Consider graph below and remove edge one by one and
identify bridge.
Articulation point: If on removing a vertex from a connected
graph, the graph becomes disconnected then that vertex is called
the articulation point.
Biconnected graph: A connection graph with no articulation point
is called a biconnected graph
Strongly connected graph: A directed graph is strongly connected if
there is a direct path from any vertex of graph to any other vertex.
DFS traversal : 0 1 2 3 6 9 5 7 8 4
Breadth-First-Searching (BFS)
Algorithm steps for BFS : Initially queue is empty, and all
vertices are at initial state.
1. Insert the starting node into the queue, change its state to
waiting
2. Loop until the Queue is empty.
3. Remove a node from the queue inside loop, visit it and
change its state to visited
4. Look for the adjacent vertices of the deleted node, and
insert only those vertices in the queue, which are at initial
state. Change the state all these vertices to waiting
6. Repeat steps 3 to 5 until Queue is empty
Start vertex is 0, so insert 0 in queue
int adj[][];
int n;
public myGraph(){
n=10;
adj = new int[n][n];
}
max_edges = n*(n-1);
}//end of loop
}//end of function
adj[origin][dest] = 1;
}
adj[origin][dest]=0;
return;
}
for(i=0;i<n;i++)
{
for(j=0;j<n;j++)
{
sysout(" " + adj[i][j]);
}
sysout("\n");
}
}
for(i=0;i<n;i++)
state[i] = 0;
st.push(v);
while(!st.isEmpty())
{
v=st.pop();
if(state[v] == 0)
{
sysout(" " + v);
state[v] = 1;
}
for(i=0;i<n;i++)
{
if(adj[v][i] == 1 && state[i] == 0)
st.push(i);
}
}
}
for(i=0;i<n;i++)
state[i] = 0;
q.insert(v);
state[v] = 1
while(!q.isEmpty())
{
v = q.del();
sysout(" " + v);
state[v] = 2;
g.insert_edge(0,3);
g.insert_edge(0,2);
g.insert_edge(1,2);
g.insert_edge(1,3);
g.insert_edge(2,3);
g.insert_edge(4,3);
g.insert_edge(0,3);
g.insert_edge(0,3);
g.insert_edge(0,3);
g.BF_Traverse(0);
g.DF_Traverse(0);
}
class Graph_for_Dijkstra {
int adj[][];
int n;
int status[];
int prede[];
int pathlength[];
Graph_for_Dijkstra(int d)
{
n=d;
adj = new int[n][n];
prede = new int[n];
pathlength = new int[n];
status = new int[n];
for(int i=0;i<n;i++)
status[i] = 0;
adj[origin][dest]=weight;
for(i=0;i<n;i++)
{
prede[i] = -1;
pathlength[i] = 9999;
status[i] = 0;
}
pathlength[s]=0;
while(true)
{
/* Search for temp vertex with minimum pathlength and make it
current */
current = min_temp();
if(current == -1)
return;
status[current] = 1;
for(i=0 ; i<n ; i++)
{
/*Check all adjacent temp vertices */
*/
for(i=0;i<n;i++)
{
if(status[i] == 0 && pathlength[i] < min)
{
min = pathlength[i];
k = i;
}
}
return k;
}
while(v != s)
{
count ++; //count = 4
path[count] = v;
u = prede[v]; //u=2
shortDist = shortDist+adj[u][v];
v = u; //v = 0
}
count++; 5
path[count] = s;
path 5 4 6 2 0
Dijkstra's algorithm
Shortest Path
• Given the graph below, suppose we wish to
find the shortest path from vertex 1 to vertex
13
Approach: Greedy
It means that path from s to v via current is smaller than the path
currently assigned to v. We need to update the previous path.
2
3
4
5
6
DIJKSTRA'S ALGORITHM - WHY USE IT?
• In Bellman Ford algorithm the shortest distance is finalized at the end of the
algorithm
• Dijkstra’s algorithm is called as label setting algorithm and Bellman Ford algorithm
is called as label correcting algorithm
Bellman Ford algorithm
A. Initialize the pathlength of all vertices to infinity, predecessor to NIL
B. Make the pathlength of source vertex equal to 0 and insert it into
queue
C. Delete vertex from queue and make it current vertex
D. Examine all the vertices adjacent to the current. Check the
condition of minimum weight for these vertices and do the
relabelling if required, as in Dijkstra’s algorithm.
E. Each label that is relabelled is inserted into queue provided it is not
already present in the queue.
F. Repeat steps C, D, E till queue becomes empty.
Dijkstra's algorithm
Shortest Path
• Given the graph below, suppose we wish to
find the shortest path from vertex 1 to vertex
13
Approach: Greedy
It means that path from s to v via current is smaller than the path
currently assigned to v. We need to update the previous path.
2
3
4
5
6
DIJKSTRA'S ALGORITHM - WHY USE IT?