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

Week3 LinkedLists

Uploaded by

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

Week3 LinkedLists

Uploaded by

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

CMP2003

Data Structures & Algorithms


Lecture Notes 3
Linked Lists
Towards Dynamic Data Structures

• An array is a collection of homogeneous


elements stored at consecutive locations
• Main limitations of arrays:
▪ It is a static data structure
▪ Its size must be known at compilation time, in
most programming languages
▪ Inefficient insertion and deletion of elements
• A dynamic data structure can overcome these
problems
2
What is a Dynamic Data Structure?

• A data structure that can shrink or grow during program


execution
• The size of a dynamic data structure is not necessarily
known at compilation time, in most programming
languages
• Efficient insertion and deletion of elements
• The data in a dynamic data structure can be stored in
non-contiguous (arbitrary) locations
• Linked list is an example of a dynamic data structure
3
What is a Linked List?
• A linked list is a collection of nodes, each node holding some
information and a pointer to another node in the list
• In the following example, there are four nodes, which are not
stored at consecutive locations
300
100
400
40 NUL
80 300 L
25 600 600

30 100

Information
part
Pointer
(Address part) 4
Advantages of linked lists

• Unused locations in array is a waste of space

• Linked lists offer an efficient use of memory:


– Nodes are created only when they are required,
– Nodes can be deleted when not required
anymore,
– Not necessary to know in advance how long the
list should be

5
Singly Linked Lists
◼ A singly linked list is a concrete data
structure consisting of a sequence of next
data
nodes - linear ordering
◼ Each node stores
◼ A data element node
◼ A link (pointer) to the next node

A B C D NULL

6
Singly Linked Lists
• Basically Singly Linked Lists are uni-directional as they can only
point to the next Node in the list but not to the previous.

• The below figure is an example of a singly linked list whose


elements are strings indicating airport codes. The next pointers of
each node are shown as arrows. The null object is denoted as ∅.

7
Singly Linked Lists
• A node references another node, the next reference
inside a node is a link or pointer to another node.

• Moving from one node to another by following a


next reference is known as link hopping or pointer
hopping.

• The first and last node of a linked list usually are


called the head and tail of the list, respectively.

8
Singly Linked Lists
• Thus, we can link hop through the list starting at the
head and ending at the tail.

• We can identify the tail as the node having a null next


reference, which indicates the end of the list.

• A linked list defined in this way is known as a singly


linked list.

9
Singly Linked Lists
• Like an array
– A singly linked list keeps its elements in a certain order.
– This order is determined by the chain of next links going
from each node to its successor in the list.
• Unlike an array
– A singly linked list does not have a predetermined fixed size
and uses space proportional to the number of its elements.
– Likewise, we do not keep track of any index numbers for
the nodes in a linked list.
– So, we cannot tell just by examining a node if it is the
second, fifth, or twentieth node in the list – disadvantage.

10
Implementing a Singly Linked List
• Data holds the data in the Node while Next (the link) holds the
address to the next Node in the list.
• How to define a linked list node:
Node in a Singly // Define a class for a singly linked list
Linked List node
class Node {
public:
int data;
Node* next;
Node(int value) {
data = value;
next = NULL;
}
};

11
Insertion at the beginning of a Singly Linked List
• When using a singly linked list, we can easily insert an element at the
head of the list.
• The main idea is:
– create a new node,
– set its next link to refer to the same object as head,
– and then set head to point to the new node.

12
Creating a Singly Linked List
// Class to represent the singly linked list
class LinkedList {
private:
Node* head;

public:
LinkedList() {
head = NULL;
}

// Function to insert a new element at the beginning of the list


void insertAtBeginning(int value) {
Node* newNode = new Node(value);
newNode->next = head;
head = newNode;
}

13
Creating a Singly Linked List
// Function to display the linked list
void display() {
Node* current = head;
while (current != NULL) {
std::cout << current->data << " -> ";
current = current->next;
}
std::cout << "NULL" << std::endl;
}
};

