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

module2_array&LL

An array is a collection of elements of the same data type stored in contiguous memory locations, allowing access via indices. The document explains single and multi-dimensional arrays, their declarations, initializations, memory representations, and operations such as traversal, insertion, deletion, searching, sorting, and merging. It also discusses parallel arrays and sparse matrices, highlighting their advantages and disadvantages.

Uploaded by

fidhasadik123
Copyright
© © All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as PDF, TXT or read online on Scribd
0% found this document useful (0 votes)
3 views

module2_array&LL

An array is a collection of elements of the same data type stored in contiguous memory locations, allowing access via indices. The document explains single and multi-dimensional arrays, their declarations, initializations, memory representations, and operations such as traversal, insertion, deletion, searching, sorting, and merging. It also discusses parallel arrays and sparse matrices, highlighting their advantages and disadvantages.

Uploaded by

fidhasadik123
Copyright
© © All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as PDF, TXT or read online on Scribd
You are on page 1/ 23

Array

An array is a collection of elements of the same data type, stored in contiguous memory
locations. Arrays allow you to store multiple values of the same type in a single variable, and
you can access the elements using an index. The index of an array starts at 0 and goes up to
(n-1) for an array of size n.

Declaration of Array(single dimension)

int arr[5]; // Declares an array of 5 integers


float arr[5]; // Declares an array of 5 float elements

Initialization of Arrays

int arr[5] = {10, 20, 30, 40, 50};


float arr[] = {1.1, 2.2, 3.3, 4.4, 5.5}; // Size automatically set to 5

Key Points

• Fixed size: Once an array is declared with a specific size, its size cannot be changed.
• Indexing: Array elements are accessed using indices starting from 0.
• Homogeneous elements: All array elements must be the same type.
• Memory layout: Arrays are stored in contiguous blocks of memory.

Single-Dimension Array:

A single-dimension array (or one-dimensional array) is a linear data structure consisting of


a sequence of elements of the same type, stored in contiguous memory locations. It is
essentially a list of elements that can be accessed using a single index.

Example in C:

int arr[5] = {10, 20, 30, 40, 50}; // A single-dimension array of size 5

• Accessing elements: Each element in a one-dimensional array is accessed using its


index, which typically starts from 0.

1
o arr[0] = 10
o arr[1] = 20
o arr[2]=30
o …….
• Use cases: Single-dimension arrays are used when the data can be represented in a
simple linear form, such as a list of integers, names, or marks.

Multi-Dimensional Array:

A multi-dimensional array is an array of arrays. The most commonly used form is the two-
dimensional array, but arrays can have higher dimensions (3D, 4D, etc.). Multi-dimensional
arrays are stored in row-major or column-major order depending on the programming
language.

2D Array Example:

A two-dimensional array can be thought of as a matrix, where each element is accessed using
two indices.

Example in C:

int matrix[3][4] = {
{1, 2, 3, 4},
{5, 6, 7, 8},
{9, 10, 11, 12}
};

• Accessing elements: Each element is accessed using two indices, one for the row and
one for the column.
o matrix[0][0] = 1
o matrix[1][2] = 7
o ……
• Use cases: Multi-dimensional arrays are useful for representing data that has multiple
dimensions, such as:
o A 2D grid (e.g., a chessboard)
o Matrices for mathematical operations
o Tables with rows and columns

Differences

2
Aspect Single-Dimension Array Multi-Dimensional Array
Structure Linear (a list of elements) Matrix-like (array of arrays)
Indexing Single index (e.g., arr[i]) Multiple indices (e.g., arr[i][j])
Memory Stored contiguously in Stored either in row-major or column-major
Layout memory order
Linear data structures (e.g.,
Use cases Tables, matrices, multi-dimensional data
list)

The representation of arrays in memory depends on whether it's a single-dimensional or


multi-dimensional array. Let's explore how each type is stored in memory.

1. Single-Dimension Array Representation

A single-dimensional array is stored in contiguous memory locations. The size of each


element is determined by the data type, and each element is placed directly after the previous
one.

Example:

int arr[5] = {10, 20, 30, 40, 50};

Assume arr starts at memory address 1000, and each integer takes 4 bytes. The memory
layout would look like:

