Data Structures Complete Notes
Data Structures Complete Notes
Array List:
================================
If the capacity is not reached then directly it will add the elements
Vector
============
In AL increase capacity by 50 % of the existing capacity where Vector will increment the
capacity by 100%
Vector is synchronized and AL is not synchronized.
Vector is also Ordered and allows duplicates
Custom ArrayList
=====================
1. Create the class
2. Have the variables for default value, index
3. Define the array, because AL internally uses Array List
4. Create the Default constructor and initialize the array
5. Create Add method
6. In Add method check the capacity by comparing index and the default capacity
7. If index reached to default capacity then increment the size by 50% and do array copy
8. Else Add the element and increment the index.
9. Create another class and instead of using the AL use custom arraylist
10. Try to work on the remove functionality.
HashMap
========
We insert the first element, the current load factor will be 1/16 = 0.0625. Check is 0.0625 > 0.75 ? The answer is No, therefore we don’t increase
the capacity.
Next we insert the second element, the current load factor will be 2/16 = 0.125. Check is 0.125 > 0.75 ? The answer is No, therefore we don’t
increase the capacity.
Similarly, for 3rd element, load factor = 3/16 = 0.1875 is not greater than 0.75, No change in the capacity.
4th element, load factor = 4/16 = 0.25 is not greater than 0.75, No change in the capacity.
5th element, load factor = 5/16 = 0.3125 is not greater than 0.75, No change in the capacity.
6th element, load factor = 6/16 = 0.375 is not greater than 0.75, No change in the capacity.
7th element, load factor = 7/16 = 0.4375 is not greater than 0.75, No change in the capacity.
8th element, load factor = 8/16 = 0.5 is not greater than 0.75, No change in the capacity.
9th element, load factor = 9/16 = 0.5625 is not greater than 0.75, No change in the capacity.
10th element, load factor = 10/16 = 0.625 is not greater than 0.75, No change in the capacity.
11th element, load factor = 11/16 = 0.6875 is not greater than 0.75, No change in the capacity.
12th element, load factor = 12/16 = 0.75 is equal to 0.75, still No change in the capacity.
13th element, load factor = 13/16 = 0.8125 is greater than 0.75, at the insertion of the 13th element we double the capacity.
Set
===========
1. Set internally uses the Map structure
2. Where the map gets initialized in (hashset constructor)
Data Structures Complete Notes Page 3
2. Where the map gets initialized in (hashset constructor)
3. Default capacity is 16 and loading factor 0.75
4. When the set is using the map internally, then what is the value for all the keys
(OBJECT)--you can find final Object PRESENT=new Object();
5. Find why set doesn't allow duplicates, because it follows map structure and map
doesn't allow duplicates
6. Question is why map doesn't allow duplicate keys
7. Hashset or hashmap doesn’t guarantee the order
8. Where linked hashmap and linked hash set guarantee the insertion order why because
it uses double linked list approach and each node contain the address of next hence
insertion order is preserved.
CopyOnWriteArrayList
==============================
1. In order to have the concurrency in the list we go for Copy on write ArrayList
2. It has the lock in add and remove etc
3. It uses the reentrant lock
4. It doesn't throw concurrent modiofication exception because the iteration will happen
on new array and not on the original array
5. Same currencny in set will be achieved with CopyOnWriteSet.
ArrayList LinkedList
This class uses a dynamic array to This class uses a doubly linked list to store the
store the elements in it. With the elements in it. Similar to the ArrayList, this
introduction of generics, this class class also supports the storage of all types of
supports the storage of all types of objects.
objects.
Manipulating ArrayList takes more time Manipulating LinkedList takes less time
due to the internal implementation. compared to ArrayList because, in a doubly-
Whenever we remove an element, linked list, there is no concept of shifting the
internally, the array is traversed and the memory bits. The list is traversed and the
memory bits are shifted. reference link is changed.
This class implements a List interface. This class implements both the List
Therefore, this acts as a list. interface and the Deque interface. Therefore, it
can act as a list and a deque.
import java.util.Arrays;
import java.util.Stack;
s1.push(10);
System.out.println(s);
System.out.println(s.peek());
System.out.println(s.pop());
System.out.println(s);
System.out.println(s.pop());
System.out.println(s);
System.out.println(s.pop());
System.out.println(s);
}
Object[] arr;
int size;
public CustomStack(){
arr= new Object[10];
}
//
public void push(Object obj) {
checkCapacity();
arr[size]=obj;//arr[size++]=obj;
size=size+1;//5
}
@Override
public String toString() {
StringBuffer s= new StringBuffer();
s.append("[");
for (int i = 0; i < arr.length; i++) {
s.append(" "+arr[i]);
}
s.append(" ]");
return s.toString();
}
}
➢ Classes that are implementing the Queue interface are PriorityQueue and LinkedList. These
are not thread safe.
➢ Thread Safe Queue is PriorityBlockingQueue
➢ PriorityQueue
➢ ArrayDqueue:
It is a special kind of a growable array that allows us to add or remove
an element from both sides
An ArrayDeque implementation can be used as a Stack (Last-In-First-Out)
or a Queue(First-In-First-Out)
ArrayDeque class is likely to be faster than Stack when used as a stack.
ArrayDeque class is likely to be faster than LinkedList when used as a
queue
➢ Adding Elements
In order to add an element to the ArrayDeque, we can use the methods add(),
addFirst(), addLast(), offer(), offerFirst(), offerLast() methods.
add()
addFirst()
addLast()
offer()
offerFirst()
offerLast()
Removing Elements
In order to remove an element from a deque, there are various methods
available. Since we can also remove from both the ends, the deque interface
provides us with removeFirst(), removeLast() methods. Apart from that, this
interface also provides us with the poll(), pop(), pollFirst(), pollLast() methods
where pop() is used to remove and return the head of the deque. However,
bounded means the size of the Queue is finite and fixed. Once created, we
cannot grow or shrink the size of the Queue. If we try to insert an element
into a full Queue then it will result in the operation blocking. Similarly, if
we try to take an element from an empty Queue, then also the operation
will be blocked. ArrayBlockingQueue stores the elements in the
Queue internally in the FIFO (first-in-first-out) order. The element at the
head or front of the Queue is the oldest element of all the elements
present in this queue. The element at the tail of this queue is the newest
element of all the elements of this queue. The new elements are always
inserted at the end or tail of the queue and the retrieval operations obtain
elements at the head of the queue
➢ LinkedBlockingQueue:
LinkedBlockingQueue is a class in Java that implements the BlockingQueue
interface. LinkedBlockingQueue is an optionally-bounded BlockingQueue
backed by linked nodes. Here, optionally-bounded means the capacity
given to LinkedBlockingQueue is bounded, otherwise, it will be
unbounded. The capacity can be given as a parameter to the constructor
of LinkedBlockingQueue. The capacity, if unspecified, is equal
to Integer.MAX_VALUE
➢ What is Tree ?
Tree is a data structure in which root node will be present and it can have left and right child
➢ Full binary Tree
is a tree which has all the nodes (each root should have left and right nodes)
If the tree height is h then 2^h nodes should be present at h height
➢ Complete Binary Tree-
Is a tree in which it should be full binary tree up to height n-1 and at nth level tree should be
filled from Left
➢ Construction of Tree:
How to find the Parent of Node: if we make the tree in array form
➢ Then i/2 will give the parent of tree provided if you array starts from 1 (I is the index starts from 1)
➢ How to find right child and left child of Node
➢ if we make the tree in array form
➢ Then (2*i)+1 will give the right child of a node and 2*i will provide the left child of a node
➢ At root , we will swap the left and right children of the binary tree. In this way, 20,11, and 22 will
come into the right subtree of the binary tree and 53,52, and 78 will come to the left of the binary
tree as follows.
➢ Then we will move to the next level and swap the children of 53. Here, 78 will become the left child
of 53 while 52 will become the right child of 53. Similarly we will swap the left child and right child
of 20. In this way, 22 will become the left child of 20 while 11 will become the right child of 20. The
output binary tree after swapping nodes at this level will be as follows.
➢ Now we will move to the next level. At this level, all the nodes are leaf nodes and have no children.
Due to this there will be no swapping at this level and the above image is the final output.
➢ Tree Map: tree map also arranges the keys in natural sorting order whereas hash map doesn’t
follow any order.
➢ Tree map uses the comparator internally
➢ Insertion sort is a simple sorting algorithm that works similar to the way you sort
playing cards in your hands
➢ The array is virtually split into a sorted and an unsorted part. Values from the unsorted
part are picked and placed at the correct position in the sorted part.
➢ Algorithm
To sort an array of size n in ascending order:
1: Iterate from arr[1] to arr[n] over the array.
2: Compare the current element (key) to its predecessor.
3: If the key element is smaller than its predecessor, compare it to the elements
before. Move the greater elements one position up to make space for the
swapped element.
➢ In the selection sort, the intend is to find out at which index or position the minimum
value of an array is present then replace it with Ith position
➢ In Selection sort, after first iteration the minimum values in the entire array will be at
first position
➢ After second iteration the second minimum values will be in the second position and
so on
➢ We make use of min_index variable and compare the elements with min_index and if
there any value that is present < min index then make that position as min index
➢ Once the entire array is compared and sort the min index with the I value (outer for
loop variable), to perform this SWAPPING, we use swap logic outside of the inner for
loop.
while(i<m) {
c[k]=a[i];
i++;
k++;
}
while(j<n) {
c[k]=b[j];
j++;
k++;
}
4. In the merge sort the given array is not sorted so to make it sorted, we will divide the array
into two by finding the mid element (mid= l+r/2)
5. But again after dividing into 2 arrays, the left and right array are not sorted so I cannot
apply the two way merging so
6. Split the array unless u get the single element. This is called divide and conquer.
7. The entire array will be divided in to half until the single element is reached
8. Once the single element is reached then we can say that now all the single element arrays
are sorted now we can apply the two merging.
9. So merge the 2 single element arrays into 1 list then follow the same until you get sorted
array
10. In the below diagram, total 7 elements are present which are not sorted
So first divide into 2 arrays -> still not sorted - > Look at step 1
So divide further -> Still not sorted ->Look at step 2
So divide further -> Still not sorted ->Look at step 3
Now each element is single and sorted
Apply two way merging for first 2 elements ->look at step 4
Again apply 2 way merging for arrays which has 2 elements -> Look at step 5
Again apply 2 way merging for arrays which has 4 elements -> Look at step 6 --Result
Now from the above diagram we can say that the elements before 2 are less and
elements after 2 are higher but those are not sorted. Even though if we sort those
elements, position of 2 is not going to change.
That means we can say that 2 is SORTED in the entire array.
Now apply the same logic towards the left side array and towards the right side
array.
In this way Quick sort follows the Divide conquer algorithm
Left side apply like this
Hoare's Partition :
Whenever you see above conditions are satisfied then swap I and j.
➢ To perform the Binary search the pre requisite is that array should be in the
ascending order
➢ Algorithm of Binary search
➢ Name the element to be found as 'X'
➢ Binary Search follows the left, right and middle approach
➢ Left is nothing but 0th index and right is nothing but length of array-1
➢ And middle will be calculated by the formula (l+r)/2;
➢ Once the middle index is found from the array compare the middle element to
the element
➢ Compare X with the middle element.
➢ If X matches with the middle element, we return the mid index.
➢ Else If X is greater than the mid element, then x can only lie in the right half
subarray after the mid element. So we recur for the right half, continue the
same steps from 1, till left<=right
➢ Else (X is smaller) recur for the left half, continue the same steps from 1, till
left<=right
A Graph is a non-linear data structure consisting of nodes and edges. The nodes are
sometimes also referred to as vertices and the edges are lines or arcs that connect
any two nodes in the graph. More formally a Graph can be defined as,
A Graph consists of a finite set of vertices(or nodes) and set of Edges which connect
a pair of nodes
A graph is a set of vertices and edges
So, we can define the graph G = (V,E) where V is the set of vertices and E is the set of edges. As in the above
diagram, the circles in which the data is stored are the vertices of the graphs and the lines connecting them
together are called edges of the graphs. Now the question arises if a graph is a set of vertices and edges then what
can be the minimum number of vertices and edges a graph can have?
See, a graph is a data structure. This means that it is a way of storing data. Who stores data in a graph? As you saw
in the above diagram, a vertex stores the data in the graph. So, presence of at least one vertex is necessary whereas
presence of an edge is not. Therefore the smallest graph is a graph with only one vertex and zero edges
So, the set V i.e. the set of vertices for a graph G cannot be empty but the set E can be empty
Directed Graph:
Non-directed Graph:
A graph whose edges do not have direction is called an undirected/non-directed graph. They are assumed to
be bi-directional.
Graph Traversal
1. Visiting a vertex
2. Exploration of Vertex : If I am at particular vertex then visiting all adjacent
vertex is called as exploration of vertex.
Explanation: After visiting the vertex, explore the adjacent vertex. So here adjacent vertex are 2,4,5 so write 2,4,5
after 1. So for 1 vertex all adjacent vertex is visited so explore any other vertex.
Take is as 2 now
Adjacent to 2 are 7,6,3 so Write these above
All vertex are visited and nothing is remaining.
Approach:
• Use Stack.
• First add the Starting Node to the Stack.
• Pop out an element from Stack and add all of its connected nodes to stack.
• Repeat the above two steps until the Stack is empty.
• Below is a walk through of the graph above.
The graph used for the demonstration of the code will be the same as the one used for the above example.
import java.io.*;
import java.util.*;
class Graph
{
private int V; //number of nodes in the graph
private LinkedList<Integer> adj[]; //adjacency list
private Queue<Integer> queue; //maintaining a queue
Graph(int v)
{
V = v;
adj = new LinkedList[v];
for (int i=0; i<v; i++)
{
adj[i] = new LinkedList<>();
}
queue = new LinkedList<Integer>();
}
void BFS(int n)
{
boolean nodes[] = new boolean[V]; //initialize boolean array for holding the data
int a = 0;
nodes[n]=true;
queue.add(n); //root node is added to the top of the queue
while (queue.size() != 0)
{
n = queue.poll(); //remove the top element of the queue
System.out.print(n+" "); //print the top element of the queue
graph.addEdge(0, 1);
graph.addEdge(0, 3);
graph.addEdge(0, 4);
graph.addEdge(4, 5);
graph.addEdge(3, 5);
graph.addEdge(1, 2);
graph.addEdge(1, 0);
graph.addEdge(2, 1);
graph.addEdge(4, 1);
graph.addEdge(3, 1);
graph.addEdge(5, 4);
graph.addEdge(5, 3);
graph.BFS(0);
}
}
➢ Tabulation vs Memoizatation
➢ Optimal Substructure Property
➢ Overlapping Subproblems Property
➢ How to solve a Dynamic Programming Problem ?
➢ Greedy Method and Dynamic Programming both are used for solving the optimization
problem
➢ Dynamic Program follow principle of Optimality
➢ Memoization follows top down approach
Memoization means no re-computation, which makes for a more efficient algorithm. Thus, memoization ensures that
dynamic programming is efficient, but it is choosing the right sub-problem that guarantees that a dynamic program goes
through all possibilities in order to find the best one.
Tabulation Method:
This approach follows bot up approach
It uses the iterative approach
➢ What is a heap?
A heap is a complete binary tree, and the binary tree is a tree in which the node can
have the utmost two children. A complete binary tree is a binary tree in which all the
levels except the last level, i.e., leaf node, should be completely filled, and all the
nodes should be left-justified.
Max Heap:
A max-heap is a complete binary tree in which the value in each internal node is
greater than or equal to the values in the children of that node
Min Heap:
A min-heap is a complete binary tree in which the root value in each internal node is
less than to the values in the children of that node
In Inserting the element in Max heap will happen from bottom to top :
In Deletion the element in max heap will happen from top to bottom
Example:
In the below diagram at first in heap there is only 1 element that is 10.
Later when we want to insert second element 20. the question comes that do we keep this
20 as Left child or right child. Answer is make sure that u follow the complete binary tree .
I can say that If I insert 20 towards left child then I can say that it is complete binary tree
After that compare 10 with 20 and shift to get max heap.
Later for 3rd element 15 -> insert 15 towards Right side of 20 because at this position only
we can have complete binary tree.
Look at the below diagram
Generally in the array the index starts from 0 so we should use the heapify from n/2-1
position.
To perform the heapsort first we need to create the Max heap. To create the max heap we
should compare the child with parent. In the below code. We are writing the condition as
n/2-1 -> reason for that is we need to compare or we need to identify the root node then
compare it with children.
Heapify Code
Here-> Based on the root node passed to this method we need to find the
left child and right child values and compare it with root node if needed we
should do swap to achieve max heap.
/*if(arr[l]>arr[r]) {
largest=l;
}else {
largest=r;
}*/
// If left child is larger than root
if (l < n && arr[l] > arr[largest])
largest = l;
The time depends on CPU -> so measuring time in terms of sec is not useful. So
we should represent in terms of mathematical function.
For constant function: a-> time is O(1) -> executing the method -> declare the
method and represent the time taken
So from this remove the constant and remove the fastest growing term. O(n^
2)
Liner Search
Search for number write 1 for loop and check each number so loop gets
executed for n times so we can say time taken is O(n)
Binary Search:
Take 8 elements -> search for last but 1-> Time taken is first iteration will be ->
n/2
Second iteration ->n/2/2-> n/2^2
Third iteration: n/2/2/2-> n/2^3
Iteration k= n/2^k
2^k=n
Log 2^k=logn
k=long(n)
Time taken is O(logn)
Linear search best case is -> searching the element at first position so -> O(1)
Worst case is O(n)-> Searching for Last element
Binary Search or Binary search tree-> best case is -> searching root element or
middle element ->O(1)
Worst case is -> Searching for Leaf or Last element O(logn)
➢ What is Tree ?
Tree is one Data structure. We use Node as a class which has left and right
➢ What is complete Binary Search Tree ?
It is a tree in which, left node should be lessthan the root node and right node should be
greaterthan equal the root node
➢ What is Full Binary Tree?
A tree which should have all left and right nodes.
➢ What is complete binary tree ?
If the height of tree is h-> h-1 level it should be full binary tree and at h level nodes should fill
from left
➢ What is Heap ?
Heap is nothing but complete binary tree
➢ What is Min Heap ?
Min Heap is a complete binary tree in which root element should be lesser than child
➢ What is Max Heap ?
Max Heap is a complete binary tree in which root element should be greater than child
➢ How to represent min heap and max heap ?
First find out parent positions. If the array length is is N then -> 0 to n/2-1 positions will be
parents afterwards child
To prepare Max or Min heap from the given array we need to start from n/2-1 position and for
each parent get the LC and RC -> LC: 2*i+1; RC: 2*i+2 where "i" the parent position and this
formula holds correct when array starts with index as zero
After that swap the root with greater child. Repeat the same process untill all the roots have
greater elements than child --> This is for Max Heap
Same process for min heap-> only the difference is, findout the lower element among child
and replace it with root
➢ How to represent Tree in Java ?
➢ What are tree traversal techniques ?
➢ What is inOrder() write code for inorder ?
Left->Root->Right
➢ What is preOrder() write code for it ?
Root->Left->Right
➢ What is postOrder() write code for it ?
Left->Right->Root
➢ What is Graph ?
Graph is a DS which has Vertex and Edge
➢ How graph is represented in Java ?
To represent Graph, Adjacency List - List[]
➢ What is DFS ? To represent in DFS what data structure is used ?
DFS:->Graph traversal technique-> visit any random vertex, from there take the adject and
then explore -> Stack is used
➢ What is BFS ? To represent in BFS what data structure is used ?
BFS:->Graph traversal technique-> visit any random vertex, and explore adjcent vertex
immediately -> Queue is used