Download as pdf or txt
Download as pdf or txt
You are on page 1of 16

What is Data Structure?

A data structure serves as a foundational framework for efficiently organizing and


managing data within a computer system. It encompasses both the conceptual
representation of data and its practical implementation in computer programs,
ensuring that information can be accessed, manipulated, and utilized effectively.
Why do we need to Learn Data Structures?

• Increasing Complexity and Data Volume:


o Modern applications face growing complexity and larger data volumes.
o This leads to challenges in tasks such as data searching, processing
speed, and handling multiple requests.
• Role of Data Structures:
o Data Structures offer diverse methods for efficiently managing, organizing,
and storing data.
o They facilitate easy traversal of data items, aiding in effective data
handling.
• Benefits Provided by Data Structures:
o Efficiency: Enhances performance by optimizing data operations,
improving processing speed, and reducing resource consumption.
o Reusability: Structures can be utilized across various applications, saving
development time and resources.
o Abstraction: Allows users to focus on high-level concepts without worrying
about implementation details, enhancing ease of use and understanding.

Types of Data Structure


Primitive data structure

The primitive data structure, also referred to as built-in data types, can only store data
of a single type. This includes integers, floating points, characters, pointers, and similar
types.

Non-Primitive Data Structure

Non-primitive data structures, unlike their primitive counterparts, can store data of
multiple types. Examples include arrays, linked lists, stacks, queues, trees, and
graphs. These are often termed derived data types.

What is Linear Data Structure?

Introduction to Linear Data Structure

A linear data structure is one in which data items are ordered sequentially or linearly,
with each member attached to its previous and next neighboring elements.
Since the data elements are stored in a linear fashion, the structure allows single-level
data storage. As a result, traversal of the data is accomplished in a single run. Memory
is not efficiently utilized in a linear data structure.

Characteristics of Linear Data Structure

The linear data structure has the following characteristics:

• It's a data structure that stores and manages data in a linear order.
• The sequence's data elements are linked to one another in sequential order.
• Since data is organized sequentially, implementing the linear structure in a
computer's memory is simple.
• Since the data elements are stored in a single level, traversing them in a single
run is possible.
• If a structure for storing data linearly is implemented, the computer's memory
will be underutilized.
• The time complexity of a data structure increases with increase in the size of the
data structure.

List of data structure in a linear type of data structure

different types of the linear data structures are:

• Arrays
• Linked List
• Stack
• Queue

Array

The array is the linear data structure that is a collection of similar data items stored at
contiguous memory locations. The elements of the array are stored in one memory
block for the entire array.

Now let's understand the properties of array that are as follows:

• In an array, elements are stored in a contiguous manner.


• The elements inside the array can be accessed in constant time.
• The time complexity of searching an element inside an array will be proportional
to the size of the array in the worst case i.e. O(size of the array).
• The element can be inserted at the end of a dynamic array in O(1) time. But to
insert the element in the beginning or in the middle we need to shift the element
towards the right to create a space. So, the time complexity will be proportional
to the size of the array i.e. O (size of the array).
• The element can be deleted from the end in O(1) time. But to delete the element
from the beginning or from the middle the time complexity will be proportional to
the size of the array i.e. O (size of the array).

Linked List

A linked list is the linear data structure made up of nodes, each of which has a data
field and a connection to the next node in the list. The first node is pointed to by the
head pointer, and the last element points to NULL marking the end of the linked list as
shown in below figure.

NOTE: The head pointer points to null when the list is empty

These are the following types of Linked List:

1. Singly Linked List: It consists of a series of a structure called nodes and each
node contain data part and pointer to the next node in the linked list therefore it
allows traversal in a single direction.