Index (arr[i]) Value Memory Address


arr[0] 10 1000
arr[1] 20 1004
arr[2] 30 1008
arr[3] 40 1012
arr[4] 50 1016

Here, each element is 4 bytes apart, as the integer data type occupies 4 bytes. The memory
address of an element can be calculated as:

Address of arr[i]=Base Address+(i-Lb)×Size of Element


i= Index
Lb= lower bound

In this case:

3
Address of arr[2]=1000+(2-0)×4=1008

2. Multi-Dimensional Array Representation

A multi-dimensional array is stored in memory as a linear sequence of elements. The two


most common ways to store multi-dimensional arrays in memory are:

• Row-major order
• Column-major order

2.1. Row-Major Order

In row-major order (used in languages like C/C++), the array is stored row by row in
contiguous memory locations.

Example:

int matrix[3][4] = {
{1, 2, 3, 4},
{5, 6, 7, 8},
{9, 10, 11, 12}
};

Assuming the starting address is 2000, and each integer takes 4 bytes, the memory layout
would look like this (row-major order):

Element (matrix[i][j]) Value Memory Address


matrix[0][0] 1 2000
matrix[0][1] 2 2004
matrix[0][2] 3 2008
matrix[0][3] 4 2012
matrix[1][0] 5 2016
matrix[1][1] 6 2020
matrix[1][2] 7 2024
matrix[1][3] 8 2028
matrix[2][0] 9 2032
matrix[2][1] 10 2036
matrix[2][2] 11 2040
matrix[2][3] 12 2044

• The elements of the first row are stored first, followed by the elements of the second
row, and so on.

Formula to calculate the address of an element in row-major order:

4
Address of matrix[i][j]=Base Address+[((i-Lr)×number of columns)+j]×Size of Element

For matrix[1][2], this would be:

Address of matrix[1][2]=2000+[((1-0)×4)+2]×4=2024

2.2. Column-Major Order

In column-major order (used in languages like Fortran), the array is stored column by column
in contiguous memory locations.

For the same matrix:

c
Copy code
int matrix[3][4] = {
{1, 2, 3, 4},
{5, 6, 7, 8},
{9, 10, 11, 12}
};

The memory layout in column-major order would look like this:

Element (matrix[i][j]) Value Memory Address


matrix[0][0] 1 2000
matrix[1][0] 5 2004
matrix[2][0] 9 2008
matrix[0][1] 2 2012
matrix[1][1] 6 2016
matrix[2][1] 10 2020
matrix[0][2] 3 2024
matrix[1][2] 7 2028
matrix[2][2] 11 2032
matrix[0][3] 4 2036
matrix[1][3] 8 2040
matrix[2][3] 12 2044

Formula to calculate the address of an element in column-major order:

Address of matrix[i][j]=Base Address+[((j-Lc)×number of rows)+i]×Size of Element

5
For matrix[1][2], this would be:

Address of matrix[1][2]=2000+[((2-0)×3)+1]×4=2028

• Single-dimension arrays are stored in contiguous memory, and each element can be
accessed using a single index.
• Multi-dimensional arrays can be stored either in row-major or column-major order,
with elements accessed using multiple indices.

Array Operations

1. Traversal

Traversal involves visiting each element of the array exactly once, usually to display or
process the elements.

Example in C:

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


int n = sizeof(arr)/sizeof(arr[0]);
for (int i = 0; i < n; i++) {
printf("%d ", arr[i]);
}

• Output: 10 20 30 40 50

2. Insertion

Insertion adds a new element at a specified position in the array. If inserting in the middle of
an array, the elements from that position onward need to be shifted to the right.

Example: To insert an element 25 at position 2 in an array:

int arr[6] = {10, 20, 30, 40, 50};


int pos = 2;
int new_elem = 25;
for (int i = 5; i > pos; i--) {
arr[i] = arr[i - 1]; // Shifting elements to the right
}
arr[pos] = new_elem;

6
• Resulting Array: {10, 20, 25, 30, 40, 50}

3. Deletion

Deletion removes an element from a specific position in the array. After deletion, the
elements to the right of the deleted element need to be shifted to the left to fill the gap.

