0% found this document useful (0 votes)
30 views

Introduction

Uploaded by

Ak221197
Copyright
© © All Rights Reserved
Available Formats
Download as PDF, TXT or read online on Scribd
0% found this document useful (0 votes)
30 views

Introduction

Uploaded by

Ak221197
Copyright
© © All Rights Reserved
Available Formats
Download as PDF, TXT or read online on Scribd
You are on page 1/ 15

Data Structures Notes

by

Farhan Sufyan
Contents

1 Introduction to Data Structures 1


1.1 Data Structure (DS) . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1
1.2 Abstract Data Types (ADT) . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 2
1.2.1 List ADT . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 2
1.2.2 Stack ADT . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 2
1.2.3 Queue ADT . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 3
1.3 Data Structures vs Abstract Data Types . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 3
1.4 Advantages of the Data Structures . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 4
1.5 Operations on Data Structures . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 4
1.6 Classification of Data Structures . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 5
1.7 Algorithm . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 7
1.7.1 Analysis of algorithms . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 7
1.7.2 What Is Complexity? . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 7
1.7.3 Complexities of an Algorithm . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 7
1.7.4 How to calculate f (n)? . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 8
1.7.5 Time Complexities or Asymptotic Notations . . . . . . . . . . . . . . . . . . . . . . . . 9
1.7.5.1 Big Oh Notation, O . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 9
1.7.6 Various Time Complexities . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 11
1.8 Sample Questions . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 13
Chapter 1

Introduction to Data Structures

1.1 Data Structure (DS)


• Data Structure (DS) is a systematic way of organizing data in a computer so that it can be used effectively.
• The idea is to reduce the space and time complexities while performing data operations like Searching,
Sorting, Insertion, Updation, Deletion.
• DS is a representation of the logical relationship existing between the individual elements of the data.

• Mathematical or Logical model of particular organization of the data items.


• DS sometimes are also referred to as data types.
• DS mainly specifies the following four things:

– Organization of the data


– Accessing Methods
– Degree of Associativity
– Processing alternatives for information
• DS are buildings block of a program, hence selection of the particular data structure depends upon two
things:
– DS must be rich enough in structure to reflect the relationship existing between the data in the real
world.
– DS should be simple enough, so that the data items can be process effectively when required.

Algorithms + Data Structure = Program

1
1.2 Abstract Data Types (ADT)
• ADT is a mathematical model or concept that defines a data type logically.

• ADT specifies a set of data items and collection of operations that can be performed on that data.
• ADT only specify what operations are to be performed on the data but not how these operations will be
implemented.
• ADT does not specify how data will be organized in memory.

• It is called “abstract” because it gives an implementation-independent view. The process of providing only
the essentials and hiding the details is known as abstraction.
• The user of data type does not need to know how that data type is implemented, for example, int, float,
char data types only with the knowledge that these data type can operate without any idea of how they are
implemented. So a user only needs to know what a data type can do, but not how it will be implemented.

1.2.1 List ADT


A list contains elements of the same type arranged in sequential order and following operations can be performed
on the list.

• initialize() - Initialize the list to be empty.

• get() - Return an element from the list at any given position.


• insert() – Insert an element at any position of the list.
• remove() – Remove the first occurrence of any element from a non-empty list.
• removeAt() – Remove the element at a specified location from a non-empty list.

• replace() – Replace an element at any position by another element.


• size() – Return the number of elements in the list.
• isEmpty() – Return true if the list is empty, otherwise return false.

• isFull() – Return true if the list is full, otherwise return false.

1.2.2 Stack ADT


A Stack contains elements of the same type arranged in sequential order. All operations take place at a single end
that is top of the stack and following operations can be performed:

• initialize() - Initialize the stack to be empty.

• push() – Insert an element at one end of the stack called top.


• pop() – Remove and return the element at the top of the stack, if it is not empty.
• peek() – Return the element at the top of the stack without removing it, if the stack is not empty.

• size() – Return the number of elements in the stack.