2. Doubly Linked List: In this type of linked list, a node contains a pointer to the
previous as well as the next node in the sequence i.e. in a doubly-linked list, a
node consists of three parts: data, a pointer to the next node in the sequence,
and a pointer to the previous node. The advantage of this type of linked list is that
we can traverse in both directions.
3. Circular Linked List: Each node in a singly-circularly-linked list contains one
link, just like in a regular singly-linked list, except the last node's next link points
back to the first node. Thus circular linked list do not have ends i.e. every node
points to its next node in the sequence but the last node points to the first node in
the list.

Properties of Linked List:

Now let's understand the important properties of linked list:

• To access the particular element in the linked list we have to traverse nodes
starting from the first one to the last one. So in the worst-case time complexity of
accessing an element in the linked list is O(n), where 'n' can be assumed as the
size of the linked list.
• To search for the element in the linked list we have to traverse all the nodes in the
worst case. So the time complexity of searching an element inside linked list
is O(n).
• We can insert an element in the linked list at the start or at the end or at any given
position but the time complexity will varies accordingly. Inserting a node, in the
beginning, will take O(1) time because we need to modify only two pointers. But
inserting a node at any particular position will take O(n) time because in the worst
case we may need to insert a node at the end of the linked list.
• The time complexity of the delete operation in the linked list will be O(n) for
scanning the list of size n to search for the particular element to be deleted.

Stack

A stack is a simple data structure used for storing data. A pile of plates in a cafeteria is
a good example of a stack. The piles are added to the stack as they are cleared and
they are placed on the top. When a plate is needed, it is taken from the stack's top. The
first plate on the stack is the last one to be used.

A stack is an ordered list in which insertion and deletion are performed at one end,
which is referred to as the top. The first element to be eliminated is the last one that
was entered. As a result, it's known as the Last in First Out (LIFO). When an element is
inserted in a stack, the concept is called push and when the element is removed from
the stack, the concept is called pop. Trying to pop out an empty stack is called
underflow and trying to push an element in a full stack is called overflow.

There are the following operations that can be performed on the stack(For
simplicity, assume the data is an integer type):

• void push(int data): Data can be inserted from the top of the stack. The time
complexity of this operation is O(1).
• int pop(): This operation is used to remove the last inserted element from the top
of the stack. The time complexity of this operation is O(1).
• int top(): This operation is used to return the last element without removing it. The
time complexity of this operation is O(1).
• int size(): This operation is used to return the number of elements stored in the
stack. The time complexity of this operation is O(1).
• int isEmpty(): It is used to indicate whether any elements are stored in the stack
or not. The time complexity of this operation is O(1).

Queue

A queue is another linear data structure that is used for storing data. In the queue, the
order in which data arrives is important. In general, a queue is a line of people or things
to be served in sequential order starting at the beginning of the line or sequence.
A queue is an ordered list in which insertions are done at one end i.e. rear end and
deletions are done at the other end i.e. front end. The first element to be added is also
the first to be removed. As a result, it's known as "First in, First out" (FIFO).

The two changes that can be made to a queue are given special names, similar to
Stacks. The concept of EnQueue is used when an element is added to a queue,
and DeQueue is used when an element is deleted from the queue. Underflow refers to
dequeuing an element from an empty queue, while overflow refers to enqueuing an
element from a filled queue.

There are the following operations that can be performed on the queue(For
simplicity, assume the data is an integer type):

• void enQueue(int data): This operation is used for inserting an element in the
queue at the rear end. The time complexity for this operation is O(1).
• int deQueue(): It is used to remove and return the element from the front of the
queue. It will take O(1) time.
• int front(): It returns the element at the front without removing it. The time
complexity for this operation is O(1).
• int rear(): It returns the element at the rear without removing it. The time
complexity for this operation is O(1).
• int size(): It returns the number of elements stored in the queue. The time
complexity for this operation is O(1).
• int isEmpty(): It indicates whether no elements are present in the queue or not.
The time complexity for this operation is O(1).
Abstract Data Type in Data Structure

