0% found this document useful (0 votes)
9 views21 pages

UNIT-3 DS

The document provides an overview of linked lists, including their structure, types (simple, doubly, and circular), and basic operations such as insertion, deletion, and reversal. It details the implementation of these operations in C programming, along with example code for managing linked lists. Additionally, it discusses the advantages and disadvantages of doubly linked lists compared to singly linked lists and outlines the characteristics of circular linked lists.

Uploaded by

sajidtyagi460
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)
9 views21 pages

UNIT-3 DS

The document provides an overview of linked lists, including their structure, types (simple, doubly, and circular), and basic operations such as insertion, deletion, and reversal. It details the implementation of these operations in C programming, along with example code for managing linked lists. Additionally, it discusses the advantages and disadvantages of doubly linked lists compared to singly linked lists and outlines the characteristics of circular linked lists.

Uploaded by

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

Unit-3 LINKED LIST

LINKED LIST
A linked list is a sequence of data structures, which are connected together via links.
Linked List is a sequence of links which contains items. Each link contains a connection
to another link. Linked list is the second most-used data structure after array. Following
are the important terms to understand the concept of Linked List.
• Link − Each link of a linked list can store a data called an element.
• Next − Each link of a linked list contains a link to the next link called Next.
• LinkedList − A Linked List contains the connection link to the first link called
First.
Linked List Representation
Linked list can be visualized as a chain of nodes, where every node points to the next
node.

As per the above illustration, following are the important points to be considered.
• Linked List contains a link element called first.
• Each link carries a data field(s) and a link field called next.
• Each link is linked with its next link using its next link.
• Last link carries a link as null to mark the end of the list.
Types of Linked List
Following are the various types of linked list.
• Simple Linked List − Item navigation is forward only.
• Doubly Linked List − Items can be navigated forward and backward.
• Circular Linked List − Last item contains link of the first element as next and
the first element has a link to the last element as previous.
Basic Operations
Following are the basic operations supported by a list.
• Insertion − Adds an element at the beginning of the list.
• Deletion − Deletes an element at the beginning of the list.
• Display − Displays the complete list.
• Search − Searches an element using the given key.
• Delete − Deletes an element using the given key.
Insertion Operation
Adding a new node in linked list is a more than one step activity. We shall learn this
with diagrams here. First, create a node using the same structure and find the location
where it has to be inserted.
Imagine that we are inserting a node B (NewNode), between A (LeftNode)
and C (RightNode). Then point B.next to C −
NewNode.next −> RightNode;
It should look like this −

Now, the next node at the left should point to the new node.
LeftNode.next −> NewNode;

This will put the new node in the middle of the two. The new list should look like this −

Similar steps should be taken if the node is being inserted at the beginning of the list.
While inserting it at the end, the second last node of the list should point to the new
node and the new node will point to NULL.
Deletion Operation
Deletion is also a more than one step process. We shall learn with pictorial
representation. First, locate the target node to be removed, by using searching
algorithms.

The left (previous) node of the target node now should point to the next node of the
target node −
LeftNode.next −> TargetNode.next;

This will remove the link that was pointing to the target node. Now, using the following
code, we will remove what the target node is pointing at.
TargetNode.next −> NULL;

We need to use the deleted node. We can keep that in memory otherwise we can
simply deallocate memory and wipe off the target node completely.

Reverse Operation
This operation is a thorough one. We need to make the last node to be pointed by the
head node and reverse the whole linked list.
First, we traverse to the end of the list. It should be pointing to NULL. Now, we shall
make it point to its previous node −

We have to make sure that the last node is not the lost node. So we'll have some temp
node, which looks like the head node pointing to the last node. Now, we shall make all
left side nodes point to their previous nodes one by one.

Except the node (first node) pointed by the head node, all nodes should point to their
predecessor, making them their new successor. The first node will point to NULL.

We'll make the head node point to the new first node by using the temp node.

The linked list is now reversed.


Program:
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <stdbool.h>

struct node {
int data;
int key;
struct node *next;
};
struct node *head = NULL;
struct node *current = NULL;

//display the list


void printList() {
struct node *ptr = head;
printf("\n[ ");

//start from the beginning


while(ptr != NULL) {
printf("(%d,%d) ",ptr->key,ptr->data);
ptr = ptr->next;
}

printf(" ]");
}

