Professional Documents
Culture Documents
# Section-B: 7 Questions
---------------------------------------------------------------------------
Q. Why there is a need of data structure?
Q. What is computer?
it is a machine/hardware/digital device which does different tasks for
users efficiently and effectively.
2. non-linear/advanced data structures: data ele's gets stored and hence can
be accessed in a non-linear manner
- tree (heirachical manner)
- graph (network)
- hash table (associative manner)
- binary heap
etc...
"array": it is a collection/list of logically related similar type of elements gets stored into the
memory contiguosly.
"structure": it is a collection/list of logically related similar and disimilar
type of elements (gets stored into the memory collectively).
"union": same as structure execept memory allocation
"class": inside class we can combine/collect "data members" (variables) as well as "member
functions" (function can be used to perform operations on,
data), wheras in a structure we can combine/collect only data members.
----------------------------------------------------------------------
- to learn data structure is nothing to learn an algorithms
Q. What is an algorithm?
- it is a finite set of instructions written in any human understandable language (like english), if
followed, acomplishesh the given task.
OR
- it is a finite set of instructions written in any human understandable language (like english) with
some programming constraints, if followed, acomplishesh the given task, such kind of algo is
reffered as "pseudocode".
- an algorithm is solution of a given problem
- algorithm = solution
e.g. Problem: "Sorting": it is a process to arrange data ele's in a collection/list of elements either in
an ascending order or in a descending order.
- Sorting Algorithms/Solutions
A1: Selection Sort
A2: Bubble Sort
A3: Insertion Sort
A4: Quick Sort
A5: Merge Sort
A6: Radix Sort
A7: Bucket Sort
A8: Shell Sort
- One problem has many solutions, and hence when we have many solutions for a single problem
we need to select an efficient solution.
- to decide efficiency of an algorithms we need to do their analysis
- analysis of an algo is a work to calculating how much "time" i.e. computer time and "space" i.e.
computer memory an algo needs to run to completion.
- there are two measures of an analysis of an algo:
1. time complexity
2. space complexity
1. "time complexity": of an algo is the amount computer time it needs to run to completion.
2. "space complexity": of an algo is the amount space i.e. computer memory it needs to run to
completion.
"Best Case Time Complexity": When an algo takes min amount of time then it is considered as best
case time complexity.
- Big Omega, notation can be used to represent best case time complexity
"Worst Case Time Complexity": When an algo takes max amount of time then it is considered as
worst case time complexity.
- Big Oh(O), notation can be used to represent worst case time complexity
"Average Case Time Complexity": When an algo takes neither min nor max amount of time then it
is considered as an average case time complexity.
- Big Theta, notation can be used to represent an average case time complexity
# Array:
Searching Algorithms:
"Searching": it is a process to find key in a given collection/list of elements.
- there are two searching algo's we can apply on an array data structure
1. Linear Search: In this algorithm key elements gets compared with each element in a
list/collection of elements from the first element till the match is not found or maximum till last
element sequentially, and if match is found it returns true and if match not found it returns false.
Algorithm/Pseudocode:
return false;
- In Linear search, best case occures when key is found at very first pso
, and only 1 no. of comparison takes place in this case and hence best
case time complexity: O(1)
- In Linear search, worst case occures when either key is exists at last
position or key does not exists and max "n" (whereas n = size of an
array ) no. of comparisons takes place, and hence worst case time
complexity : O(n)
- In Linear search, average case occures when key is exists at in between
position, and hence an average case time complexity: O(n/2).
# Asymptotic Analysis:
Best Case : Big Omega(1)
Worst Case : Big Oh(n)
Average Case: Big Theta(n)
2. Binary Search:
- if we want to apply this algo on array, array ele's must exists in a sorted order.
- we use "divide-and-conquer" stratergy in this algo
- in this algo, big size array gets divided into two subarrays by finding "mid" position, in first
iteration key ele gets compared with mid pos ele, if key is matches with mid pos ele, then true gets
returned to the calling function, otherwise key will get searched either into the left subarray or into
right subarray by skipping one of the subarray
- In Binary Search, best case occures when key is found in very first iteration in only 1 comparison,
and hence best case time complexity: O(1).
- In Binary Search, worst case occures if key does not exists or key is exist in (log n) no. of
comparisons, and hence worst case time compleity : O(log n)
- Average Case Time Complexity: O(log n).
# Asymptotic Analysis:
Best Case : Big Omega(1)
Worst Case : Big Oh(log n)
Average Case: Big Theta(log n)
# Sorting: it is a process to arrange data ele's in a collection/list of ele's either in an ascending order
or in a descending order.
1. Selection Sort:
# Asymptotic Analysis:
Best Case : Big Omega(n^2)
Worst Case : Big Oh(n^2)
Average Case: Big Theta(n^2)
2. Bubble Sort:
# Asymptotic Analysis:
Best Case : Big Omega(n)
Worst Case : Big Oh(n^2)
Average Case: Big Theta(n^2)
3. Insertion Sort:
# Asymptotic Analysis:
Best Case : Big Omega(n)
Worst Case : Big Oh(n^2)
Average Case: Big Theta(n^2)
4. Merge Sort:
- this algo follows "divide-and-conquer" stratergy
- as the size of an array smaller sorting is efficient
- when we want to merge two arrays, then merging of two already sorted
arrays is always efficient.
- smallest size of any array/subarray is 1, and hence in a merge sort
algo, big size array is divided into smallest size (i.e. size 1 ) subarrays
logically.
5. Quick Sort:
- this algo follows "divide-and-conquer" stratergy
- in quick we need to do partitioning:
- "partitioning": we need to select one ele as a pivot ele, and after
selection of pivot ele, we will going shift all ele's which are smaller
than pivot towards its left and ele's which are greater than pivot towards
its right, in first first pivot ele gets setteled at its fixed
position, ele's which are at left side of pivot is considered as "left
partitiion", whereas ele's which are at right side of pivot considered as
"right partition", and same logic of partitioning further can be applied on
left partition as well right partition.
- int arr[100];
- while inserting/deleting ele in an array we need to shift array ele
towards right side while inserting and towards left while deletion, and
hence addition & deletion operations are not efficient as it takes O(n)
time.
arr[20]
- in this list/collection of elements, element which was inserted/added last can only be deleted first,
this list works in "last in first out" manner, and hence it is also
called as "LIFO" list.
- basically we can perform three operations onto the stack data structure:
1. Push: to insert/add an ele into the stack at top end/position
2. Pop: to delete/remove an ele from the stack which is at top end/position
3. Peek: to get the value of an ele which is at top end/position.
# Applications of Stack:
- to control flow of an execution of a program internally an OS maintains a "stack".
- when any function gets called "function activation record" for that function call gets created into
the stack which is maintained by an OS.
- "undo" & "redo" functionalities of an OS has been implemented by using stack
- stack is used to implement advanced data structure algo: DFS i.e. Depth First Search
in tree & graph.
- stack is used to implement algo's like: conversion of given infix expression into its equivalent
prefix and postfix, postfix expression evaluation etc...
infix expression: a * b / c * d / e + f * g - h
prefix: => a * b / c * d / e + f * g - h
=> *ab / c * d / e + f * g - h
=> /*abc * d / e + f * g - h
=> */*abcd / e + f * g - h
=> /*/*abcde + f * g - h
=> /*/*abcde + *fg - h
=> +/*/*abcde*fg - h
=> -+/*/*abcde*fgh
-+/*/*abcde*fgh
hgf*edcba*/*/+-
-+/*/*abcde*fgh
-+/*/*abcde*fgh
infix expression: a * b / c * d / e + f * g - h
=> ab*c/d*e/fg*+h-
ab*c/d*e/fg*+h-
ab*c/d*e/fg*+h-
ab*c/d*e/fg*+h-
ab*c/d*e/fg*+h-
STACK
--------------------
step1:start scanning/reading postfix expression from left to right till its end
step2: if the cur ele is an operand then push it onto the stack
step3: if the cur ele is an operator then
- pop two ele's from the stack, so that first popped ele will be the second
operand & second popped ele will be the first operand
- perform cur ele (opr) operations between operand1 & operand2, and push back
result onto the stack
step4: repeat step1 & step2 till the end of postfix string
step5: finally, pop the final result from the stack and return it to the calling
function
postfix: 4 5 8 * 7 / 3 * + 2 +
-----
21
=======================================================================
===============
# Queue: it is a collection/list of logically related similar type of elements
in which ele can be inserted from one end reffered as "rear" end, wheras ele can be deleted from
another end reffered as "front" end.
- in this list element which was inserted first can be deleted first, so this list works "first in first out"
manner, and hence this list is also called as "FIFO" list.
- we can perform two basic operations onto the queue:
1. "enqueue": to insert/push/add an element into the queue from rear end
2. "dequeue": to remove/pop/delete an ele from the queue which is at front end
- priority queue can be implemented by using "linked list", and it can be implemented
efficiently by using "binary heap".
4. "double ended queue (deque): it is a type of queue in which ele's can be inserted as deleted from
both the ends.
4 basic operations can be applied onto the deque:
i. push_back()
ii. push_front()
iii. pop_back()
iv. pop_front()
II. "output restricted deque": it is a deque in which we can insert ele from both
the ends, whereas ele can be deleted only from one end.
#define SIZE 5
typedef struct
{
int arr[SIZE];
int front;
int rear;
}queue_t;
2. circular queue
front == (rear+1)%SIZE
rear++;
rear = rear+1
rear = (rear+1)%SIZE
# applications of queue:
- queue is used in an implementation of advanced data structures algo: BFS Breadth First Search in
tree & graph.
- queue is used to implement OS data structures like ready queue, job queue,
message queue etc...
- queue is used to implement OS algo's like: FCFS cpu sched, Priority sched,
FIFO page replacement algo etc....
- queue can used in any application, where collection/list of ele's should work in
first in first out manner.
=======================================================================
===============
# "tree":
it is a non-linear, advanced data structure which is a collection of finite
no. of logically related similar (as well disimilar) type of elements in which,
- there is a first specially designated ele reffered as "root", and
- remaining all ele's are connetected to the root ele in heirachical manner,
follows "parent-child" relationship.
* in a tree data structure any node can have any no. of child nodes, and tree can grow
in downwords direction at any level, and due to this operations on tree data structure cannot be
achieved efficiently, and hence restrictions can be appiled onto the tree data structure, and therefore
there are different types of tree:
- binary tree
- binary search tree
- complete binary tree
- balanced binary search tree
- avl tree
- full binary tree
- left skewed
- right skewed
- extended binary tree
- b tree
- b+ tree
* binary tree: it is a tree in which each node can have max two no. of child nodes
OR binary tree is a tree in which each node can have either 0 OR 1 OR 2 children.
OR binary tree is a tree in which degree of each node is either 0 OR 1 OR 2.
* binary tree: is set of finite no. of ele's/nodes which has three subsets:
1. root node
2. left subtree(may be empty)
3. right subtree(may be empty)
* "binary search tree" (bst): it is a binary tree in which left child is always smaller than its parent
and right child is always greater than or equal to its parent.
- these restrictions has been applied onto binary tree and binary search tree has been formed to
achieve efficiency in an operations like addition, deletion, searching etc...
2. inorder :(LVR) - any node can be visited only after visiting its left subtree
then we can visit that node and then only we can visit its right subtree
- we can visit any node only if either left subtree of that is empty OR
its left subtree is already visited.
3. postorder: (LRV) - we can visit any node only after visiting its left subtree
as well right subtree.
- we can visit any node only if either its left subtree and right subtree are
empty or its left subtree as well right subtree is already visited.
* "right skewed bst": it is a bst in which left child/link of every node is NULL.
* "left skewed bst": it is a bst in which right child/link of every node is NULL.
* "self-balanced bst": while inserting and deleting an ele into the bst it is making
sure that, bst remains balanced, this concept was designed two mathematicians
1. Adelson Velsinki
2. Lendis
- self balanced bst is also reffersd as AVL tree.
=======================================================================
===============
# graph: it is a non-linear, advanced data structure which is a collection of logically related similar
and disimilar type of ele's which contains:
- finite set of elements reffered as "vertices", also called as nodes, and
- finite set of ordered/unordered pairs of vertices reffered as an "edges", also
called as an "arcs", which may or may not contains weight/cost/value.
(weight/cost/value may be -ve).
example:
G(V,E)
V= set of finite no. of ele's = {0,1,2,3,4}
E= set of ordered/unordered pairs of vertices = edges
{(0,1), (0,2), (0,3), (1,2), (1,4), (2,3), (3,4) }
there are two ways by which we can represent a graph/two graph representation
methods are there:
1. adjacency matrix representation: 2-D Array
2. adjacency list representation: Array of Linked Lists
0 1 2 3 4
---------------------------
0 0 1 1 1 0
1 1 0 1 0 1
2 1 1 0 1 0
3 1 0 1 0 1
4 0 1 0 1 0
------------------------------------------------------------------
- adjacency matrix of a undirected graph is always a "symmetric matrix"
- if there is direct edge exists between two vertices then those two vertices are refered as adjacent
vertices.
- "cycle": if in a path starting vertex and end vertex are same, then such a path
is reffered as a "cycle".
- if path exists between two vertices then those two vertices are reffered as
"connected" vertices.
- if any vertex in a graph is connected to remaining all vertices in a graph then such a graph is
reffered as "connected graph", otherwise it is reffered as "disconnected
graph".
- if all vertices in graph are connected to remaining all vertices, then such a graph
is reffered as "complete graph".
"spanning tree": it is a subgraph of a graph can be formed by removing one or more edges from it in
a such a way that, graph remains connected and do not a cycle.
- as we know that multiple paths may exists between two vertices, but we are really interested in a
shortest path always,
- "dijsktra's" algo is used to find shortest distance of all vertices from a given
source vertex.
# hash table:
- we want to store records of thousands customers as per their mobile numbers
1. array: array is static, and addition & deletion operations are efficient
2. linked list: on a linked list we can apply only linear search -- O(n) which is
not efficient
3. balanced bst: addition, deletion & searching - O(log n)
4. "direct access table": addition, deletion & searching can be achieved in O(1)
"hashing": hashing is a process in which "big key value" gets converted into a "small practical key
value" by means of passiong to a function reffered as "hash function",
hash function returns a hash value which can be used as an index in a direct access table.