An Abstract Data Type (ADT) is a programming concept that defines a high-level view of
a data structure, without specifying the implementation details. In other words, it is a
blueprint for creating a data structure that defines the behavior and interface of the
structure, without specifying how it is implemented.

An ADT in the data structure can be thought of as a set of operations that can be
performed on a set of values. This set of operations actually defines the behavior of the
data structure, and they are used to manipulate the data in a way that suits the needs
of the program.

ADTs are often used to abstract away the complexity of a data structure and to provide
a simple and intuitive interface for accessing and manipulating the data. This makes it
easier for programmers to reason about the data structure, and to use it correctly in
their programs.

Examples of abstract data type in data structures are List, Stack, Queue, etc.

Abstract Data Type Model

List ADT

Lists are linear data structures that hold data in a non-continuous structure. The list is
made up of data storage containers known as "nodes." These nodes are linked to one
another, which means that each node contains the address of another block. All of the
nodes are thus connected to one another via these links. You can discover more about
lists in this article: Linked List Data Structure.
Some of the most essential operations defined in List ADT are listed below.

• front(): returns the value of the node present at the front of the list.

• back(): returns the value of the node present at the back of the list.

• push_front(int val): creates a pointer with value = val and keeps this pointer to
the front of the linked list.

• push_back(int val): creates a pointer with value = val and keeps this pointer to
the back of the linked list.

• pop_front(): removes the front node from the list.

• pop_back(): removes the last node from the list.

• empty(): returns true if the list is empty, otherwise returns false.

• size(): returns the number of nodes that are present in the list.

Stack ADT

A stack is a linear data structure that only allows data to be accessed from the top. It
simply has two operations: push (to insert data to the top of the stack) and pop (to
remove data from the stack). (used to remove data from the stack top).
Some of the most essential operations defined in Stack ADT are listed below.

• top(): returns the value of the node present at the top of the stack.

• push(int val): creates a node with value = val and puts it at the stack top.

• pop(): removes the node from the top of the stack.

• empty(): returns true if the stack is empty, otherwise returns false.

• size(): returns the number of nodes that are present in the stack.

Queue ADT

A queue is a linear data structure that allows data to be accessed from both ends.
There are two main operations in the queue: push (this operation inserts data to the
back of the queue) and pop (this operation is used to remove data from the front of the
queue).

Some of the most essential operations defined in Queue ADT are listed below.

• front(): returns the value of the node present at the front of the queue.
• back(): returns the value of the node present at the back of the queue.

• push(int val): creates a node with value = val and puts it at the front of the queue.

• pop(): removes the node from the rear of the queue.

• empty(): returns true if the queue is empty, otherwise returns false.

• size(): returns the number of nodes that are present in the queue.

Advantages of ADT in Data Structures

The advantages of ADT in Data Structures are:

• Provides abstraction, which simplifies the complexity of the data structure and
allows users to focus on the functionality.

• Enhances program modularity by allowing the data structure implementation to


be separate from the rest of the program.

• Enables code reusability as the same data structure can be used in multiple
programs with the same interface.

• Promotes the concept of data hiding by encapsulating data and operations into a
single unit, which enhances security and control over the data.

• Supports polymorphism, which allows the same interface to be used with


different underlying data structures, providing flexibility and adaptability to
changing requirements.

Searching Techniques:
1. Linear Search
2. Binary Search
Implementation:-

• Step 1- Take array input and calculate the number of elements in the array call
this as arr[]
• Step 2- Take the input for the item to be searched in the array. Call this as item
• Step 3- Linearly traverse the array using a for loop.
• Step 4 – For each array item check if arr[i] == item
o If such condition is met print value and its position and return to the main
function
o If no such element is found and the whole array is traversed. Print not found

C Code:-
#include <stdio.h>

void LinearSearch(int arr[], int len, int item)


{
for(int i=0;i < len;i++)
{
if(arr[i] == item)
{
printf("%d Found at index %d", item, i);
return;
}
}
printf("Not Found");
}