Example: To delete an element at position 3:

int arr[5] = {10, 20, 30, 40, 50};


int pos = 3;
for (int i = pos; i < 4; i++) {
arr[i] = arr[i + 1]; // Shifting elements to the left
}

• Resulting Array: {10, 20, 30, 50}

4. Searching

Searching involves finding the position of a given element in an array. There are two main
types of searching:

• Linear Search: Search for the element by checking each element one by one.
• Binary Search: If the array is sorted, use binary search to find the element more
efficiently.

Search Example:

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


int key = 30;
for (int i = 0; i < 5; i++) {
if (arr[i] == key) {
printf("Element found at index %d\n", i);
break;
}
}

5. Sorting

Sorting is the process of rearranging the elements of the array in a specific order, typically
either ascending or descending. There are several sorting algorithms:

• Bubble Sort: Compare adjacent elements and swap them if they are in the wrong
order.
• Selection Sort: Select the smallest (or largest) element and place it in its correct
position.
• Merge Sort, Quick Sort: More efficient algorithms that follow the divide-and-
conquer strategy.

Sort Example:

7
int arr[] = {50, 20, 40, 10, 30};
int n = sizeof(arr) / sizeof(arr[0]);
for (int i = 0; i < n - 1; i++) {
for (int j = 0; j < n - i - 1; j++) {
if (arr[j] > arr[j + 1]) {
int temp = arr[j];
arr[j] = arr[j + 1];
arr[j + 1] = temp;
}
}
}

• Sorted Array: {10, 20, 30, 40, 50}

6. Merging

Merging involves combining two sorted arrays into a single sorted array.

Example:

int arr1[] = {10, 20, 30};


int arr2[] = {15, 25, 35};
int merged[6];
int i = 0, j = 0, k = 0;
while (i < 3 && j < 3) {
if (arr1[i] < arr2[j]) {
merged[k++] = arr1[i++];
} else {
merged[k++] = arr2[j++];
}
}
while (i < 3) merged[k++] = arr1[i++];
while (j < 3) merged[k++] = arr2[j++];

• Merged Array: {10, 15, 20, 25, 30, 35}

7. Reversing

Reversing an array means arranging the elements in reverse order.

Example:

8
int arr[] = {10, 20, 30, 40, 50};
int n = sizeof(arr) / sizeof(arr[0]);
for (int i = 0; i < n / 2; i++) {
int temp = arr[i];
arr[i] = arr[n - i - 1];
arr[n - i - 1] = temp;
}

• Reversed Array: {50, 40, 30, 20, 10}

8. Updating

Updating involves changing the value of an element at a given position.

Example: To update the value at index 2 to 35:

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


arr[2] = 35;

• Updated Array: {10, 20, 35, 40, 50}

9. Copying

Copying one array into another array involves transferring all elements from one array to
another.

Example:

int arr1[] = {10, 20, 30, 40, 50};


int arr2[5];
for (int i = 0; i < 5; i++) {
arr2[i] = arr1[i];
}

• Copied Array: arr2 = {10, 20, 30, 40, 50}

Parallel arrays (or structure of arrays) refer to a data structure where multiple arrays are
used in parallel, with each array holding a different type of data, but corresponding elements
at the same index across all arrays are logically related. Essentially, parallel arrays store
different attributes of the same entity in different arrays.

char names[3][10] = {"Alice", "Bob", "Charlie"};


int ages[3] = {20, 22, 21};
char grades[3] = {'A', 'B', 'A'};

9
In this example:

• names[i] holds the name of the student at index i.


• ages[i] holds the age of the student at index i.
• grades[i] holds the grade of the student at index i.

So for index 0:

• names[0] = "Alice"
• ages[0] = 20
• grades[0] = 'A'

The values across the arrays at the same index (i) represent different attributes of the same
student.

Advantages:

1. Separation of Data Types: Parallel arrays make it easy to handle different data types
for different attributes of the same entity.
2. Direct Access: Each array stores one type of data, so you can easily access or process
just one aspect of the entity (e.g., names or ages) without affecting the other data.
3. Memory Efficiency: When using low-level languages like C, parallel arrays can be
more memory-efficient than using an array of structures because of more control over
memory alignment and layout.