• isEmpty() – Return true if the stack is empty, otherwise return false.
• isFull() – Return true if the stack is full, otherwise return false.

2
1.2.3 Queue ADT
A Queue contains elements of the same type arranged in sequential order. Operations take place at both ends,
insertion is done at the end and deletion is done at the front. Following operations can be performed:

• initialize() - Initialize the queue to be empty.


• enqueue() – Insert an element at the end of the queue.
• dequeue() – Remove and return the first element of the queue, if the queue is not empty.

• peek() – Return the element of the queue without removing it, if the queue is not empty.
• size() – Return the number of elements in the queue.
• isEmpty() – Return true if the queue is empty, otherwise return false.
• isFull() – Return true if the queue is full, otherwise return false.

1.3 Data Structures vs Abstract Data Types


• DS is a implementation of an ADT.
• ADT is the logical view of the data and operations to manipulate the data. While the DS is the actual
representation of the data and algorithms to manipulate the data.
• ADT tells us what is to be done and DS tells us how to do it.

3
1.4 Advantages of the Data Structures
• Efficiency

– Proper choice of the DS makes our program efficient.


– For example, in case of search operation, organizing data in an array is not efficient. We can use DS
like binary search tree.
• Re-usability

– DS can be implemented and complied into the libraries to be used again and again.
• Abstraction
– The client program use the DS through an interface without getting into the implementation details.
– For example, in case stack, the user can simply use push() and pop() operations. Implementation of the
stack can be changed from array to linked list, the client program work in the same way.

1.5 Operations on Data Structures


• Traversing: Traversing means visiting each element of the data structure only once.
• Insertion: Insertion can be defined as the process of adding the new element to the DS at any location. If the
size of data structure is n then we can only insert (n-1) data elements into it.

• Deletion: The process of removing an element from the data structure is called deletion. We can delete an
element from the data structure at any location. If we try to delete an element from an empty data structure
then underflow occurs.
• Searching: The process of finding the location of an element within the data structure is called Searching.
• Sorting: The process of arranging the elements in the data structure in some logical order is known as
Sorting.
• Merging: Combining the records in two different sorted files into single sorted file.

4
1.6 Classification of Data Structures

Figure 1.1: Data Structure Classification

(a) Primitive and Non-Primitive DS


• Primitive DS
– These are basic DS that are directly operated by the machine instructions.
– Primitive DS are also called atomic or fundamental DS.
– Pre-Defined by the programming language.
– For eg- int, float, char, pointer, boolean, etc.
• Non-Primitive DS
– These are sophisticated DS derived from the primitive DS, that’s why they are also called derived
DS.
– Non-Primitive DS refers to object and hence they are also called reference types.
– Non-Primitive data types emphasize on grouping of homogeneous (same) or heterogeneous
(different) data items.
– For eg- Array, Linked-List, Trees, Graphs, etc.

5
(b) Linear and Non-Linear DS
• Linear DS
– A DS is said to be linear if its elements form a sequence or linear order.
– One way to have a linear relationship between the elements represented by means of sequential
memory locations (eg- Array).
– Another way is to have the linear relationship between the elements represented by the means of
pointer or links (eg- Linked List).
– In linear DS, each element has only one successor and one predecessor, except first and last
element.
– In linear DS, single-level is involved, therefore all the elements can be traversed in a single run.
– Easy to implement.
– eg- String, Array, Stack, Queues.
• Non-Linear DS
– In Non-Linear DS there is no linear order in the arrangements of the elements.
– Elements in non-linear DS are attached in hierarchical manner.
– Non-Linear DS is the multi-level and are not easy to implement.
– Cannot traverse all the elements of DS in a single run.
– Utilize computer memory efficiency in comparison to linear DS.
– eg- Trees, Graph, Files.
(c) Static and Dynamic DS