int main()
{
int arr[] = {10, 20, 30, 40, 50};

// calculating length of array


int len = sizeof(arr)/sizeof(arr[0]);

// item to be searched
int item = 40;
LinearSearch(arr, len, item);

return 0;
}
Output:-
40 Found at index 3

More about Linear Search


Pros
1.Very easy to understand and implement
2.Quick to write the code
3.Ideal for Unsorted array
4.Ideal for Array with lesser number of items
Cons
1.Time complexity is bad O(n).
2.Binary Search gives better, efficient and faster results.
Binary Search in C
Binary search is a very fast and efficient searching algorithm. It requires to be list be in
sorted order, ie; either in ascending or descending.
Lets have a look at binary search below –
How Binary Search in C works?

1. The array needs to be sorted in either ascending or descending order


2. In our case we are taking an example for an array sorted in ascending order.
3. The searching algorithm proceed from any of two halves
4. Depends upon whether the element you are searching is greater or smaller than
the central element
5. If the element is small then, searching is done in first half
6. If it is big then searching is done in second half.
It is fast search algorithm with the complexity of O(log n).

Implementation of Binary Search

• Take a sorted array (mandatory)


• Find mid using formula m = (l+r)/2
• If the item to be searched is greater than mid
o Check the right subarray
• If the item to be searched is lesser than the mid
o Check the left subarray
• If mid element == item return with the position where found
• Else keep doing the above steps until you violate the bounds of the array
Sorting Techniques:

Bubble Sort in C

1.Sorting is the process of arranging the data in some logical order. Bubble sort is an
algorithm to sort various linear data structures.
2.The logical order can be ascending and descending in the case of numeric values or
dictionary order in the case of alphanumeric values.
3.Bubble Sort is a very simple and easy to implement sorting technique.
4.In the bubble sort technique, each pair of element is compared.
5.Elements are swapped if they are not in order.
6.The worst-case complexity of bubble sort is O(n2).

Implementation of Bubble Sort


The algorithm works on the principle (For ascending order)

• Linearly traverse an array


• Start from the leftmost item

• If left item is greater than its right item swap them

That is arr[i] > arr[i+1] swap them

Let’s take an example, we have a list of number stored in array

Pass 1

• ( 28 6 4 2 24 ) -> ( 6 28 4 2 24 ) : Swapped 28 & 6 since 28 > 6


• ( 6 28 4 2 24 ) -> ( 6 4 28 2 24 ) : Swapped 28 & 4 since 28 > 4
• ( 6 4 28 2 24 ) -> ( 6 4 2 28 24 ) : Swapped 28 & 2 since 28 > 2
• ( 6 4 2 28 24 ) -> ( 6 4 2 24 28 ) : Swapped 28 & 24 since 28 > 24
As you can see in pass 1 we got the largest element at the end of the array so that part
is already sorted. Which is why its called bubble sort

• Like in a soda drink the largest bubble traverse to the stop first
• Here the largest item traversed to right first.

Code:
#include <stdio.h>

// Function to print array


void display(int arr[], int size)
{
int i;
for (i=0; i < size; i++)
printf("%d ", arr[i]);
printf("\n");
}

// Main function to run the program


int main()
{
int array[] = {5, 3, 1, 9, 8, 2, 4,7};
int size = sizeof(array)/sizeof(array[0]);

printf("Before bubble sort: \n");


display(array, size);

int i, j, temp;
for (i = 0; i < size-1; i++){

// Since, after each iteration right-most i elements are sorted


for (j = 0; j < size-i-1; j++)
if (array[j] > array[j+1])
{
temp = array[j]; // swap the element
array[j] = array[j+1];
array[j+1] = temp;
}
}
printf("After bubble sort: \n");
display(array, size);
return 0;
}
Output
After Sorted Element List
Before bubble sort
53198247
After bubble sort:
12345789

You might also like