//insert link at the first location


void insertFirst(int key, int data) {
//create a link
struct node *link = (struct node*) malloc(sizeof(struct node));

link->key = key;
link->data = data;

//point it to old first node


link->next = head;

//point first to new first node


head = link;
}

//delete first item


struct node* deleteFirst() {

//save reference to first link


struct node *tempLink = head;

//mark next to first link as first


head = head->next;

//return the deleted link


return tempLink;
}

//is list empty


bool isEmpty() {
return head == NULL;
}

int length() {
int length = 0;
struct node *current;

for(current = head; current != NULL; current = current->next) {


length++;
}

return length;
}

//find a link with given key


struct node* find(int key) {

//start from the first link


struct node* current = head;

//if list is empty


if(head == NULL) {
return NULL;
}

//navigate through list


while(current->key != key) {

//if it is last node


if(current->next == NULL) {
return NULL;
} else {
//go to next link
current = current->next;
}
}
//if data found, return the current Link
return current;
}

//delete a link with given key


struct node* delete(int key) {

//start from the first link


struct node* current = head;
struct node* previous = NULL;

//if list is empty


if(head == NULL) {
return NULL;
}

//navigate through list


while(current->key != key) {

//if it is last node


if(current->next == NULL) {
return NULL;
} else {
//store reference to current link
previous = current;
//move to next link
current = current->next;
}
}

//found a match, update the link


if(current == head) {
//change first to point to next link
head = head->next;
} else {
//bypass the current link
previous->next = current->next;
}

return current;
}
void sort() {

int i, j, k, tempKey, tempData;


struct node *current;
struct node *next;

int size = length();


k = size ;

for ( i = 0 ; i < size - 1 ; i++, k-- ) {


current = head;
next = head->next;

for ( j = 1 ; j < k ; j++ ) {

if ( current->data > next->data ) {


tempData = current->data;
current->data = next->data;
next->data = tempData;

tempKey = current->key;
current->key = next->key;
next->key = tempKey;
}

current = current->next;
next = next->next;
}
}
}

void reverse(struct node** head_ref) {


struct node* prev = NULL;
struct node* current = *head_ref;
struct node* next;

while (current != NULL) {


next = current->next;
current->next = prev;
prev = current;
current = next;
}
*head_ref = prev;
}

void main() {
insertFirst(1,10);
insertFirst(2,20);
insertFirst(3,30);
insertFirst(4,1);
insertFirst(5,40);
insertFirst(6,56);

printf("Original List: ");

//print list
printList();

while(!isEmpty()) {
struct node *temp = deleteFirst();
printf("\nDeleted value:");
printf("(%d,%d) ",temp->key,temp->data);
}

printf("\nList after deleting all items: ");


printList();
insertFirst(1,10);
insertFirst(2,20);
insertFirst(3,30);
insertFirst(4,1);
insertFirst(5,40);
insertFirst(6,56);

printf("\nRestored List: ");


printList();
printf("\n");

struct node *foundLink = find(4);

if(foundLink != NULL) {
printf("Element found: ");
printf("(%d,%d) ",foundLink->key,foundLink->data);
printf("\n");
} else {
printf("Element not found.");
}

delete(4);
printf("List after deleting an item: ");
printList();
printf("\n");
foundLink = find(4);

if(foundLink != NULL) {
printf("Element found: ");
printf("(%d,%d) ",foundLink->key,foundLink->data);
printf("\n");
} else {
printf("Element not found.");
}

printf("\n");
sort();

printf("List after sorting the data: ");


printList();

reverse(&head);
printf("\nList after reversing the data: ");
printList();
}
If we compile and run the above program, it will produce the following result −
Output
Original List:
[ (6,56) (5,40) (4,1) (3,30) (2,20) (1,10) ]
Deleted value:(6,56)
Deleted value:(5,40)
Deleted value:(4,1)
Deleted value:(3,30)
Deleted value:(2,20)
Deleted value:(1,10)
List after deleting all items:
[]
Restored List:
[ (6,56) (5,40) (4,1) (3,30) (2,20) (1,10) ]
Element found: (4,1)
List after deleting an item:
[ (6,56) (5,40) (3,30) (2,20) (1,10) ]
Element not found.
List after sorting the data:
[ (1,10) (2,20) (3,30) (5,40) (6,56) ]
List after reversing the data:
[ (6,56) (5,40) (3,30) (2,20) (1,10) ]
Doubly Linked List
A Doubly Linked List (DLL) contains an extra pointer, typically called previous pointer,
together with next pointer and data which are there in singly linked list.