Disadvantages:

1. Indexing Complexity: You must always ensure that you use the same index across
all arrays to refer to the same entity. If this indexing is not synchronized, it can lead to
logical errors.
2. Lack of Encapsulation: Parallel arrays do not bundle the data for a single entity
together, making it harder to conceptually treat the data as a single object. In object-
oriented programming, a class or structure would be more natural.

Sparse Matrix

A sparse matrix is a matrix in which most of the elements are zero. Sparse matrices are often
encountered in scientific computing, machine learning, graph theory, and other areas where
large datasets are common, but only a small subset of the data is significant (non-zero). Due
to the large number of zero elements, sparse matrices can be efficiently represented and
processed using specialized storage techniques.

Characteristics of a Sparse Matrix:

10
• Most elements are zero: Typically, a matrix is considered sparse if more than half of
its elements are zero.
• Efficient storage: Rather than storing all elements (including the zeros), sparse
matrices use techniques to store only the non-zero elements, leading to significant
memory savings.

Example of a Sparse Matrix:

Copy code
|0 0 0 0 5|
|0 8 0 0 0|
|0 0 0 0 0|
|2 0 0 0 0|

In this 4x5 matrix, only three elements are non-zero. Storing all the zero elements would be
inefficient, especially if the matrix size is large.

Sparse Matrix Representation:

To efficiently represent sparse matrices, the following methods are often used:

1. Coordinate List (COO) Representation:

The COO format stores the non-zero elements and their corresponding row and column
indices.

Example (for the above matrix):

• Values: [5, 8, 2]
• Row indices: [0, 1, 3]
• Column indices: [4, 1, 0]

11
Linked List

Linked list is a linear collection of data elements called nodes. It can be considered as a series
of nodes, with each node storing data as well as the address of the next node.

Linked list Data Structure

Linked lists contain a pointer variable HEAD that stores the address of the first node. Also,
we store NULL in the address part of the last node because it has no next node connected to
it.

Difference between Array and Linked List

Arrays store elements in contiguous memory locations. The size of the array is fixed and
cannot be changed at runtime. We must know the number of elements in advance. Normally
the allocated memory is equal to the upper limit of the array and In practice, however, the
highest limit is rarely attained.

12
In a linked list nodes can exist at non-contiguous addresses. This permits the linked list’s size
to be changed at runtime.

Array elements can be accessed directly with its index. But in the case of a linked list,
random access is not possible. To access any element, all previous items must be traversed.

Inserting and deleting elements in an array is expensive because we have to shift the elements
to preserve the order. Ease of insertion and deletion is a notable advantage of linked lists at
the cost of extra space required for storing the address pointers.

Array Linked List

Data can be only stored in contiguous memory Data can exist at non-contiguous
locations. addresses.

Size is fixed and cannot be altered at runtime. Size can be changed at runtime.

Elements must be accessed


Random access is allowed.
sequentially.

Memory equivalent to upper limit has to be Extra memory required to store


allocated. pointers.

Representation of Linked List

A linked list is a series of nodes in which the address of the first node is stored in a pointer
called HEAD. Each of the nodes in the linked list consists of two parts:

• A data item.
• An address that points to another node.

In C, we can represent nodes using structures as:

struct node

int data;

struct node *next;

};

Each struct node contains a data item as well as a pointer to another struct node. The
following example creates a basic Linked List with three items and displays its elements.

Example: Creating a simple Linked List

#include <stdio.h>

13
#include <stdlib.h>

struct node

int data;

struct node *next;

};

int main()

// Create and initialize nodes

struct node *head;

struct node *one = NULL;

struct node *two = NULL;

struct node *three = NULL;

struct node *current = NULL;

// Allocate memory for the nodes

one = (struct node*) malloc(sizeof(struct node));

two = (struct node*) malloc(sizeof(struct node));

three = (struct node*) malloc(sizeof(struct node));

// Assign data to nodes

one->data = 1;

two->data = 2;

three->data = 3;

// Connect first node

// with the second node

one->next = two;

14
// Connect second node

// with the third node

two->next = three;

// make next pointer of

//third node to NULL

