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

Unit3

The document provides an overview of linked lists as a linear data structure that uses pointers to link elements, highlighting their advantages over arrays, such as dynamic sizing and efficient insertion/deletion. It discusses various types of linked lists including singly, doubly, and circular linked lists, along with basic operations like insertion and deletion. Additionally, it covers the complexity analysis of these operations and their applications in real-world scenarios.

Uploaded by

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

Unit3

The document provides an overview of linked lists as a linear data structure that uses pointers to link elements, highlighting their advantages over arrays, such as dynamic sizing and efficient insertion/deletion. It discusses various types of linked lists including singly, doubly, and circular linked lists, along with basic operations like insertion and deletion. Additionally, it covers the complexity analysis of these operations and their applications in real-world scenarios.

Uploaded by

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

Open Elective2:

Subject: Data structures using


Python
Unit 3: Linked list
Linked list Data Structure

► A linked list is a linear data structure, in which the elements are not stored at
contiguous memory locations. The elements in a linked list are linked using
pointers as shown in the below image:

2
Why Linked List?

Arrays can be used to store linear data of similar types, but


arrays have the following limitations:
● The size of the arrays is fixed: So we must know the upper limit on the number of elements
in advance. Also, generally, the allocated memory is equal to the upper limit irrespective of
the usage.
● Insertion of a new element / Deletion of a existing element in an array of elements is
expensive: The room has to be created for the new elements and to create room existing
elements have to be shifted but in Linked list if we have the head node then we can traverse
to any node through it and insert new node at the required position.

Example:

In a system, if we maintain a sorted list of IDs in an array id[] = [1000, 1010, 1050, 2000, 2040].

If we want to insert a new ID 1005, then to maintain the sorted order, we have to move all the
elements after 1000 (excluding 1000).

Deletion is also expensive with arrays until unless some special techniques are used.
3
Advantages of Linked Lists over arrays:

● Dynamic Array.
● Ease of Insertion/Deletion.

4
Drawbacks of Linked Lists:

● Random access is not allowed. We have to access elements


sequentially starting from the first node(head node). So we cannot
do a binary search with linked lists efficiently with its default
implementation.
● Extra memory space for a pointer is required with each element of
the list.
● Not cache friendly. Since array elements are contiguous locations,
there is locality of reference which is not there in case of linked
lists.

5
Types of Linked Lists:

● Single Linked List – In this type of linked list, one can move or traverse the linked
list in only one direction
● Doubly Linked List – In this type of linked list, one can move or traverse the
linked list in both directions (Forward and Backward)
● Circular Linked List – In this type of linked list, the last node of the linked list
contains the link of the first/head node of the linked list in its next pointer and the
first/head node contains the link of the last node of the linked list in its prev pointer

6
Basic operations on Linked Lists:

● Deletion
● Insertion
● Search
● Display

7
Representation of Linked Lists:

A linked list is represented by a pointer to the first node of the linked list.
The first node is called the head of the linked list. If the linked list is
empty, then the value of the head points to NULL.

Each node in a list consists of at least two parts:


● A Data Item (we can store integer, strings, or any type of data).
● Pointer (Or Reference) to the next node (connects one node to
another) or An address of another node

8
Inserting a node
# Node class
class Node:

# Function to initialize the node object


def __init__(self, data):
self.data = data # Assign data
self.next = None # Initialize next as null

# Linked List class


class LinkedList:

# Function to initialize the Linked List object


def __init__(self):
self.head = None
9
Inthis post, methods to insert a new node in the linked list are
discussed. A node can be added in three ways
● At the front of the linked list
● After a given node.
● At the end of the linked list.

10
Add a node at the front: (4 steps process)

Approach: The new node is always added before the head of the given Linked List.
And newly added node becomes the new head of the Linked List. For example, if the
given Linked List is 10->15->20->25 and we add an item 5 at the front, then the Linked
List becomes 5->10->15->20->25. 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 the push
must change the head pointer to point to the new node

11
Following are the 4 steps to add a node at the front.

# This function is in LinkedList class


# Function to insert a new node at the beginning
def push(self, new_data):

# 1 & 2: Allocate the Node &


# Put in the data
new_node = Node(new_data)

# 3. Make next of new Node as head


new_node.next = self.head

# 4. Move the head to point to new Node


self.head = new_node
12
Complexity Analysis:

● Time Complexity: O(1), We have a pointer to the head and we can directly
attach a node and change the pointer. So the Time complexity of inserting a
node at the head position is O(1) as it does a constant amount of work.
● Auxiliary Space: O(1)

13
Add a node after a given node: (5 steps process)

Approach: We are given a pointer to a node, and the new node is inserted after the
given node.
Follow the steps to add a node after a given node:

● Firstly, check if the given previous node is NULL or not.


● Then, allocate a new node and
● Assign the data to the new node
● And then make the next of new node as the next of previous node.
● Finally, move the next of the previous node as a new node.

14
15
#This function is in LinkedList class.
# Inserts a new node after the given prev_node. This method is
# defined inside LinkedList class shown above */

def insertAfter(self, prev_node, new_data):

# 1. check if the given prev_node exists


if prev_node is None:
print("The given previous node must inLinkedList.")
return

# 2. Create new node &


# 3. Put in the data
new_node = Node(new_data)

# 4. Make next of new Node as next of prev_node


new_node.next = prev_node.next
16
# 5. make next of prev_node as new_node
prev_node.next = new_node
Complexity Analysis:

Time complexity: O(N), where N is the size of the linked list


Auxiliary Space: O(1) since using constant space to modify pointers

17
Add a node at the end: (6 steps process)

● The new node is always added after the last node of the given Linked List. For
example if the given Linked List is 5->10->15->20->25 and we add an item 30 at
the end, then the Linked List becomes 5->10->15->20->25->30.
● Since a Linked List is typically represented by the head of it, we have to traverse
the list till the end and then change the next to last node to a new node.

18
19
# This function is defined in Linked List class
# Appends a new node at the end. This method is
# defined inside LinkedList class shown above
def append(self, new_data):
# 1. Create a new node
# 2. Put in the data
# 3. Set next as None
new_node = Node(new_data)
# 4. If the Linked List is empty, then make the
# new node as head
if self.head is None:
self.head = new_node
return
# 5. Else traverse till the last node
last = self.head
while (last.next):
last = last.next
20
# 6. Change the next of last node
last.next = new_node
# This function is defined in Linked List class
# Appends a new node at the end. This method is
# defined inside LinkedList class shown above
def append(self, new_data):
# 1. Create a new node
# 2. Put in the data
# 3. Set next as None
new_node = Node(new_data)
# 4. If the Linked List is empty, then make the
# new node as head
if self.head is None:
self.head = new_node
return
# 5. Else traverse till the last node
last = self.head
while (last.next):
last = last.next
# 6. Change the next of last node
last.next = new_node
21
Complexity Analysis:

● Time complexity: O(N), where N is the number of nodes in the linked list. Since there
is a loop from head to end, the function does O(n) work.
○ This method can also be optimized to work in O(1) by keeping an extra pointer
to the tail of the linked list/
● Auxiliary Space: O(1)

22
Deleting a node

Delete from a Linked List:-


You can delete an element in a list from:
● Beginning
● End
● Middle

23
1) Delete from Beginning:

Point head to the next node i.e. second node


temp = head
head = head->next

Make sure to free unused memory


free(temp); or delete temp;

24
2) Delete from End:

Point head to the previous element i.e. last second element


Change next pointer to null
struct node *end = head;
struct node *prev = NULL;
while(end->next)
{
prev = end;
end = end->next;
}
prev->next = NULL;

Make sure to free unused memory


free(end); or delete end;
25
Delete from Middle:
Keeps track of pointer before node to delete and pointer to node to delete
temp = head;
prev = head;
for(int i = 0; i < position; i++)
{
if(i == 0 && position == 1)
head = head->next;
free(temp)
else
{
if (i == position - 1 && temp)
{
prev->next = temp->next;
free(temp);
}
26
else
{
prev = temp;
if(prev == NULL) // position was greater than number of nodes in the list
break;
temp = temp->next;
}
}
}

27
Applications, Advantages and Disadvantages of Linked List

● A Linked List is a linear data structure that is used to store a collection of data with the help of
nodes. A linked list is made up of two items that are data and a reference to the next node. A
reference to the next node is given with the help of pointers and data is the value of a node.
Each node contains data and links to the other nodes. It is an ordered collection of data
elements called a node and the linear order is maintained by pointers. It has an upper hand
over the array as the number of nodes i.e. the size of the linked list is not fixed and can grow
and shrink as and when required, unlike arrays. Some of the features of the linked list are as
follows:
● The consecutive elements are connected by pointers.
● The size of a linked list is not fixed.
● The last node of the linked list points to null.
● Memory is not wasted but extra memory is consumed as it also uses pointers to keep track of
the next successive node.
● The entry point of a linked list is known as the head.

28
The various types of linked lists are as follows:

● Singly Linked List: It is the most basic linked list in which traversal is unidirectional i.e.
from the head node to the last node.
● Doubly Linked List: In this linked list, traversal can be done in both ways, and hence it
requires an extra pointer.
● Circular Linked List: This linked list is unidirectional but in this list, the last node points
to the first i.e. the head node and hence it becomes circular in nature.
● Circular Doubly Linked List: The circular doubly linked list is a combination of the
doubly linked list and the circular linked list. It means that this linked list is bidirectional
and contains two pointers and the last pointer points to the first pointer.

29
Linked Lists are most commonly used for:

● Linked Lists are mostly used because of their effective insertion and
deletion.
● Insertion and deletion in the linked list are very effective and take
less time complexity as compared to the array data structure.
● This data structure is simple and can be also used to implement
a stack, queues, and other abstract data structures.

30
Applications of Linked Lists:

● Linked Lists are used to implement stacks and queues.


● It is used for the various representations of trees and graphs.
● It is used in dynamic memory allocation( linked list of free blocks).
● It is used for representing sparse matrices.
● It is used for the manipulation of polynomials.
● It is also used for performing arithmetic operations on long integers.
● It is used for finding paths in networks.

31
Applications of Linked Lists in real world:

● The list of songs in the music player are linked to the previous and next songs.
● In a web browser, previous and next web page URLs are linked through the
previous and next buttons.
● In image viewer, the previous and next images are linked with the help of the
previous and next buttons.
● Switching between two applications is carried out by using “alt+tab” in windows
and “cmd+tab” in mac book. It requires the functionality of circular linked list.
● In mobile phones, we save the contacts of the people. The newly entered contact
details will be placed at the correct alphabetical order. This can be achieved by
linked list to set contact at correct alphabetical position.
● The modifications that we are made in the documents are actually created as
nodes in doubly linked list. We can simply use the undo option by pressing Ctrl+Z
to modify the contents. It is done by the functionality of linked list.

32
Advantages of Linked Lists:

● Insertion and deletion in linked lists are very efficient.


● Linked list can be expanded in constant time.
● For implementation of stacks and queues and for representation of
trees and graphs.
● Linked lists are used for dynamic memory allocation which means
effective memory utilization hence, no memory wastage.

33
Disadvantages of Linked Lists:

● Use of pointers is more in linked lists hence, complex


and requires more memory.
● Searching an element is costly and requires O(n) time
complexity.
● Traversing is more time consuming and reverse
traversing is not possible in singly linked lists.
● Random access is not possible due to dynamic
memory allocation.

34
Types of Linked List

A linked list is a linear data structure, in which the elements are not stored at contiguous memory
locations. The elements in a linked list are linked using pointers. In simple words, a linked list
consists of nodes where each node contains a data field and a reference(link) to the next node in
the list.

Types Of Linked List:

1. Singly Linked List


It is the simplest type of linked list in which every node contains some data and a
pointer to the next node of the same data type.
The node contains a pointer to the next node means that the node
stores the address of the next node in the sequence. A single linked list
allows the traversal of data only in one way. Below is the image for the
same:
35
36
# structure of Node
class Node:
def __init__(self, data):
self.data = data
self.next = None

37
Doubly Linked List

A doubly linked list or a two-way linked list is a more complex type of linked list that
contains a pointer to the next as well as the previous node in sequence.
Therefore, it contains three parts of data, a pointer to the next node, and a pointer to the
previous node. This would enable us to traverse the list in the backward direction as
well. Below is the image for the same:

38
Doubly Linked List

A Doubly Linked List (DLL) contains an extra pointer, typically called the
previous pointer, together with the next pointer and data which are
there in a singly linked list.

39
Below are operations on the given
DLL:
► Add a node at the front of DLL: The new node is always
added before the head of the given Linked List. And the newly
added node becomes the new head of DLL & maintaining a
global variable for counting the total number of nodes at that
time.
Traversal of a Doubly linked list

40
► Insertion of a node: This can be done in three ways:
► At the beginning: The new created node is insert in
before the head node and head points to the new node.
► At the end: The new created node is insert at the end of
the list and tail points to the new node.
► At a given position: Traverse the given DLL to that
position(let the node be X) then do the following:
► Change the next pointer of new Node to the next
pointer of Node X.
► Change the prev pointer of next Node of Node X to the
new Node.
► Change the next pointer of node X to new Node.
► Change the prev pointer of new Node to the Node X.

41
► Deletion of a node: This can be done in three ways:
► At the beginning: Move head to the next node to delete the node at
the beginning and make previous pointer of current head to NULL .
► At the last: Move tail to the previous node to delete the node at the end
and make next pointer of tail node to NULL.
► At a given position: Let the prev node of Node at position pos be Node
X and next node be Node Y, then do the following:
► Change the next pointer of Node X to Node Y.
► Change the previous pointer of Node Y to Node X.

42
Doubly Linked List | Set 1 (Introduction
and Insertion)

► A Doubly Linked List (DLL) contains an extra pointer, typically called


the previous pointer, together with the next pointer and data which
are there in the singly linked list.

43
# Node of a doubly linked list

► class Node:

► def __init__(self, next=None, prev=None, data=None):


► # reference to next node in DLL


► self.next = next

► # reference to previous node in DLL


► self.prev = prev
► self.data = data
44
Advantages of DLL over the singly linked
list:

► A DLL can be traversed in both forward and backward directions.


► The delete operation in DLL is more efficient if a pointer to the node
to be deleted is given.
► We can quickly insert a new node before a given node.
► In a singly linked list, to delete a node, a 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 the previous
pointer.

45
Disadvantages of DLL over the singly
linked list:

► Every node of DLL Requires extra space for a previous pointer. It is


possible to implement DLL with a single pointer though .
► All operations require an extra pointer previous to be maintained.
For example, in insertion, we need to modify previous pointers
together with the next pointers. For example in the following
functions for insertions at different positions, we need 1 or 2 extra
steps to set the previous pointer.

46
Insertion in DLL:

► A node can be added in four ways:


► At the front of the DLL
► After a given node.
► At the end of the DLL
► Before a given node.

47
1) Add a node at the front:

► 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 1->0->1->5 and we add an
item 5 at the front, then the Linked List becomes 5->1->0->1->5.
Let us call the function that adds at the front of the list push(). The
push() must receive a pointer to the head pointer because the push
must change the head pointer to point to the new node

48
# Adding a node at the front of the list
► def push(self, new_data):
► # 1 & 2: Allocate the Node & Put in the data
► new_node = Node(data=new_data)
► # 3. Make next of new node as head and previous as NULL
► new_node.next = self.head
► new_node.prev = None
► # 4. change prev of head node to new node
► if self.head is not None:
► self.head.prev = new_node
► # 5. move the head to point to the new node
► self.head = new_node

49
2) Add a node after a given node:

► We are given a pointer to a node as prev_node, and the new node is


inserted after the given node.

50
► # Given a node as prev_node, insert
► # a new node after the given node
► def insertAfter(self, prev_node, new_data):
► # 1. check if the given prev_node is NULL
► if prev_node is None:
► print("This node doesn't exist in DLL")
► return
► # 2. allocate node & 3. put in the data
► new_node = Node(data=new_data)
► # 4. Make next of new node as next of prev_node
► new_node.next = prev_node.next
► # 5. Make the next of prev_node as new_node
► prev_node.next = new_node
► # 6. Make prev_node as previous of new_node
► new_node.prev = prev_node
► # 7. Change previous of new_node's next node */
► if new_node.next is not None:
► new_node.next.prev = new_node
51
3) Add a node at the end:

► The new node is always added after the last node of the given
Linked List. For example, if the given DLL is 5->1->0->1->5->2 and
we add item 30 at the end, then the DLL becomes 5->1->0->1->5-
>2->30. Since a Linked List is typically represented by its head of it,
we have to traverse the list till the end and then change the next of
last node to the new node.

52
# Add a node at the end of the DLL

► def append(self, new_data):


► # 1. allocate node 2. put in the data
► new_node = Node(data=new_data)
► last = self.head
► # 3. This new node is going to be the
► # last node, so make next of it as NULL
► new_node.next = None
► # 4. If the Linked List is empty, then
► # make the new node as head
► if self.head is None:
► new_node.prev = None
► self.head = new_node
► return
53

► # 5. Else traverse till the last node
► while (last.next is not None):
► last = last.next

► # 6. Change the next of last node


► last.next = new_node
► # 7. Make last node as previous of new node */
► new_node.prev = last

54
4) Add a node before a given node:
► Follow the below steps to solve the problem:
► Let the pointer to this given node be next_node and the data of the new node be
added as new_data.
► 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
► Allocate memory for the new node, let it be called new_node
► Set new_node->data = new_data
► Set the previous pointer of this new_node as the previous node of the next_node,
new_node->prev = next_node->prev
► Set the previous pointer of the next_node as the new_node, next_node->prev =
new_node
► Set the next pointer of this new_node as the next_node, new_node->next =
next_node;
► 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
► Else, if the prev of new_node is NULL, it will be the new head node. So, make
(*head_ref) = new_node.
55
56
Python program to insert a new node at the beginning of
the Circular Linked List

In this program, we will create a circular linked list and insert every new node
at the beginning of the list. If the list is empty, then head and tail will point to
the newly added node. If the list is not empty, then we will store the data of
the head into a temporary node temp and make new node as the head. This
new head will point to the temporary node. In simple words, the newly added
node will be the first node(head) and previous head(temp) will become the
second node of the list.

57
58
After inserting the new node to the beginning of the list.

59
ALGORITHM:

1. Define a Node class which represents a node in the list. It has two
properties data and next which will point to the next node.
2. Define another class for creating the circular linked list, and it has two
nodes: head and tail. It has two methods: addAtStart() and display() .
3. addAtStart() will add the node to the beginning of the list:
● It first checks whether the head is null (empty list), then it will insert the
node as the head.
● Both head and tail will point to a newly added node.
● If the list is not empty, then the newly added node will become the new
head, and it will point to the previous head. 60

You might also like