Data Structures and Algorithms in C | Set 1
Data Structures-Arrays, Dynamic Arrays, and Linked lists
DSA is a very important concept in any programming language. Suppose we have a lot of books, and we need to choose a bookshelf to organize all the books. We'll first check how many books we have, and then we'll assume how many more books we might buy in the future. Then, we'll think of a reasonable budget we can spend for the shelf. We'll check which one is strong and has a good life out of the filtered shelves. Finally, we'll buy the best one.
In programming, books refer to huge amounts of data we must deal with while writing code, the program we are writing is the room, and inside our program, we need to find a good storage spot to arrange all the data efficiently. A messy room is never any good.
In this series of tutorials, we'll cover all the data structures in C language and then about another topic-Algorithms.
Data Types and Data Structures:
These two words might have Data in common but are not the same. Simply, we can say that a data type is a characteristic of variables. It represents what kind of data/ value can be stored in a particular variable. C is a static language. Hence, we need to declare every variable we want to use in the program with its data type before using it.
On the other hand, a data structure is the collection and organization of data from different data types from which we can process and retrieve data. It deals with the arrangement of data in the computer's memory.
int, float, etc. are data types, and stacks, queues, etc. are examples of data structures.
There are different types of data structures available in C. We need to learn them to know which one to use when in need.
Here is a flowchart showing the classification in C based on the organization of the variables:
An array is a collection of homogeneous elements at contiguous memory locations. The elements of an array can be accessed using indexes (0 to size-1). It can be multi-dimensional. It can store primitive and derived data typed elements, but all the elements should belong to the same data type. The aim of creating an array is to represent multiple same data-typed elements under one name.
Here is a program with all the basic operations on arrays:
a = 10 20 30 40 50 Out of index a: 0 Array elements are stored in contiguous locations: 000000000062FDF0 000000000062FDF4 000000000062FDF8 000000000062FDFC 000000000062FE00 Pointer indication: a = 10 *a = 10 Traversing using pointer: 10 20 30 40 50 By commutative property a[i] = i[a] = a = 30 2[a] = 30 Multi-dimensional array(4 X 4): 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 Sum of elements of b = 15 Sorting the array x: 1 2 4 7 9 -------------------------------- Process exited after 0.8778 seconds with return value 2 Press any key to continue . . .
A linked list is a linear data structure like an array, but the elements are not stored in contiguous memory locations. Every node/ element in the linked list has two sections-one with the data and the other with a pointer pointing to the next node's location. These pointers connect the nodes making a linked list linear. The address of the first node is stored in the head.
In C, a linked list is created using structures, and it also is homogeneous like an array, meaning it can only store data of the same data type in its nodes.
A simple linked list looks like this:
As shown in the above figure, the head is the first node, and the next (reference) part of the last node holds None.
A double-linked list looks like this:
In a double-linked list, every node will have three sections. Head holds the reference of the first node, the "previous" section of the first node holds None, and the next field of the last node refers to None. Each node will hold two references along with the data, one to its previous node and the next to the succeeding node.
Circular Linked List:
A circular linked list can be single or double:
Circular single linked list:
It is a single linked list, but the last node in the list holds the reference of the first node like a circle.
Circular Double-linked List:
It is a double-linked list, but the last node in the list holds the reference of the first node, and the 'previous' section of the first node holds the reference of the last node like a circle.
Here is a program showing some of the basic operations we can perform on a single linked list:
The created Linked List: HEAD -> 1 -> 2 -> 3 -> NULL Insertions: After inserting 5 at the beginning: HEAD -> 1 -> 2 -> 3 -> NULL -----> HEAD -> 5 -> 1 -> 2 -> 3 -> NULL After inserting 10 after 2 node: HEAD -> 1 -> 2 -> 3 -> NULL ----> HEAD -> 1 -> 2 -> 10 -> 3 -> NULL After inserting 17 at the end: HEAD -> 1 -> 2 -> 10 -> 3 -> NULL ----> HEAD -> 1 -> 2 -> 10 -> 3 -> 17 -> NULL Deletions: After deleting the 1st node: HEAD -> 1 -> 2 -> 10 -> 3 -> 17 -> NULL ----> HEAD -> 2 -> 10 -> 3 -> 17 -> NULL After deleting the last node: HEAD -> 1 -> 2 -> 10 -> 3 -> 17 -> NULL ----> HEAD -> 1 -> 2 -> 10 -> 3 -> NULL After deleting node from 3 position: HEAD -> 1 -> 2 -> 10 -> 3 -> NULL ----> HEAD -> 1 -> 2 -> 3 -> NULL
Once we declare an array, its size will be fixed. It is a drawback because we might run into the need for more memory at runtime. Hence, dynamic arrays are introduced.
There are 4 built-in dynamic memory allocation functions available:
In both malloc() and calloc(), the memory is allocated in one place contiguously. Hence, it is possible to create dynamic arrays.
Here is an example program to show the difference between malloc() and calloc() allocations:
Enter the number of elements in the first D-array: 5 Enter the number of elements in the second D-array: 5 Initial values: By malloc(): 11901584 0 11862352 0 1936028257 By calloc(): 0 0 0 0 0 Memory allocations: By malloc(): 11867904 11867908 11867912 11867916 11867920 By calloc(): 11867936 11867940 11867944 11867948 11867952
Suppose we created a regular array with size n, and we decided we didn't need the first element at runtime. We shift all the elements to the left by removing the first element. It will not change the array size, and the empty spot is never gone.
In the case of dynamic arrays, we can use realloc() to shrink the array. Here is an example to demonstrate the phenomenon:
Enter the size: 6 The memory allocations in a regular array: 6487264 6487268 6487272 6487276 6487280 6487284 The memory allocations in the dynamic array: 12130048 12130052 12130056 12130060 12130064 12130068 After removing the first element: Regular array: 6487264 6487268 6487272 6487276 6487280 6487284 Dynamic array: 12130048 12130052 12130056 12130060 12130064 -------------------------------- Process exited after 2.795 seconds with return value 1 Press any key to continue . . .
This is the first tutorial on Data structures and algorithms in C.
In this tutorial, we covered:
Programs with all the basic operations and explanations are implemented for better understanding. In the next tutorial, we'll carry on with stacks and queues.