//indicates last node

three->next = NULL;

// Save address of first node in head

head = one;

current = head;

// print the linked list values

while(current != NULL)

printf("%d ", current->data);

current = current->next;

return 0;

Now we’ve made a simple linked list with three nodes.

Linked list representation

Output

123

Applications of Linked List

15
• To implement other data structures such as Queues, Stacks, Trees, Graphs, etc.
• Used for dynamic memory allocation.
• For manipulating polynomials, representing sparse matrice, etc.
• In undo functionality of softwares.
• Previous and next page navigation on web browsers.

Linked List Operations

Like any other data structure, we can perform insertion, deletion and traversal operations in a
linked list. In the next tutorial, let’s learn Algorithms for insertion, deletion and traversal
operations in a linked list.

A doubly linked list or two way linked list is a type of linked list that contains a pointer to
the next node as well as the previous node in the sequence.

A doubly linked list node


That is, each node in a doubly-linked list consists of:
• data
– Data Item.
• prev
– Address of previous node.
• next
– Address of next node.
Representation of Doubly Linked List
In C, we can represent a doubly linked list node using structures as:
struct node
{
struct node *prev;
int data;
struct node *next;
};
Each struct node contains a data item, a pointer to the previous struct node, and a pointer to
the next struct node.
The following example creates a basic Linked List with three items and displays its elements.
Example: Creating a Doubly Linked List
#include <stdio.h>
#include <stdlib.h>
struct node
{
int data;
struct node *next;
struct node *prev;
};
int main()
{
// Create and initialize nodes
struct node *head;

16
struct node *one = NULL;
struct node *two = NULL;
struct node *three = NULL;
struct node *current = NULL;
// Allocate memory for the nodes
one = (struct node*) malloc(sizeof(struct node));
two = (struct node*) malloc(sizeof(struct node));
three = (struct node*) malloc(sizeof(struct node));
// Assign data to nodes
one->data = 1;
two->data = 2;
three->data = 3;
// Connect first node
// with the second node
one->next = two;
// Connect second node
// with the third node
two->next = three;
// make next pointer of
//third node to NULL
//indicates last node
three->next = NULL;
//connect previous nodes
one->prev = NULL;
two->prev = one;
three->prev = two;
// Save address of first node in head
head = one;
current = head;
// print the linked list values forward
while(current != NULL)
{
printf("%d ", current->data);
current = current->next;
}
return 0;
}
Now we’ve made a doubly-linked list with three nodes.

Output
123

17
Circular Linked List

A circular linked list is a type of linked list in which the last node is also connected to the first
node to form a circle. Thus a circular linked list has no end.

Circular Linked List Data Structure


There are two types of linked lists:
• Circular Singly Linked List.
• Circular Doubly Linked List.
Representation of Circular Linked List
Each of the nodes in the linked list consists of two parts:
• A data item.
• An address that points to another node.
A single node can be represented using structure as
struct node {
int data;
struct node *next;
};
Each struct node contains a data item as well as a pointer to another struct node. The
following example creates a Circular Linked List with three items and display its elements.
Example: Creating a Circular Linked List
#include <stdio.h>
#include <stdlib.h>
struct node
{
int data;
struct node *next;
};
int main()
{
// Create and initialize nodes
struct node *head;
struct node *one = NULL;
struct node *two = NULL;
struct node *three = NULL;
struct node *current = NULL;
// Allocate memory for the nodes
one = (struct node*) malloc(sizeof(struct node));
two = (struct node*) malloc(sizeof(struct node));
three = (struct node*) malloc(sizeof(struct node));
// Assign data to nodes

18
one->data = 1;
two->data = 2;
three->data = 3;
// Connect first node
// with the second node
one->next = two;
// Connect second node
// with the third node
two->next = three;
// Connect second node
// with the third node
three->next = one;
// Save address of first node in head
head = one;
current = head;
// print the linked list values
while(current != NULL)
{
printf("%d ", current->data);
current = current->next;
}
return 0;
}
Now we’ve made a circular linked list with three nodes.

Representation of Circular Linked List


