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

Unit 3 DataStructureNotes

The document discusses data structures, focusing on linked and sequential organizations, highlighting their differences in terms of memory allocation, insertion, deletion, and access speed. It explains the singly linked list, its operations, and dynamic memory management in C, emphasizing the importance of dynamic allocation for flexibility and efficiency. The document also details core functions for dynamic memory allocation, such as malloc, calloc, and free, and their advantages over static memory allocation.

Uploaded by

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

Unit 3 DataStructureNotes

The document discusses data structures, focusing on linked and sequential organizations, highlighting their differences in terms of memory allocation, insertion, deletion, and access speed. It explains the singly linked list, its operations, and dynamic memory management in C, emphasizing the importance of dynamic allocation for flexibility and efficiency. The document also details core functions for dynamic memory allocation, such as malloc, calloc, and free, and their advantages over static memory allocation.

Uploaded by

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

Data Structure UNIT 3

Dr. DeshpanDe a.s


UNIT 3
Concept of Linked Organization

Data structures are used to store and organize data in a way that makes it easy to access,
modify, and analyze.

Two of the most common types of data structures are :

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:

In a sequential organization, the elements or components of the system are arranged in a


specific order, and each element depends on the previous one. Sequential organization has the
advantage of fast access to elements, but has the disadvantage of slow insertion and deletion
of elements, especially when the data is stored in a contiguous block of memory.

Difference Between Sequential Organization and Linked Organization:

S.N Linked Organization Sequential Organization

Data is stored in nodes that are linked


1. Data is stored in a linear sequence
together

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

4. More complex to implement Simpler to implement

Can be used for implementing data Can be used for implementing data
5.
structures like linked lists and trees structures like arrays and stacks

Less memory is required as no


6. Requires more memory for pointers
pointers needed

7. Can be used for dynamic data structures Suitable for static data structures

8. Flexible in terms of size and structure Fixed-size and structure

9. Random access is not possible Random access is possible

Pointers may be pointing to null or non- All elements are stored in contiguous
10.
existent memory in case of broken links memory

Can have multiple pointers in case of Only one pointer is required to


11.
bidirectional links traverse the list

12. Can have a circular linked list Only a linear sequential list is possible

Only one head and tail pointer is


13. Can have multiple head and tail pointers
required
S.N Linked Organization Sequential Organization

Can have variable length of data in each


14. Fixed length of data in each element
node

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.

Singly Linked List


Singly Linked List: A linked list is also an ordered list of elements. You can add an element
anywhere in the list, change an element anywhere in the list, or remove an element from any
position in the list. Each node in the list stores the content and a pointer or reference to the next
node in the list. To store a single linked list, only the reference or pointer to the first node in
that list must be stored. The last node in a single linked list points to nothing (or null).

Here are some of the major differences between a Static Queue and a Singly Linked List
Static Queue Singly Linked List

A linked list is a collection of one or


Queue is a collection of one or more elements more elements arranged in memory
arranged in memory in a contiguous fashion. in a dis-contiguous fashion.

Static Queue is always fixed size. List size is never fixed.

In Queue, only one and single type of


information is stored because static Queue List also stored the address for the
implementation is through Array. next node along with it’s content.

Static Queue is index based. Singly linked list is reference based.

Insertion can always be performed on a single


end called REAR and deletion on the other end Insertion as well as deletion can
called FRONT. performed any where within the list.

List may be based on FIFO or LIFO


Queue is always based on FIFO. etc.

While List has only one pointer


Queue have two pointer FRONT and REAR. basically called HEAD.
A singly linked list (SLL) is a data structure that consists of a series of connected nodes, where
each node stores data and a link to the next node:

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

The last node in a linked list is called the 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.

Memory Representation of Singly Linked List

Let's consider four elements to insert into the list.

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:

Let our elements to insert be 10, 20, 30, and 40.

The head node holds the address of the first node.

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.

Syntax of Singly Linked List

struct node

int data;

struct node* next;

};

Operations on Singly Linked List:

• Insertion operation
• Deletion operation
• Traversal operation
Implementation Of All Insertion Operations On SLL
#include <stdio.h>

#include <stdlib.h>

struct Node {

int data;

struct Node* next;

};

