You are on page 1of 17

# Data Structures:

# 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.

+ basic functions of computer:


1. data storage
2. data processing
3. data movement
4. control

+ there is a need of data structure to acheive following 3 things in


programming:
1. efficiency
2. abstraction
3. reusability

Q. What is data structure?


- it is a way to store data into the memory (i.e. into the main memory)
in an organized manner so that operations (like insertion, deletion,
searching, sorting, traversal etc....) can be performed on it efficiently.

- there are two types of data structures:


1. linear/basic data structures: data ele's gets stored and hence can be
accessed in a linear manner
- array
- structure & union
- class
- linked list
- stack
- queue

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.

- Linear search is also called as "sequential search".

Algorithm/Pseudocode:

LinearSearch(A, n, key)//A is an array of size "n" & key to be search


{
for( index = 1 ; index <= n ; index++ )
{
//if key is found at any pos then return true
if( key == A[index] )
return true;
}

//if key is not found at any position


}

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.

Q. What are limitations/drawbacks of an array data structure?


- array is "static" i.e. size of an array cannot be grow or shrink during
runtime.

int arr[10];//sizeof(arr) = 40 bytes


7 ele's --> 12 bytes is getting wasted

- 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]

Why Linked List?? - to overcome limitations of an array data structure

# Linked List: it is a collection/list of logically related similar type elements in which:


- addr of first ele in a list gets stored into a pointer variable reffered as "head".
- each element contains actual value and addr of its next element (as well as prev ele) in that list.

+ element in a linked list is also called as "node".


- there are four types of linked list:
1. singly linear linked list
2. singly circular linked list
3. doubly linear linked list
4. doubly circular linked list

1. singly linear linked list: it is a linked list in which:


- head always contains addr of first ele/node if list is not empty
- each node has two parts:
1. data part: contains actual data of any primitive/non-primitive type
2. pointer part(next): contains addr of its next node
- last node points to NULL i.e. next part of last node contains NULL.

typedef struct node


{
int data;//data part: 4 bytes
struct node *next;//addr of its next node -> self referential pointer:
4 bytes
}node_t;
sizeof(node_t): 8 bytes

- we can perform two operations on linked list


1. addition: add node into the linked list
- we can add node into the linked list by three ways:
i. add node into the list at last posisition
ii.add node into the list at first posisition
iii. add node into the list at specific posisition

2. deletion: delete node from the linked list


i. delete node from the list at last posisition
ii.delete node from the list at first posisition
iii. delete node from the list at specific posisition

- "traversal" of a linked list: to visit each node in a linked list max


once sequentially.

2. singly circular linked list: it is a linked list in which:


- head always contains addr of first ele/node if list is not empty
- each node has two parts:
1. data part: contains actual data of any primitive/non-primitive type
2. pointer part(next): contains addr of its next node
- last node points to first node i.e. next part of last node contains addr of first node.

* limitations of singly linked list (either linear or circular)


- we cannot access prev node of any node from it
- we can traverse the linked list in only forward direction

- "doubly linked list" has beed designed to overcome limitations of singly


linked list.

3. doubly linear linked list: it is a linked list in which:


- head always contains addr of first ele/node if list is not empty
- each node has three parts:
1. data part: contains actual data of any primitive/non-primitive type
2. pointer part(prev): contains addr of its prev node
3. pointer part(next): contains addr of its next node
- next part of last node and prev part of first node points to NULL.

4. doubly circular linked list: it is a linked list in which:


- head always contains addr of first ele/node if list is not empty
- each node has three parts:
1. data part: contains actual data of any primitive/non-primitive type
2. pointer part(prev): contains addr of its prev node
3. pointer part(next): contains addr of its next node
- next part of last node points to first node and prev part of first node points to last node.
# Stack: it is a collection/list of logically related similar type of elements in which elements can be
added as well deleted only from one end reffered as "top" end.

- 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.

- implementation of stack by using an array: "static stack"


1. Push: to insert/add an ele into the stack at top end/position:
step1: check stack is not full
step2: increment the value of top by 1
step3: insert ele into the stack at top position

2. Pop: to delete/remove an ele from the stack which is at top end/position:


