Unit 3 DataStructureNotes
Unit 3 DataStructureNotes
Data structures are used to store and organize data in a way that makes it easy to access,
modify, and analyze.
Linked Organization:
In a linked organization, the elements or components of the system are connected through
relationships, but the order in which they occur may not be fixed. In Linked Organization,
elements might or might not be stored in consecutive memory locations and the order is
determined by the links between elements. This makes it easy to insert and delete elements
without requiring any movement of other elements and it can be extended or reduced according
to requirements.
Sequential Organization:
Each node contains data and a pointer to the Each element is stored one after the
2.
next node other
S.N Linked Organization Sequential Organization
3. Allows for fast insertions and deletions Allows for fast traversal and access
Can be used for implementing data Can be used for implementing data
5.
structures like linked lists and trees structures like arrays and stacks
7. Can be used for dynamic data structures Suitable for static data structures
Pointers may be pointing to null or non- All elements are stored in contiguous
10.
existent memory in case of broken links memory
12. Can have a circular linked list Only a linear sequential list is possible
Can be used for implementing more Can be used for simple data structures
15.
complex data structures like graphs. like queues and stacks.
Both sequential and linked organization have their own advantages and disadvantages. The
sequential organization is best for data structures that need to be accessed frequently and are
relatively static, while the linked organization is best for data structures that need to be modified
frequently and can change in size. The choice of organization will depend on the specific
requirements of the application or program.
Here are some of the major differences between a Static Queue and a Singly Linked List
Static Queue Singly Linked List
Nodes
A node is a collection of two parts: a data part that stores the element and a next part that stores
the link to the next node.
Linked list
A linked list is formed when many nodes are linked together to form a chain.
Head
The first node in a linked list is called the head and is used as a reference to traverse the list.
Tail
SLLs are a popular choice for organizing data because they are efficient for inserting and
deleting elements without the overhead of pre-allocating space. They are often used to
implement stacks, queues, and other abstract data types.
We have four nodes, each consisting of a data part and address part stored at some address. In
the singly linked list, we have a special node called the head node that holds the address of the
first node, and the last node points to Null.
Every node in a linked list connects with the other through a pointer that points to the address
of the next node, and arrows in the above-given diagram represent that.
In a linked list, each node connects through a pointer that points to the address of its next node,
and arrows in the above-given diagram represent that.
For Example:
The next part of the first node holds the address of the next node, address 2.
Similarly, the second node holds the address of the third node, address 3.
The third node holds the address of its next node, address 4. which follows till the last node
that is pointing to the Null. In this way, they link together.
Now we know the memory representation of a singly linked list with the help of a diagram.
Advancing, let's have a look at the syntax.
struct node
int data;
};
• Insertion operation
• Deletion operation
• Traversal operation
Implementation Of All Insertion Operations On SLL
#include <stdio.h>
#include <stdlib.h>
struct Node {
int data;
};
new->data = new_data;
new->next = (*head);
(*head) = new;
new->data = new_data;
new->next = NULL;
if (*head == NULL) {
*head = new;
return;
lastnode->next = new;
return;
if (prev_node == NULL) {
return;
new->data = new_data;
new->next = prev_node->next;
prev_node->next = new;
node = node->next;
int main()
insertionAtEnd(&head, 11);
insertionAtBegin(&head, 20);
insertionAtBegin(&head, 13);
insertionAtEnd(&head, 44);
insertionAfternode(head->next, 15);
display(head);
Output:
#include <stdio.h>
#include <stdlib.h>
struct Node {
int data;
};
new->data = new_data;
new->next = (*head);
(*head) = new;
}
new->data = new_data;
new->next = NULL;
if (*head == NULL) {
*head = new;
return;
lastnode->next = new;
return;
if (prev_node == NULL) {
return;
new->data = new_data;
new->next = prev_node->next;
prev_node->next = new;
}
*head = ptr->next;
free(ptr);
return;
prev = ptr;
ptr = ptr->next;
if (ptr == NULL)
return;
prev->next = ptr->next;
free(ptr);
node = node->next;
}
int main() {
insertionAtEnd(&head, 11);
insertionAtBegin(&head, 20);
insertionAtBegin(&head, 13);
insertionAtEnd(&head, 44);
insertionAfternode(head->next, 15);
display(head);
deletionNode(&head, 13);
display(head);
Output:
while(node!=NULL)
{
printf("%d ",node->data);
node = node->next;
traversal(head);
In thе rеalm of programming, mеmory management plays a vital role in making thе most
efficient use of systеm rеsourcеs. Dynamic mеmory allocation in thе C programming languagе
is a fundamental concеpt that givеs programmers thе роwеr to allocate and dеallocatе mеmory
whilе thе program is running. This process allows for more flеxiblе mеmory usagе, еnabling
applications to adapt to changing requirements and improvе thеir efficiency. This article will
explore thе various aspects of dynamic mеmory allocation in C, including its corе functions,
advantages, and how it differs from static mеmory allocation.
Dynamic mеmory allocation is a kеy concеpt in the C programming language that enables
developers to allocatе and handlе mеmory whilе a program runs. Unlikе static mеmory
allocation, which happens during compilation and has a fixеd mеmory sizе, dynamic mеmory
allocation allows programs to ask thе system for memory resources whеn nеcеssary. This
dynamic nature of mеmory allocation еnhancеs thе flexibility and effectiveness of C programs.
calloc(): Contiguous Allocation
Whеn you usе thе malloc() function to allocatе mеmory, it does not initialize the contеnt of thе
mеmory. Howеvеr, if you usе thе calloc(), which stands for "contiguous allocation, "it not
only allocates mеmory for arrays of еlеmеnts but also ensures that thе memory is initializеd to
zеro. This Zеro-initialization can be pretty handy when working with data structurеs or arrays
that rеquirе a specific starting point. By specifying the size of еach еlеmеnt and the number of
elements needed, calloc() will give you a pointer to thе first byte of the allocatеd mеmory
block.
Whеn programs allocatе mеmory dynamically, it's essential to rеlеаsе memory no longer
needed to avoid mеmory lеaks. Thе function known as frее() sеrvеs this purpose. Once you
have finished using a block of dynamically allocatеd mеmory, you can call frее() and provide
the pointеr to that block as an argumеnt. By doing so, the mеmory is dеallocatеd, frееing it up
for future usе. Neglecting to rеlеаsе memory can result in a gradual dеplеtion of availablе
mеmory and, in thе worst-casе scеnario, can causе program crashes due to insufficient mеmory
rеsourcеs.
Static mеmory allocation consists of storing mеmory for variables and data structures at
compilе timе. Although simple, this mеthod lacks flеxibility and could rеsult in inefficient
mеmory usе if not handlеd carefully. On thе contrary, dynamic memory allocation allows
developers to assign mеmory during runtimе, adjusting to thе spеcific mеmory demands of thе
program. This adaptability bеcomеs crucial when dealing with data structurеs of varying sizеs
or unforeseeable mеmory requirements.
Flеxibility:
Dynamic allocation allows the creation of data structurеs that can adjust to different input
sizеs.
Efficiеncy:
Mеmory Optimization:
Applications can effectively manage mеmory usagе, minimizing thе chances of memory
ovеrflow or inеfficiеnciеs.
Improvеd Pеrformancе:
Dynamic allocation makes crеating data structurеs such as linkеd lists and dynamic arrays
еasy.
A doubly linked list is a more complex data structure than a singly linked list, but it offers
several advantages. The main advantage of a doubly linked list is that it allows for efficient
traversal of the list in both directions. This is because each node in the list contains a pointer to
the previous node and a pointer to the next node. This allows for quick and easy insertion and
deletion of nodes from the list, as well as efficient traversal of the list in both directions.
A doubly linked list is a data structure that consists of a set of nodes, each of which contains
a value and two pointers, one pointing to the previous node in the list and one pointing to
the next node in the list. This allows for efficient traversal of the list in both directions,
making it suitable for applications where frequent insertions and deletions are required.
1. Data
• Create a new node, say new_node with its previous pointer as NULL.
• Check if the linked list is not empty then we update the previous pointer of the current
head to the new node, head->prev = new_node.
• Finally, we return the new node as the head of the linked list.
Algorithm To insert a new node after a specific node,
• Find the given node in the doubly linked list, say curr.
• Once we find it, create a new node with the new data, say new_node.
• Update the new node’s previous pointer to given node and new node’s next pointer to
the given node’s next, new_node->prev = curr and new_node->next = curr->next.
• Then, we update the next pointer of given node with new node, curr->next =
new_node.
• Also, if the new node is not the last node of the linked list, then update previous pointer
of new node’s next node to new node, new_node->next->prev = new_node.
To insert a new node at the end of the linked list.
Examples:
GARBAGE COLLECTION
Garbage collection frees memory occupied by linked lists when they are no longer in use.
A linked list is a dynamic data structure that consists of nodes, where each node contains a data
field and a reference (link) to the next node in the sequence. When you create a linked list, each
new node is allocated memory dynamically from the heap. As long as there are references to
these nodes (i.e., they are still in use), the garbage collector will not touch them. However, once
a node is no longer referenced by the program, it becomes eligible for garbage collection.
For instance, if you delete a node from the linked list by changing the 'next' reference of the
preceding node to skip over it, the deleted node will no longer be accessible from the list. Since
there are no more references to this node, the garbage collector identifies it as 'garbage' and
reclaims the memory it was occupying.
It's important to note that the process of garbage collection is typically abstracted away from
the programmer, and it's handled automatically by the runtime environment of the managed
language. The garbage collector periodically checks for objects in memory that are no longer
referenced by the program, marking them as garbage. It then sweeps through the memory,
freeing up the space occupied by the garbage.
In summary, garbage collection in managed languages helps to manage memory for dynamic
data structures like linked lists. It automatically reclaims memory from nodes that are no longer
in use, ensuring efficient use of resources and preventing potential memory leaks.
GC works by:
• Reclaiming memory: The garbage collector reclaims memory that is no longer being
used.
GC helps to:
A circular linked list is a special type of linked list where all the nodes are connected to form
a circle. Unlike a regular linked list, which ends with a node pointing to NULL, the last node
in a circular linked list points back to the first node. This means that you can keep traversing
the list without ever reaching a NULL value.
In Circular Singly Linked List, each node has just one pointer called the “next” pointer. The
next pointer of last node points back to the first node and this results in forming a circle. In
this type of Linked list we can only move through the list in one direction.
In circular doubly linked list, each node has two pointers prev and next, similar to doubly
linked list. The prev pointer points to the previous node and the next points to the next node.
Here, in addition to the last node storing the address of the first node, the first node will also
store the address of the last node.
Implementation to Create or Declare a Node of Circular Linked List
struct Node
int data;
};
// Allocate memory
newNode->data = value;
newNode->next = NULL;
return newNode;
}
Example of Creating a Circular Linked List
Here’s an example of creating a circular linked list with three nodes (2, 3, 4):
// Initilize nodes
first->data = 2;
second->data = 3;
last->data = 4;
// Connect nodes
first->next = second;
second->next = last;
last->next = first;
Operations on the Circular Linked list:
We can do some operations on the circular linked list similar to the singly and doubly linked
list which are:
• Insertion
• Deletion
• Searching
• We can traverse the list from any node and return to it without needing to restart from
the head, which is useful in applications requiring a circular iteration.
• Circular linked lists can easily implement circular queues, where the last element
connects back to the first, allowing for efficient resource management.
• In a circular linked list, each node has a reference to the next node in the sequence.
Although it doesn’t have a direct reference to the previous node like a doubly linked
list, we can still find the previous node by traversing the list.
Disadvantages of Circular Linked Lists
• Circular linked lists are more complex to implement than singly linked lists.
• Traversing a circular linked list without a clear stopping condition can lead to infinite
loops if not handled carefully.
• Debugging can be more challenging due to the circular nature, as traditional methods
of traversing linked lists may not apply.
• In multiplayer games, a circular linked list can be used to switch between players. After
the last player’s turn, the list cycles back to the first player.
• Circular linked lists are often used in buffering applications, such as streaming data,
where data is continuously produced and consumed.
• In media players, circular linked lists can manage playlists, this allowing users to loop
through songs continuously.
• Browsers use circular linked lists to manage the cache. This allows you to navigate back
through your browsing history efficiently by pressing the BACK button.