void insertionAtBegin(struct Node** head, int new_data) {

struct Node* new = (struct Node*)malloc(sizeof(struct Node));

new->data = new_data;

new->next = (*head);

(*head) = new;

void insertionAtEnd(struct Node** head, int new_data) {

struct Node* new = (struct Node*)malloc(sizeof(struct Node));

struct Node* lastnode = *head;

new->data = new_data;

new->next = NULL;

if (*head == NULL) {

*head = new;

return;

while (lastnode->next != NULL) lastnode = lastnode->next;

lastnode->next = new;
return;

void insertionAfternode(struct Node* prev_node, int new_data) {

if (prev_node == NULL) {

printf("the given previous node cannot be NULL");

return;

struct Node* new = (struct Node*)malloc(sizeof(struct Node));

new->data = new_data;

new->next = prev_node->next;

prev_node->next = new;

void display(struct Node* node)

while (node != NULL) {

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

node = node->next;

int main()

struct Node* head = NULL;

insertionAtEnd(&head, 11);

insertionAtBegin(&head, 20);
insertionAtBegin(&head, 13);

insertionAtEnd(&head, 44);

insertionAfternode(head->next, 15);

printf("Linked list elements are: ");

display(head);

Output:

Implementation Of All Deletion Operations On SLL


Program to perform deletion operation on singly Linked List.

#include <stdio.h>

#include <stdlib.h>

struct Node {

int data;

struct Node* next;

};

void insertionAtBegin(struct Node** head, int new_data) {

struct Node* new = (struct Node*)malloc(sizeof(struct Node));

new->data = new_data;

new->next = (*head);

(*head) = new;
}

void insertionAtEnd(struct Node** head, int new_data){

struct Node* new = (struct Node*)malloc(sizeof(struct Node));

struct Node* lastnode = *head;

new->data = new_data;

new->next = NULL;

if (*head == NULL) {

*head = new;

return;

while (lastnode->next != NULL) lastnode = lastnode->next;

lastnode->next = new;

return;

void insertionAfternode(struct Node* prev_node, int new_data)

if (prev_node == NULL) {

printf("the given previous node cannot be NULL");

return;

struct Node* new = (struct Node*)malloc(sizeof(struct Node));

new->data = new_data;

new->next = prev_node->next;

prev_node->next = new;
}

void deletionNode(struct Node** head, int key) {

struct Node *ptr = *head, *prev;

if (ptr != NULL && ptr->data == key) {

*head = ptr->next;

free(ptr);

return;

while (ptr != NULL && ptr->data != key) {

prev = ptr;

ptr = ptr->next;

if (ptr == NULL)

return;

prev->next = ptr->next;

free(ptr);

void display(struct Node* node)

while (node != NULL) {

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

node = node->next;

}
int main() {

struct Node* head = NULL;

insertionAtEnd(&head, 11);

insertionAtBegin(&head, 20);

insertionAtBegin(&head, 13);

insertionAtEnd(&head, 44);

insertionAfternode(head->next, 15);

printf("Linked list elements: ");

display(head);

printf("\nAfter deleting an element: ");

deletionNode(&head, 13);

display(head);

Output:

Function to perform traversal operation on singly linked list

void traversal(struct Node* node)

printf("\nLinked List elements: ");

while(node!=NULL)

{
printf("%d ",node->data);

node = node->next;

traversal(head);

DYNAMIC MEMORY MANAGEMENT

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.

What is Dynamic Memory Allocation in C?


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е flеxibility and effectiveness of C programs.

Core Functions of Dynamic Memory Allocation


Several functions are essential for dynamic memory allocation in C:

malloc(): Allocating Memory

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.

free(): Releasing Allocated Memory

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.

Benefits of Dynamic Memory Allocation


Dynamic memory allocation provides sеvеral bеnеfits:

Flеxibility:

Dynamic allocation allows the creation of data structurеs that can adjust to different input
sizеs.
Efficiеncy:

Mеmory is assignеd only whеn nеcеssary, reducing memory wastagе.

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 memory allocation in C can optimizе mеmory usagе, improving overall


performance.

Adaptablе Data Structurеs:

Dynamic allocation makes crеating data structurеs such as linkеd lists and dynamic arrays
еasy.

Dynamic memory allocation in C is an incrеdibly powerful technique that allows programmеrs


to manage memory during runtime еfficiеntly. By using functions likе malloc and calloc,
frее(), and rеalloc(), programmеrs can dynamically allocatе mеmory based on specific nееds,
resulting in optimizеd and flеxiblе mеmory usagе. Undеrstanding thе advantages of dynamic
allocation and how it diffеrs from static allocation еnablеs programmers to dеvеlop
applications that arе adaptablе and morе еfficiеnt. By incorporating dynamic mеmory
allocation into your programming rеpеrtoirе, you get accеss to thе tools nеcеssary for crеating
applications that can dynamically rеspond to changing data requirements. This not only
improvеs thе ovеrall pеrformancе of your applications but also enhances their mеmory
еfficiеncy.
DOUBLY LINKED LIST

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.

What is a Doubly Linked List?

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.

Doubly Linked List

Representation of Doubly Linked List in Data Structure


In a data structure, a doubly linked list is represented using nodes that have three fields:

1. Data

2. A pointer to the next node (next)

3. A pointer to the previous node (prev)


Each node in a Doubly Linked List contains the data it holds, a pointer to
the next node in the list, and a pointer to the previous node in the list. By linking these
nodes together through the next and prev pointers, we can traverse the list in both
directions (forward and backward), which is a key feature of a Doubly Linked List.

Operations on Doubly Linked List


• Traversal in Doubly Linked List

• Searching in Doubly Linked List

• Finding Length of Doubly Linked List

Algorithm To insert a Node at the beginning In DLL

To insert a new node at the front of doubly linked list,

• Create a new node, say new_node with its previous pointer as NULL.

• Set the next pointer to the current head, new_node->next = head.

• 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:

Input: LinkedList = 2 -> 3 -> 4 -> 5, NewNode = 1


Output: LinkedList = 2 -> 3 -> 4 -> 5 -> 1

Input: LinkedList = NULL, NewNode = 1


Output: LinkedList = 1

An Algorithm to add a new node at the end of the linked list:


• Create a new node and set its next pointer as NULL since it will be the last node.
• Store the head reference in a temporary variable
• If the Linked List is empty, make the new node as the head and return
• Else traverse till the last node
• Change the next pointer of the last node to point to the new node

GARBAGE COLLECTION
Garbage collection frees memory occupied by linked lists when they are no longer in use.

Garbage collection is a form of automatic memory management utilised by many modern


programming languages, including managed languages like Java, C#, and Python. It works by
automatically reclaiming memory that is no longer in use by the program, freeing up resources
and preventing memory leaks. When it comes to linked lists in these languages, garbage
collection plays a crucial role in managing memory.

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:

• Marking objects: The garbage collector marks objects in memory as garbage.

• Sweeping: The garbage collector scans through memory to free up space.

• Reclaiming memory: The garbage collector reclaims memory that is no longer being
used.

GC helps to:

• Prevent memory leaks

• Ensure that a program doesn't exceed its memory quota

• Reduce the potential for memory-related bugs

• Free developers from manually managing memory


Introduction to Circular Linked List
A circular linked list is a data structure where the last node connects back to the first, forming
a loop. This structure allows for continuous traversal without any interruptions. Circular linked
lists are especially helpful for tasks like scheduling and managing playlists, this allowing for
smooth navigation. In this tutorial, we’ll cover the basics of circular linked lists, how to work
with them, their advantages and disadvantages, and their applications.

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.

Types of Circular Linked Lists


We can create a circular linked list from both singly linked lists and doubly linked lists. So,
circular linked list are basically of two types:

1. Circular Singly Linked List

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.

2. Circular Doubly Linked List:

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;

struct Node *next;

};

// Function to create a new node

struct Node *createNode(int value){

// Allocate memory

struct Node *newNode =

(struct Node *)malloc(sizeof(struct Node));

// Set the data

newNode->data = value;

// Initialize next to NULL

newNode->next = NULL;

// Return the new node

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):

Program to allocate Memory for Nodes

/ Allocate memory for nodes

struct Node *first =

(struct Node *)malloc(sizeof(struct Node));

struct Node *second =

(struct Node *)malloc(sizeof(struct Node));

struct Node *last =

(struct Node *)malloc(sizeof(struct Node));

// 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

o Insertion at the empty list (Refer GeekForGeeks for Actual Implementation)

o Insertion at the beginning

o Insertion at the end

o Insertion at the given position

• Deletion

o Delete the first node

o Delete the last node

o Delete the node from any position

• Searching

Advantages of Circular Linked Lists


• In circular linked list, the last node points to the first node. There are no null references,
making traversal easier and reducing the chances of encountering null pointer
exceptions.

• 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.

Applications of Circular Linked Lists


• It is used for time-sharing among different users, typically through a Round-Robin
scheduling mechanism.

• 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.

You might also like