int main() {
LinkedList myList;

myList.insertAtBeginning(3);
myList.insertAtBeginning(2);
myList.insertAtBeginning(1);

std::cout << "Linked List: ";


14
myList.display();
Insertion at the tail of a Singly Linked List
• We can also easily insert an element at the tail of the list, provided we keep
a reference to the tail node, as shown in the below figure.
Otherwise, we have to move a pointer from the head to the last node.
• In this case,
– we create a new node,
– assign its next reference to point to the null object,
– set the next reference of the tail to point to this new object,
– and then assign the tail reference itself to this new node.

15
Insertion at the tail of a Singly Linked List
Inserting a new node at the end of a singly linked list, given only a pointer to the head
(no tail).
This method works also if the list is empty.
// Function to insert a new element at the end of the list
void insertAtEnd(int value) {
Node* newNode = new Node(value);
if (head == NULL) {
head = newNode;
} else {
Node* current = head;
while (current->next != NULL) {
current = current->next;
}
current->next = newNode;
}
}

16
Deleting the head of a Singly Linked List
The reverse operation of inserting a new element at the head of a linked
list is to remove an element at the head.

Below figure: Removal of an element at the head of a singly linked list:


(a) before the removal;
(b) "linking out" the old new node;
(c) after the removal.

17
Deleting the head of a Singly Linked List

// Function to delete the head (first element) of the list


void deleteHead() {
if (head != NULL) {
Node* temp = head;
head = head->next;
delete temp;
}
}

18
Deleting the tail of a Singly Linked List
// Function to delete the tail (last element) of the list
void deleteTail() {
if (head == NULL) {
return; // Nothing to delete
} else if (head->next == NULL) {
delete head;
head = NULL;
} else {
Node* current = head;
while (current->next->next != NULL) {
current = current->next;
}
delete current->next;
current->next = NULL;
}
}

19
Deleting the tail of a Singly Linked List - Analysis

• Even if we have a tail reference directly to the last node of


the list, we cannot easily delete it.

• Indeed, we must be able to access the node before the last


node in order to remove the last node.

• The only way to access the tail node is to start from the
head of the list and search all the way through the list, but
such a sequence of link hopping operations could take a
long time.

20
Doubly Linked Lists
• It is time consuming to remove any node other than the head
in a singly linked list, since we do not have a quick way of
accessing the node in front of the one we want to remove.

• There is a type of linked list that allows us to go in both


forward and reverse directions in a linked list. It is called a
doubly linked list.

• A doubly linked list allows for a great variety of quick update


operations, including insertion and removal at both ends, and
in intermediary positions.

• Every node in a doubly linked list stores two references:


– next link: a pointer to the next node in the list,
– previous link: a pointer to the previous node in the list. 21
Doubly Linked Lists
A doubly linked list contains a collection of nodes where each node
contains two pointers: one pointer pointing to the next element in
the list and another pointer pointing to the previous element.

// Define a class for a doubly linked list node


class Node {
private:
int data;
Node* next;
Node* previous;
public:
Node(int value) {
data = value;
next = NULL; 22

previous = NULL;
}
};
Doubly Linked Lists
A doubly linked list with head and tail, marking the ends of
the list.

An empty list would have NULL head and tail pointers.


23
Insertion at the beginning of a Doubly Linked List
One can easily perform an insertion of a new element
at the beginning of a doubly linked list.

Adding an element at the front:

24
Insertion at the beginning of a Doubly Linked List
Note that this method works also on an empty list.

// Function to insert a new element at the beginning of the list


void insertBeginning(int value) {
Node* newNode = new Node(value);
if (head == NULL) {
head = newNode;
tail = newNode;
} else {
newNode->next = head;
head->previous = newNode;
head = newNode;
}
}
25
Insertion at the end of a Doubly Linked List
Note that this method works also on an empty list.

// Function to insert a new element at the end of the list


void insertEnd(int value) {
Node* newNode = new Node(value);
if (tail == NULL) {
head = newNode;
tail = newNode;
} else {
newNode->previous = tail;
tail->next = newNode;
tail = newNode;
}
}
26
Deletion in a Doubly Linked List
• It is easy to remove an intermediary node v in a doubly linked list.
• We access the nodes u and w on either side of v.
• To remove node v, we simply have u and w point to each other instead
of v. We refer to this operation as the linking out of v.
• We also null out v's previous and next pointers so as not to retain old
references to the list.

• Deleting the tail is also easy. Indeed, the previous links eliminate the
need to traverse the list to get to the node just before the tail.

27
Deleting the tail of a Doubly Linked List
Removing the node storing P:
• Set tail to temp->previous.
• delete tail→next.
• Set tail→next to NULL

28
Deleting the tail of a Doubly Linked List
// Function to delete the tail (last element) of the list
void deleteTail() {
if (tail != NULL) {
if (tail->previous != NULL) {
tail = tail->previous;
delete tail->next;
tail->next = NULL;
} else {
delete tail;
head = NULL;
tail = NULL;
}
}
}
29
Circular Singly Linked Lists
• A circular singly linked list has the same kind of nodes as a singly
linked list.

• Each node in a circular linked list has a next pointer and a data
element.

• There is no head or tail in a circular linked list.

• A singly linked list can be turned into a circular linked list by


making the last node's next pointer point back to the first node.
Hence, there is no first or last node in a circular linked list.

• If we traverse the nodes of a circular linked list starting from any


30
node, we will cycle through the nodes.
Circular Singly Linked Lists
• Even though a circularly linked list has no beginning or end, we
need a node to be marked as a special node, which we will call
the cursor node.

• The cursor node allows us to have a place to start from if we


ever need to traverse a circular linked list.
• We have several possibilities for
the cursor. It can be the first
inserted node (head) or the last
node (tail). We can have other
nodes as cursors as well.

• It is interesting to take the last


node as cursor. This way, we
know both the first node and the 31
last node with a single pointer.
Inserting an Element in a Circular Linked List
// Function to insert a new element into the circular linked list
void insert(int value) {
Node* newNode = new Node(value);
if (head == NULL) {
head = newNode;
head->next = head; // Make it point to itself to form a
//circular list
} else {
Node* current = head;
while (current->next != head) {
current = current->next;
}
current->next = newNode;
newNode->next = head; // Make the new node point to the
//head to maintain the circular structure
}
32
}
Print Elements of a Circular Linked List
// Function to display the circular linked list
void display() {
if (head == NULL) {
std::cout << "Circular Linked List is empty." << std::endl;
return;
}

Node* current = head;


do {
std::cout << current->data << " -> ";
current = current->next;
} while (current != head);

std::cout << " (Head)" << std::endl;


}

33

You might also like