step1: check stack is not empty
step2: decrement the value of top by 1 i.e. we are deleting/popping ele from the
stack

3. Peek: to get the value of an ele which is at top end/position.


step1: check stack is not empty
step2: return the value of topmost ele (without increment/decrement the top).

is_stack_full: top == SIZE-1


is_stack_empty: top == -1

# 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...

# expression: combination/sequence of an operands and operators:


- there are three types of expression:
1. infix expression : a+b
2. prefix expression : +ab
3. postfix expression: ab+

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

postfix => ab* / c * d / e + f * g - h


=> ab*c/ * d / e + f * g - h
=> ab*c/d* / e + f * g - h
=> ab*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-

ab*c/d*e/fg*+h-

# Algorithm : Prefix to Postfix:


- Read prefix expression in reverse order(i.e. from right to left)
- if an ele is an operand -> push it onto the stack
- if an ele is an operator -> pop two ele's from the stack
create a string by concatenating the two operands and the operator
string = op1 + op2 + opr
push the string into the stack

- Repeat the above steps until end of the Prefix expression


- + / * / * a b c d e *fgh

ab*c/d*e/fg*+h-

STACK
--------------------

infix expression: "4+5*8/7*3+2"


- convert infix expression into its equivalent postfix:
=> 4 + 5 * 8 / 7 * 3 + 2
=> 4 + 58* / 7 * 3 + 2
=> 4 + 58*7/ * 3 + 2
=> 4 + 58*7/3* + 2
=> 458*7/3*+ + 2
=> 458*7/3*+2+

postfix expression: 458*7/3*+2+

algo for postfix evaluation: "458*7/3*+2+"

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

- there are 4 types of queue:


1. linear queue
2. circular queue
3. "priority queue": it is a type of queue in which ele can be added into the queue from rear end
randomly (i.e. without checking priority), whereas ele which is highest
priority can only be deleted first.

- 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()

- there are two types of double ended queue:


I. "input restricted deque": it is a deque in which we can insert ele only from
one end, whereas ele can be deleted from both the ends.

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.

1. "linear queue": we can implement linear queue by using an array


- as array is static, linear queue also becomes static, i.e. there is limit
on no. of ele's we can insert into the queue at a time.

#define SIZE 5

typedef struct
{
int arr[SIZE];
int front;
int rear;
}queue_t;

queue_full: rear == SIZE-1


queue_empty: rear == -1 || front > rear
1. "enqueue": to insert/push/add an element into the queue from rear end:
step1: check queue is not full
step2: increment the value of rear by 1
step3: insert/push ele into the queue from rear end
step4: if ( front == -1 ) then front=0

2. "dequeue": to remove/pop/delete an ele from the queue which is at front end


step1: check queue is not empty
step2: increment the value of front by 1, i.e. we are deleting ele from the
queue.

- limitation of linear queue : "vacant places cannot be reutilized"

2. circular queue

queue_full: front == (rear+1)%SIZE


queue_empty: rear == -1 && front == rear

1. "enqueue": to insert/push/add an element into the queue from rear end:


step1: check queue is not full
step2: increment the value of rear by 1 [ rear = (rear+1)% SIZE ]
step3: insert/push ele into the queue from rear end
step4: if ( front == -1 ) then front=0

2. "dequeue": to remove/pop/delete an ele from the queue which is at front end


step1: check queue is not empty
step2: increment the value of front by 1, i.e. we are deleting ele from the
queue. [ front = (front+1)% SIZE ]

front == (rear+1)%SIZE

for => rear = 0, front = 1


=> front == (rear+1)%SIZE
=> 1 == (0+1)%5
=> 1 == 1%5
=> 1 == 1

for => rear = 1, front = 2


=> front == (rear+1)%SIZE
=> 2 == (1+1)%5
=> 2 == 2%5
=> 2 == 2

for => rear = 2, front = 3


=> front == (rear+1)%SIZE
=> 3 == (2+1)%5
=> 3 == 3%5
=> 3 == 3

for => rear = 3, front = 4


=> front == (rear+1)%SIZE
=> 4 == (3+1)%5
=> 4 == 4%5
=> 4 == 4