Following is representation of a DLL node in C language.


/* Node of a doubly linked list */
struct Node {
int data;
struct Node* next; // Pointer to next node in DLL
struct Node* prev; // Pointer to previous node in DLL
};
Following are advantages/disadvantages of doubly linked list over singly linked list.
Advantages over singly linked list
1) A DLL can be traversed in both forward and backward direction.
2) The delete operation in DLL is more efficient if pointer to the node to be deleted is
given.
3) We can quickly insert a new node before a given node.
In singly linked list, to delete a node, pointer to the previous node is needed. To get
this previous node, sometimes the list is traversed. In DLL, we can get the previous
node using previous pointer.
Disadvantages over singly linked list
1) Every node of DLL Require extra space for an previous pointer. It is possible to
implement DLL with single pointer though
2) All operations require an extra pointer previous to be maintained. For example, in
insertion, we need to modify previous pointers together with next pointers. For
example in following functions for insertions at different positions, we need 1 or 2 extra
steps to set previous pointer.
Insertion
A node can be added in four ways
1) At the front of the DLL
2) After a given node.
3) At the end of the DLL
4) Before a given node.
1) Add a node at the front: (A 5 steps process)
The new node is always added before the head of the given Linked List. And newly
added node becomes the new head of DLL. For example if the given Linked List is
10152025 and we add an item 5 at the front, then the Linked List becomes 510152025.
Let us call the function that adds at the front of the list is push(). The push() must
receive a pointer to the head pointer, because push must change the head pointer to
point to the new node

2) Add a node after a given node.: (A 7 steps process)


We are given pointer to a node as prev_node, and the new node is inserted after the
given node.

3) Add a node at the end: (7 steps process)


The new node is always added after the last node of the given Linked List. For example
if the given DLL is 510152025 and we add an item 30 at the end, then the DLL becomes
51015202530. Since a Linked List is typically represented by the head of it, we have to
traverse the list till end and then change the next of last node to new node.

4) Add a node before a given node:


Steps
Let the pointer to this given node be next_node and the data of the new node to be
added as new_data.
1. Check if the next_node is NULL or not. If it’s NULL, return from the function
because any new node can not be added before a NULL
2. Allocate memory for the new node, let it be called new_node
3. Set new_node->data = new_data
4. Set the previous pointer of this new_node as the previous node of the next_node,
new_node->prev = next_node->prev
5. Set the previous pointer of the next_node as the new_node, next_node->prev =
new_node
6. Set the next pointer of this new_node as the next_node, new_node->next =
next_node;
7. If the previous node of the new_node is not NULL, then set the next pointer of
this previous node as new_node, new_node->prev->next = new_node
Circular Linked List
Circular linked list is a linked list where all nodes are connected to form a circle. There is
no NULL at the end. A circular linked list can be a singly circular linked list or doubly
circular linked list.

Advantages of Circular Linked Lists:


1) Any node can be a starting point. We can traverse the whole list by starting from any
point. We just need to stop when the first visited node is visited again.
2) Useful for implementation of queue. Unlike this implementation, we don’t need to
maintain two pointers for front and rear if we use circular linked list. We can maintain a
pointer to the last inserted node and front can always be obtained as next of last.
3) Circular lists are useful in applications to repeatedly go around the list. For example,
when multiple applications are running on a PC, it is common for the operating system
to put the running applications on a list and then to cycle through them, giving each of
them a slice of time to execute, and then making them wait while the CPU is given to
another application. It is convenient for the operating system to use a circular list so that
when it reaches the end of the list it can cycle around to the front of the list.
4) Circular Doubly Linked Lists are used for implementation of advanced data structures
like Fibonacci Heap.
Insertion in an empty List

Initially when the list is empty, last pointer will be NULL.

After inserting a node T,