• Static DS
– In static DS, the size of the structure is fixed, the memory is allocated at compilation time only
and can’t be changed at run time.
– The content of the DS can be modified but without changing the memory space allocated to it.
– Static DS allows faster access to elements but insertion and deletion is expensive.
– eg- Array.
• Dynamic DS
– In Dynamic DS, the memory is located at run-time. Therefore, these DS are flexible in size and
can be modified during the operation performed on it in the run-time.
– Efficient with respect to the memory complexity of the code.
– Dynamic DS allows fast insertion and deletion of the elements but access to elements is slow.
– eg- Linked-List.

6
1.7 Algorithm
An algorithm is defined as a well-defined list of steps for solving a problem. Each step of an algorithm will have a
clear meaning and can be performed with a finite amount of effort and finite length of time. Every algorithm must
satisfy the following criteria,

• Inputs: Zero or more quantities which are externally supplied to the algorithm.
• Output: At least one quantity is produced as output.
• Definiteness: Each step must be clear and unambiguous.
• Finiteness: All steps for all cases of an algorithm will terminate after a finite amount of time.

• Effectiveness: The algorithm will be efficient.

1.7.1 Analysis of algorithms


Analysis of the algorithm is the process of analyzing the problem-solving capability of the algorithm in terms of
the time and space required. Time is measured by counting the number of operations and space is measured by
counting the maximum amount of memory consumed by the algorithm while implementation.

1.7.2 What Is Complexity?


Complexity measures how the resources (in this example, time) fluctuate as the problem grows in size. An algorithm
may run quickly and show no time difference, but when the input size rises, the program may take longer to execute,
become sluggish, and perform poorly; here is the concept complexity is assessed.

1.7.3 Complexities of an Algorithm


• The complexity of an algorithm is expressed as a function of input size which gives running time and or
space. In other words, the complexity of an algorithm computes the amount of time and spaces required by
an algorithm for an input of size (n).

• An algorithm’s time complexity specifies how long it will take to execute an algorithm as a function of its
input size.
• Similarly, an algorithm’s space complexity specifies the total amount of space or memory required to execute
an algorithm as a function of the size of the input.

• The complexity of an algorithm can be divided into two types:


– Time complexity
– Space complexity
• As we know that data structure is a way of organizing the data efficiently and that efficiency is measured
either in terms of time or space. So, the ideal data structure is a structure that occupies the least possible time
to perform all its operation and the memory space.
• Our focus would be on finding the time complexity rather than space complexity, and by finding the time
complexity, we can decide which data structure is the best for an algorithm. Hence, the main concern of the
analysis of the algorithm is the required time or performance.

• Suppose we have an array of 100 elements, and we want to insert a new element at the beginning of the list.
A List can be implemented using the Array or Linked List

– This becomes a very tedious task in case of array, as we first need to shift the elements towards the
right, and we will add new element at the starting of the array.
– Hence, for inserting a new element at the beginning of requires shifting 100 elements in an array, then
it takes 100 units of time to shift. It concludes that time complexity depends upon the input size.
Therefore, if the input size is n, then f(n) is a function of n that denotes the time complexity.

7
– Suppose we consider the linked list as a data structure to add the element at the beginning. The linked
list contains two parts, i.e., data and address of the next node. We simply add the address of the first
node in the new node, and head pointer will now point to the newly added node.
– Therefore, we conclude that adding the data at the beginning of the linked list is faster than the arrays.
In this way, we can compare the data structures and select the best possible data structure for performing
the operations.

1.7.4 How to calculate f (n)?

8
1.7.5 Time Complexities or Asymptotic Notations
• In complexity theory, we find complexity f(n) for three major cases as follows:

– Worst case - O - Big OH


– Average case - Θ - Theta
– Best case - Ω - Omega

1.7.5.1 Big Oh Notation, O

• Big–O notation considers asymptotic algorithm behavior. The notation tells clearly how the algorithm scales
when input size increases. This is often called the order of growth.
• In theoretical terms, Big –O notation is used to examine the performance/complexity of an algorithm.

• Big –O notation examines an algorithm’s upper bound of performance. It measures the worst case time
complexity or the longest amount of time an algorithm can possibly take to complete.