for => rear = 4, front = 0


=> front == (rear+1)%SIZE
=> 0 == (4+1)%5
=> 0 == 5%5
=> 0 == 0

rear++;
rear = rear+1
rear = (rear+1)%SIZE

for rear = 0 => (rear+1)%SIZE => (0+1)%5 => 1%5 => 1


for rear = 1 => (rear+1)%SIZE => (1+1)%5 => 2%5 => 2
for rear = 2 => (rear+1)%SIZE => (2+1)%5 => 3%5 => 3
for rear = 3 => (rear+1)%SIZE => (3+1)%5 => 4%5 => 4
for rear = 4 => (rear+1)%SIZE => (4+1)%5 => 5%5 => 0

# 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 tree data structure, ele is also called as "node".


* root node
* parent node/father
* child node/son
* grand parent/grand father
* grand child/grand son
* siblings: child nodes of same parent
* ancestors: all the nodes which are in the path from root node to that node
* descendents: all nodes which are accessible from it
* degree of a node = no. of child nodes of that node/no. of children of a node
* degree of a tree = max degree of any node in a given tree
* leaf node/terminal node/external node: node which do not having any child node
OR node which is having degree 0.

* non-leaf node/non-terminal node/internal node: node which having child node


OR node which is having non-zero degree.

* if we assume, level of a root node = 0


* level of node = level of its parent node + 1
* level of a tree = max level of any node in a given tree

* 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...

- we can always start traversal in a bst from "root node" only.

- we can traverse tree by three methods:


1. preorder :(VLR) - first we visit the node, then visit its left subtree and we
can visit its right subtree

PREORDER: 50 20 10 5 15 45 30 90 85 75 50 100 95 120


- in this type of traversal, root node is always occures at first position, this
order remains applicable for subtree's as well

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.

INORDER: 5 10 15 20 30 45 50 50 75 85 90 95 100 120


- we will always gets bst ele's in an ascending order

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.

POSTORDER: 5 15 10 30 45 20 50 75 85 95 120 100 90 50


- in this type of traversal, root node is always gets visited/occures at last
position, this order remains applicable for subtree's as well

* "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.

* "balanced bst": bst in which each node is balanced


- if "balance factor" of each node is either -1 OR 0 OR +1 then only we can say node is balanced.
- balance factor of a node = ( ht. of its left subtree - ht. of its right subtree )
- height of a node = max( ht. of left subtree, ht. of right subtree) + 1
- "height of a tree" = max height of any node in a given tree

- max ht. of bst = n, n = no. of ele's in a bst


- min ht. of bst = log n, n = no. of ele's in a bst
- as ht. of any is max operations like addition, deletion and searching becomes
inefficient. in other words as the ht. of a bst is min operations like addition, deletion and searching
becomes efficient.

* "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) }

two vertices => u, v


(u,v) <==> (v,u)

(u,v) <==> (v,u) ==> undirected edge = unordered pair of vertices


(u,v) != (v,u) ==> directed edge = ordered pair of of vertices

- if graph contains unordered pairs of vertices then such a graph is reffered


as "undirected graph".

- if graph contains ordered pairs of vertices then such a graph is reffered


as "directed graph"/"di-graph".

- if edges in a graph carries weight/cost/value, then such a graph is reffered as


"weighted graph", otherwise it is reffered as "unweighted graph".
- if there is an edge from any node to itself, then such edge is reffered as
a "loop".

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".

- adjacent vertices are always connected, but vice-versa is not true

"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.

- spanning must contains min (V-1) no. of edges


- "weight of a graph" = sum of weights of all its edges
- one graph may has multiple spanning trees
- "minimum spanning tree": spanning tree of a graph which is having min weight is reffered as
"minimum spanning tree".
- to find minimum spanning tree of a given input graph two algo's used:
1. kruskal's
2. prim's

- 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.

- after applying hashing on direct access table it becomes a hash table,


"hash table" is nothing an improvement on a "direct access table".
in which data ele's can be kept in an associative manner i.e. key-value pairs
and operations like addition, deletion and searching can be achieved in closed to
O(1).

You might also like