After insertion, T is the last node so pointer last points to node T. And Node T is first
and last node, so T is pointing to itself.
Function to insert node in an empty List,
struct Node *addToEmpty(struct Node *last, int data)
{
// This function is only for empty list
if (last != NULL)
return last;
// Creating a node dynamically.
struct Node *last =
(struct Node*)malloc(sizeof(struct Node));

// Assigning the data.


last -> data = data;

// Note : list was empty. We link single node


// to itself.
last -> next = last;

return last;
}
Run on IDE

Insertion at the beginning of the list

To Insert a node at the beginning of the list, follow these step:


1. Create a node, say T.
2. Make T -> next = last -> next.
3. last -> next = T.

After insertion,

Function to insert node in the beginning of the List,


struct Node *addBegin(struct Node *last, int data)
{
if (last == NULL)
return addToEmpty(last, data);

// Creating a node dynamically.


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

// Assigning the data.


temp -> data = data;

// Adjusting the links.


temp -> next = last -> next;
last -> next = temp;

return last;
}

Insertion at the end of the list

To Insert a node at the end of the list, follow these step:


1. Create a node, say T.
2. Make T -> next = last -> next;
3. last -> next = T.
4. last = T.

After insertion,

Function to insert node in the end of the List,


struct Node *addEnd(struct Node *last, int data)
{
if (last == NULL)
return addToEmpty(last, data);

// Creating a node dynamically.


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

// Assigning the data.


temp -> data = data;

// Adjusting the links.


temp -> next = last -> next;
last -> next = temp;
last = temp;

return last;
}

Insertion in between the nodes

To Insert a node at the end of the list, follow these step:


1. Create a node, say T.
2. Search the node after which T need to be insert, say that node be P.
3. Make T -> next = P -> next;
4. P -> next = T.
Suppose 12 need to be insert after node having value 10,

After searching and insertion,


Function to insert node in the end of the List,
struct Node *addAfter(struct Node *last, int data, int item)
{
if (last == NULL)
return NULL;
struct Node *temp, *p;
p = last -> next;
// Searching the item.
do
{
if (p ->data == item)
{
temp = (struct Node *)malloc(sizeof(struct Node));
// Assigning the data.
temp -> data = data;
// Adjusting the links.
temp -> next = p -> next;
// Adding newly allocated node after p.
p -> next = temp;
// Checking for the last node.
if (p == last)
last = temp;
return last;
}
p = p -> next;
} while (p != last -> next);

cout << item << " not present in the list." << endl;
return last;
}
Memory Allocation-
Whenever a new node is created, memory is allocated by the system. This memory is
taken from list of those memory locations which are free i.e. not allocated. This list is
called AVAIL List. Similarly, whenever a node is deleted, the deleted space becomes
reusable and is added to the list of unused space i.e. to AVAIL List. This unused space
can be used in future for memory allocation.
Memory allocation is of two types-
1. Static Memory Allocation
2. Dynamic Memory Allocation

1. Static Memory Allocation:


When memory is allocated during compilation time, it is called ‘Static Memory
Allocation’. This memory is fixed and cannot be increased or decreased after
allocation. If more memory is allocated than requirement, then memory is wasted. If
less memory is allocated than requirement, then program will not run successfully.
So exact memory requirements must be known in advance.
2. Dynamic Memory Allocation:
When memory is allocated during run/execution time, it is called ‘Dynamic Memory
Allocation’. This memory is not fixed and is allocated according to our requirements.
Thus in it there is no wastage of memory. So there is no need to know exact memory
requirements in advance.
Garbage Collection-
Whenever a node is deleted, some memory space becomes reusable. This memory
space should be available for future use. One way to do this is to immediately insert the
free space into availability list. But this method may be time consuming for the operating
system. So another method is used which is called ‘Garbage Collection’. This method is
described below: In this method the OS collects the deleted space time to time onto the
availability list. This process happens in two steps. In first step, the OS goes through all
the lists and tags all those cells which are currently being used. In the second step, the
OS goes through all the lists again and collects untagged space and adds this collected
space to availability list. The garbage collection may occur when small amount of free
space is left in the system or no free space is left in the system or when CPU is idle and
has time to do the garbage collection.
Compaction
One preferable solution to garbage collection is compaction.
The process of moving all marked nodes to one end of memory and all available
memory to other end is called compaction. Algorithm which performs compaction is
called compacting algorithm.

You might also like

pFad - Phonifier reborn

Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.

Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy