1. IFT312_DataStruct_Algo
1. IFT312_DataStruct_Algo
Data structures are used to organize and store data to use in an effective way when performing
data operations.
Data search: Searching through a heap of data for every request for data, e.g. an inventory app
of 1 million items has to search 106 items every time, thereby slowing down the search.
Processor Speed: The processor speed does not catch up with the rate of growth of data. The
processor speed is limited, whereas the data continues to grow.
Multiple requests: As many user requests are entertained simultaneously, servers could fail the
requests of multiple users while searching for data.
DSA has come to solve these problems, whereby data are organized in such a way that all data
items may not be searched to get a desired data.
TQ 2: Group the above data structures into Static and Dynamic storage system; then group
according to Linear and non-linear.
1.3 Algorithms:
We are going to study the following Algorithms:
1. Searching Algorithms
2. Sorting Algorithms
3. Approximation Algorithms
4. Divide and Conquer Algorithms
5. Greedy Algorithms
6. Recursion Algorithms
7. Backtracking Algorithms
8. Randomized Algorithms
Step1: START
Step2: declare three variables, a, b and c
Step3: Assign values to variables a and b
Step4: Add the content of variables and b
Step5: Store the output of step 4 into variable c
Step6 : Print the content of variable c
Step7: STOP
An Analyst writes the algorithm and the programmer writes the code. Note that a problem can be
solved in more than one ways, hence many algorithms can be derived for a given problem.
a. A Priori Analysis: this is the analysis of an algorithm where its efficiency is measured
based on the assumption that the processor speed is constant and it has no effect on the
implementation.
b. A Posterior Analysis: this is the analysis of an algorithm using a selected programming
language on a target computer considering the running time and the space consumption
of the implementation.
Built-in Data Type
Those data types for which a language has built-in
support are known as Built-in Data
types. For example, most of the languages provide
the following built-in data types.
required.
These data
structures
are efficient
considering
the space
complexity
of the program. Few examples of dynamic linear data structures include: linked lists, stacks and
queues.
However, they are designed to overcome the issues and limitations of linear data structures. For
instance, the main disadvantage of linear data structures is the memory allocation. Since the data
is allocated sequentially in linear data structures, each element in these data structures uses one
whole memory block. However, if the data uses less memory than the assigned block can hold,
the extra memory space in the block is wasted. Therefore, non-linear data structures are
introduced. They decrease the space complexity
and use the memory optimally.
Arrays are used as solutions to many problems from the small sorting problems to more complex
problems like travelling salesperson problem. An array has a random access lookup time, that is,
accessing the 1st index of the array and the 1000th index of the array will both take the same
time. This is due to the fact that array comes with a pointer and an offset value.
The pointer points to the right location of the memory and the offset value shows how far to look
in the said memory.
Array Representation
Arrays are represented as a collection of buckets where each bucket stores one element. These
buckets are indexed from '0' to 'n-1', where n is the size of the array. For example, an array with
size 10 will have buckets indexed from 0 to 9.
This indexing will be similar for the multidimensional arrays as well. If it is a 2-dimensional
array, it will have sub-buckets in each bucket. Then it will be indexed as array_name[r,c], where
m and n are the sizes of each level in the array in a row and column (r,c) manner. See the IFT
matrix above.
Figure 3: A Single Dimension Array
TQ. 3: a. Write out Six important points about an array data structure.
b. Is an array static or a dynamic data structure?
A linked list is a dynamic linear data structure whose memory size can be allocated or de-
allocated at run time based on the operation insertion or deletion, this helps in using system
memory efficiently. Linked lists can be used to implement various other data structures like a
stack, queue, graph, hash maps, etc.
A linked list starts with a head node which points to the first node. Every node consists
of data which holds the actual data (value) associated with the node and a next pointer
which holds the memory address of the next node in the linked list. The last node is
called the tail node in the list which points to null indicating the end of the list.
2.3.1 Differences Between an Array and a Linked-List
In case of arrays, the size is given at the time of creation and so arrays are of fixed length (Static
data structure); whereas Linked lists are dynamic in size and any number of nodes can be added
in the linked lists dynamically. An array can accommodate similar types of data types whereas
linked lists can store various nodes of different data types.
TQ 4: What are the differences between Array and Linked List data structures?
Now, the next node at the left should point to the new node, as in Fig. 3
1. START
2. Create a node to store the data
3. Check if the list is empty
4. If the list is empty, add the data to the node and assign the head pointer to it.
Figure 3: Linked list Insertion final step
5. If the list is not empty, add the data to a node and link to the current head. Assign the head to
the newly added node.
6. END
1. START
2. Create a new node and assign the data
1. START
2. Create a new node and assign data to it
3. Iterate until the node at position is found
4. Point first to new first node
5. END
Linked List - Deletion Operation
Deletion is also a more than one step process. First, locate the target node to be removed, by
using searching algorithms.
The left (previous) node of the target node now should point to the next node of the target node.
This will remove the link that was pointing to the target node. Now, using the following code, we
will remove what the target node is pointing at.
Figure 4:Deleting a node
We need to use the deleted node. We can keep that in memory otherwise we can
simply deallocate memory and wipe off the target node completely.
Similar steps should be taken if the node is being inserted at the beginning of the list.
While inserting it at the end, the second last node of the list should point to the new node and the
new node will point to NULL. Deletion in linked lists is also performed in three different ways
as follows -
Deletion at Beginning
In this deletion operation of the linked, we are deleting an element from the beginning of the list.
Algorithm
1. START
2. Assign the head pointer to the next node in the list
3. END
Deletion at Ending
In this deletion operation of the linked, we are deleting an element from the ending of the list.
Algorithm
1. START
2. Iterate until you find the second last element in the list.
3. Assign NULL to the second last element in the list.
4. END
In this deletion operation of the linked list, we are deleting an element at any position of
the list.
Algorithm
1. START
2. Iterate until find the current node at position in the list.
3. Assign the adjacent node of current node in the list
Figure 6: Deletion at a given node
to its previous node.
4. END
Stack is considered a complex data structure because it uses other data structures for
implementation, such as Arrays, Linked lists, etc.
Stack Representation
A stack allows all data operations at one end only. At any given time, we can only access
the top element of a stack.
The following diagram depicts a stack and its operations
A stack can be implemented by means of Array, Structure, Pointer, and Linked List. Stack can
either be a fixed size one or it may have a sense of dynamic resizing.
Stack operations are usually performed for initialization, usage and, de-initialization of the stack
abstract data type (ADT). The most fundamental operations in the stack ADT include: push(),
pop(), peek(), isFull(), isEmpty(). These are all built-in operations to carry out data
manipulation and to check the status of the stack in a typical programming language.
Stack uses pointers that always point to the topmost element within the stack, hence
called the top pointer.
Stack Insertion: push()
The push() is an operation that inserts elements into the stack. The following is an
algorithm that describes the push() operation in a simpler way
Algorithm
1. Checks if the stack is full.
2. If the stack is full, produces an error and exit.
3. If the stack is not full, increments top to point next
empty space.
4. Adds data element to the stack location, where top
is pointing.
5. Returns success.
Algorithm
1. Checks if the stack is empty.
2. If the stack is empty, produces an error and exit.
3. If the stack is not empty, accesses the data element at
which top is pointing.
4. Decreases the value of top by 1.
5. Returns success.
Algorithm
1. START
2. return the element at the top of the stack
3. END
Algorithm
1. START
2. If the size of the stack is equal to the top position of the stack,
the stack is full. Return 1.
3. Otherwise, return 0.
4. END
Algorithm
1. START
2. If the top value is -1, the stack is empty. Return 1.
3. Otherwise, return 0.
4. END
A real-world example of queue can be a single-lane one-way road, where the vehicle enters first,
exits first. More real-world examples can be seen as queues at the ticket windows and bus-stops.
Representation of Queues
Similar to the stack Abstract Data Type (ADT), a queue ADT can also be implemented using
arrays, linked lists, or pointers. For better understanding, let us implement queues using a one-
Figure 9: A Queue
dimensional array.
The most fundamental operations in the queue ADT include: enqueue(), dequeue(), peek(),
isFull(), isEmpty(). These are all built-in operations (in an object-oriented programming
language) to carry out data manipulation and to check the status of the queue.
Queue uses two pointers - front and rear. The front pointer accesses the data from the
front end (helping in enqueueing) while the rear pointer accesses data from the rear end
(helping in dequeuing).
Algorithm
1. START
2. Check if the queue is empty.
3. If the queue is empty, produce underflow error and exit.
4. If the queue is not empty, access the data where front
is pointing.
5. Increment front pointer to point to the next available
data element.
Algorithm
1. START
2. Return the element at the front of the queue
3. END
Algorithm
1. START
2. If the count of queue elements equals the queue size,
return true
3. Otherwise, return false
4. END
Algorithm
1. START
2. If the count of queue elements equals zero, return true
3. Otherwise, return false
4. END
Therefore, a heap can be of two types: Min-heap and max-Heap. For example, suppose we have
the following sequence of data: 35 33 42 10 14 19 27 44 26 31
Min-Heap - Where the value of the root node is less than or equal to either of its children.
Max-Heap - Where the value of the root node is greater than or equal to either of its children.
The trees are constructed using the input and order of arrival.
Hash Table uses an array as a storage medium and uses hash technique to generate an index
where an element is to be inserted or is to be located from.
Hashing
Hashing is a technique to convert a range of key values into a range of indexes of an array. We're
going to use modulo operator to get a range of key values. Consider an example of hash table of
size 20, and the following items are to be stored. Item are in the (key,value) format.
For example, given the following (key, value) pairs of number sequence:
Linear Probing
Note that, the hashing technique generated an already used array index of the array. In such a
case, the next available location in the array is used searched and used, this technique is called
linear probing. Our array index table now becomes:
Basic Operations:
The following operations can be performed on a hash table:
To implement a hash table, define or create a pair of data item and a key value; then specify a
hashing function (e.g. modulo or any other arithmetic computation) to compute the array index.
Search Operation
Whenever an element is to be searched, compute the hash code of the key given and locate the
element using that hash code as index in the array. Use linear probing to get the element ahead if
the element is not found at the computed hash code.
Insert Operation
Whenever an element is to be inserted, compute the hash code of the key passed and locate the
index using that hash code as an index in the array. Use linear probing for empty location, if an
element is found at the computed hash code.
Delete Operation
Whenever an element is to be deleted, compute the hash code of the key passed and locate the
index using that hash code as an index in the array. Use linear probing to get the element ahead if
an element is not found at the computed hash code. When found, store a dummy item there to
keep the performance of the hash table intact.
7. Graph Data Structure
A graph data structure consists of a set of objects that are connected to each other via links. The
interconnected objects are represented by points termed as vertices, and the links that connect
the vertices are called edges.
Figure 13:A Graph Data Structure
Formally, a graph is a pair of sets (V, E), where V is the set of vertices and E is the set of edges,
connecting the pairs of vertices. Take a look at the following graph
Vertex - Each node of the graph is represented as a vertex. In the following example, the labeled
circle represents vertices. Thus, A to G are vertices. We can represent them using an array as
shown in the following image. Here A can be identified by index 0. B can be identified using
index 1 and so on.
Edge - Edge represents a path between two vertices or a line between two vertices. In the
following example, the lines from A to B, B to C, and so on represents edges. We can use a two-
dimensional array to represent an array as shown in the following image. Here AB can be
represented as 1 at row 0, column 1, BC as 1 at row 1, column 2 and so on, keeping other
combinations as 0.
Adjacency - Two node or vertices are adjacent if they are connected to each other through an
edge. In the following example, B is adjacent to A, C is adjacent to B, and so on.
Path - Path represents a sequence of edges between the two vertices. In the following example,
ABCD represents a path from A to D.
Operations of Graphs
The primary operations of a graph include creating a graph with vertices and edges, and
displaying the said graph. However, one of the most common and popular operation performed
using graphs are Traversal, i.e. visiting every vertex of the graph in a specific order.
The DFS traversal uses the stack data structure to keep track of the unvisited nodes.
The DFS traversal uses the queue data structure to keep track of the unvisited nodes.
Representation of Graphs
While representing graphs, we must carefully depict the elements (vertices and edges) present in
the graph and the relationship between them. Pictorially, a graph is represented with a finite set
of nodes and connecting links between them. However, we can also represent the graph in other
most commonly used ways, like
Adjacency Matrix
Adjacency List
Adjacency Matrix
The Adjacency Matrix is a V x V matrix
where the values are filled with either 0 or 1. If
the link exists between Vi and Vj, it is
recorded 1; otherwise, 0. For the given graph
below, let us construct an adjacency matrix
Figure 14: Adjacency Matrix
Types of graph
There are two basic types of graph : Directed and Undirected Graphs
from a single node called a root node and has subtrees connected to the root.
Path - Path refers to the sequence of nodes along the edges of a tree.
Root - The node at the top of the tree is called root. There is only one root per tree and one path
from the root node to any node.
Parent - Any node except the root node has one edge upward to a node called parent.
Leaf - The node which does not have any child node is called the leaf node.
Visiting - Visiting refers to checking the value of a node when control is on the node.
Binary Trees
Binary Trees are general trees in which the root node can only hold up to maximum 2 subtrees:
left subtree and right subtree. Based on the number of children, binary trees are divided into three
types.
The data in the Binary Search Trees (BST) is always stored in such a way that the values in the
left subtree are always less than the values in the root node and the values in the right subtree are
always greater than the values in the root node, i.e. left subtree < root node right subtree.
Tree Traversal
Traversal is a process to visit all the nodes of a tree. Since all nodes are connected via edges
(links) we always start from the root (head) node. Tress are traversed in three ways.
i. In-order Traversal
ii. Pre-order Traversal
iii.
Post-order Traversal
In-order Traversal
In this traversal method, the left subtree is visited first, then the root and later the right sub-tree
(L,Rt,R). We should always remember that every node may represent a subtree itself. If a binary
tree is traversed in-order, the output will produce sorted key values in an ascending order.
We start from A, and following in-order traversal, we move to its left subtree B.B is also
traversed in-order. The process goes on until all the nodes are visited. The output of inorder
traversal of this tree will be - D B Figure
E A F19:CInorder
G Traversal
Pre-order Traversal
The root node is visited first, then the left subtree and finally the right subtree (R t, L,R).
We start from A, and following pre-order traversal,
we first visit A itself and then move
to its left subtree B. B is also traversed pre-order. The
process goes on until all the
nodes are visited. The output of pre-order traversal of
this tree will be -
A→B→D→E→C →F→G
The way to write arithmetic expression is known as a notation. An arithmetic expression can be
written in three different but equivalent notations, i.e., without changing the essence or output of
Figure 21: Post-order Traversal
an expression. These notations are – Infix Notation, Prefix (Polish) Notation, and Postfix
(Reverse-Polish) Notation.
Infix Notation
We write expression in infix notation, e.g. a - b + c, where operators are used in-between
operands. It is easy for us humans to read, write, and speak in infix notation but the same does
not go well with computing devices. An algorithm to process infix notation could be difficult and
costly in terms of time and space consumption.
Prefix Notation
In this notation, operator is prefixed to operands, i.e. operator is written ahead of operands. For
example, +ab. This is equivalent to its infix notation a + b. Prefix notation is also known as
Polish Notation
Postfix Notation
This notation style is known as Reversed Polish Notation. In this notation style, the
operator is postfixed to the operands i.e., the operator is written after the operands. For
example, ab+. This is equivalent to its infix notation a + b.
(a + b) ∗ c ∗+abc ab+c∗
1 a+b +ab ab+
a ∗ (b + c) ∗a+bc abc+∗
2
9. 3 Matrix Data
(a + b) ∗ (c + d) ∗+ab+cd ab+cd+∗
4 a/b+c/d +/ab/cd ab/cd/+ Structure
Matrices can be used in various applications, such as image processing, data analysis, and
machine learning.
If the matrix has m rows and n columns, there are m n elements. The matrix is represented by
uppercase letters (in this case, "A"), and the elements in the matrix are represented by lowercase
letters and two subscripts that represent the positions of the elements in the same order, e.g. a m,n
Types of Matrices in Data Structure
There are many types of matrices, which are basically categorized based on element values,
order, number of rows and columns, and so on. There are different types of matrices in linear
algebra. All types of matrices are distinguished based on their elements, order, and specific
conditions.
Special types of matrices are square, diagonal, identity, translocations, and symmetric matrices.
This is a square matrix with the same number of rows and columns.
Row Matrix: If a matrix has only one row, it is called a row matrix. 1 2 3 4
Column Matrix: If a matrix has only one column, it is called a column matrix.
1
2
3
4
Square Matrix: If the number of rows and columns in a matrix is the same, e.g. 2x2 , 3x3, etc.
4 5 8
2 7 0
6 9 1
Identity Matrix : If the diagonal elements of a square matrix are 1 and all other elements are 0.
1 0 0
0 1 0
0 0 1
Other forms of matrices can also be defined such as Triangular Matrix diagonal, symmetric and
scalar.
Operations on Matrices
Traversal - Traversing a matrix means visiting each element in the matrix exactly once. This
can be done using nested loops to iterate over each row and column in the matrix.
Search - Searching for an element in a matrix involves finding the position of a specific element
in the matrix. This can be done by traversing the matrix and comparing each element with the
target element.
The traversal and search of elements in matrix can be carried out in row-order (i.e. iterating row
first) or column order (i.e. iterating column first).
Application of Matrices
Image processing -
Matrices are used for images. let's say we have an image of 100x100 pixels, then the image can
be represented as a 100x100 matrix where each element represents the color of a pixel. Matrices
can be used to perform operations such as scaling, rotation, and filtering on images.
Data analysis -
It is also used for data analysis. Imagine we have a data set with multiple features, then the data
set can be represented as a matrix where each row represents a data point and each column
represents a feature. E.g. Name, Matric No,, Course, Grade, etc.
Other application areas of matrices are in scientific computing of mathematical numerical
analysis such as integration, differentiation, computer graphics (for representing 3-D images) and
machine learning.
Garbage collection
The automatic process of making space in computer’s memory by removing data that is no
longer required or in use.
T.Qx: Discuss any five types of Garbage collection.
Storage management