• This implies that f (n) does not grow faster than g(n), or g(n) is an upper bound on the function f (n). In this
case, we are calculating the growth rate of the function which eventually calculates the worst time complexity
of a function, i.e., how worst an algorithm can perform.

9
10
1.7.6 Various Time Complexities
1. Constant time complexity - O(1)
• When your algorithm is not dependent on the input size n, it is said to have a constant time complexity
with order O(1). This means that the run time will always be the same regardless of the input size.
• For example, if an algorithm is to return the first element of an array. Even if the array has 1 million
elements, the time complexity will be constant if you use this approach:
2. Logarithmic time complexity - O(logn)
• A method with a logarithmic complexity (where n is really big) divides the issue into little bits for each
iteration (log n). It takes log(N) steps to execute a particular operation on N items.
• This method is the second best because your program runs for half the input size rather than the full
size. After all, the input size decreases with each iteration.
• For N = 1, 000, 000, an algorithm that has a complexity of O(log(N)) would undergo 20 steps (with a
constant precision). Here, the logarithmic base does not hold a necessary consequence for the operation
count order, so it is usually omitted.
• For example, Binary Search
3. Linear time complexity - O(n)
• When an algorithm executes n steps for input size n (where n is very large) and the time consumed by
the process changes linearly as the input size rises, the algorithm is said to have complexity O(n).
• To execute an operation on N items it takes about the same number of steps as the number of elements.
• Linear complexity denotes a relationship between the number of components and the number of steps.

• For example, Linear Search
4. Log-Linear time complexity - O(nlogn)

• An algorithm with an O(nlogn) complexity (where n is really big) divides the issue into little chunks
for each invocation, then takes each of the smallest bits and stitches them back together (n log n).
Executing a given operation on N items takes N ∗ log(N) steps.
• For a given 1000 elements, the Log-linear time complexity will execute 10, 000 steps for solving a
given problem.

5. Quadratic time complexity - O(n2 ) or Polynomial time complexity - O(nk )


• In this type of algorithms, the time it takes to run grows directly proportional to the square of the size
of the input.
• In most scenarios and particularly for large data sets, algorithms with quadratic time complexities take
a lot of time to execute and should be avoided.
• Nested For Loops run on quadratic time, because you’re running a linear operation within another linear
operation, or n*n which equals n².
• If you face these types of algorithms, you’ll either need a lot of resources and time, or you’ll need to
come up with a better algorithm.
• Bubble sort
6. Exponential time complexity - O(2n )
• In exponential time algorithms, the growth rate doubles with each addition to the input (n), often
iterating through all subsets of the input elements. Any time an input unit increases by 1, it causes you
to double the number of operations performed.
• For example, if N = 10, then the exponential function 2N will result in 1024. Similarly, if N = 20, it
will result in 1048 576, and if N = 100, it will result in a number having 30 digits.
• Brute-Force algorithms

11
7. Factorial time complexity - O(N!)
• The exponential function N! grows even faster; for example, if N = 5 will result in 120. Likewise, if
N = 10, it will result in 3, 628, 800 and so on.
n
8. Double exponential time complexity - O(22 ),

Figure 1.2: Time Complexity Chart

12
1.8 Sample Questions
1. Explain the concepts of data, information, and data structure.

2. Define an algorithm and discuss its key characteristics.


3. Develop a C function to remove duplicate numbers from a linear array.
4. Define algorithm complexity and its significance.
5. Define abstract data type (ADT) and provide a concise explanation.

6. Define data structure and discuss the factors influencing the selection of a specific data structure.
7. Analyze the complexity of a given algorithm represented by the pseudocode below:

Algorithm Sum(a,n)
{
s := 0;
for i = 1 to n do
s = s + a[i];
Return s;
}

8. Describe the stack Abstract Data Type (ADT) and implement it using dynamic memory allocation, including
operations like Insert, Delete, Empty, and Full.
9. Differentiate between primitive and non-primitive data types.

10. Explain the concept of time and space trade-off and define various asymptotic notations used to analyze
algorithm performance.

13

You might also like