Output
123
Inserting a New Node to a Circular Linked List
A new node can be inserted anywhere in a circular linked list. Here, we are discussing the
following cases.
• Inserting a new Node at the beginning of a Circular Linked List.
• Inserting a new Node at the end of a Circular Linked List.
The remaining cases are the same as those described for a singly linked list.
Insert at the beginning of a list
Suppose we want to add a new node with data 24 as the first node in the following linked list.
The following changes will be done in the linked list.

19
• Allocate memory for new node and initialize its DATA part to 24.
• Add the new node as the first node of the list by pointing the NEXT part of the new
node to HEAD.
• Make HEAD to point to the first node of the list.
• Make HEAD point to the new node.
Algorithm: InsertAtBeginning
Step 1: IF AVAIL = NULL
Write OVERFLOW
Go to Step 11
[END OF IF]
Step 2: SET NEW_NODE = AVAIL
Step 3: SET AVAIL = AVAIL NEXT
Step 4: SET NEW_NODE -> DATA = VAL
Step 5: SET PTR = HEAD
Step 6: Repeat Step 7 while PTR -> NEXT != HEAD
Step 7: PTR = PTR -> NEXT
[END OF LOOP]
Step 8: SET NEW_NODE -> NEXT = HEAD
Step 9: SET PTR -> NEXT = NEW_NODE
Step 10: SET HEAD = NEW_NODE
Step 11: EXIT
Note that the first step of the algorithm checks if there is enough memory available to create a
new node. The second, and third steps allocate memory for the new node.
Insert at the end of the list
Suppose we want to add a new node with data 24 as the last node of the following circular
linked list. The following changes have to be made in the linked list.

20
• Allocate memory for the new node and initialize data.
• Traverse to the end of the list.
• Point the NEXT part of the last node to the newly created node.
• Make the value of next part of last node to HEAD.
Algorithm: InsertAtLast
Step 1: IF AVAIL = NULL
Write OVERFLOW
Go to Step 1
[END OF IF]
Step 2: SET NEW_NODE = AVAIL
Step 3: SET AVAIL = AVAIL -> NEXT
Step 4: SET NEW_NODE -> DATA = VAL
Step 5: SET NEW_NODE -> NEXT = HEAD
Step 6: SET PTR = HEAD
Step 7: Repeat Step 8 while PTR -> NEXT != HEAD
Step 8: SET PTR = PTR -> NEXT
[END OF LOOP]
Step 9: SET PTR -> NEXT = NEW_NODE
Step 1 : EXIT
Deleting a Node from a Circular Linked List
Let’s look at how a node is removed from a circular linked list in the following scenarios.
• The first node is deleted.
• The last node is deleted.
The remaining cases are the same as those described for a singly linked list.
Deleting first node from a list
The following changes have to be made to the linked list if we want to remove the first node
having data 24.

21
• Check if the linked list is empty or not. Exit if the list is empty.
• Make HEAD points to the second node.
• Traverse to the end of the list and point the next part of last node to second node.
• Free the first node from memory.
Algorithm: DeleteFirst
Step 1: IF HEAD = NULL
Write UNDERFLOW
Go to Step 8
[END OF IF]
Step 2: SET PTR = HEAD
Step 3: Repeat Step 4 while PTR -> NEXT != HEAD
Step 4: SET PTR = PTR -> NEXT
[END OF LOOP]
Step 5: SET PTR -> NEXT = HEAD -> NEXT
Step 6: FREE HEAD
Step 7: SET HEAD = PTR -> NEXT
Step 8: EXIT
Deleting last node from the list
Suppose we want to delete the last node from the circular linked list. The following changes
will be done in the list.

22
• Traverse to the end of the list.
• Change value of next pointer of second last node to HEAD.
• Free last node from memory.
Algorithm: DeleteFirst
Step 1: IF HEAD = NULL
Write UNDERFLOW
Go to Step 8
[END OF IF]
Step 2: SET PTR = HEAD
Step 3: Repeat Steps 4 and 5 while PTR NEXT != HEAD
Step 4: SET PREPTR = PTR
Step 5: SET PTR = PTR -> NEXT
[END OF LOOP]
Step 6: SET PREPTR -> NEXT = HEAD
Step 7: FREE PTR
Step 8: EXIT

23

You might also like