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

W9 Linked List(1)

This document provides an overview of linked lists in C++, including their structure, operations such as adding and deleting nodes, and the advantages they hold over arrays. It emphasizes the dynamic nature of linked lists, the importance of proper pointer management, and common pitfalls in implementation. The document also includes code examples for adding and removing nodes from a linked list.

Uploaded by

songjiany
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)
4 views

W9 Linked List(1)

This document provides an overview of linked lists in C++, including their structure, operations such as adding and deleting nodes, and the advantages they hold over arrays. It emphasizes the dynamic nature of linked lists, the importance of proper pointer management, and common pitfalls in implementation. The document also includes code examples for adding and removing nodes from a linked list.

Uploaded by

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

SC1008 C and C++

Programming

Assistant Professor WANG Yong


[email protected]
CCDS, Nanyang Technological University
Week 9
Linked List
Outline

• Introduction to Linked List


• Linked List Operations
– add a node to the end of the list
– delete a node
– traverse a linked list
– delete/destroy a linked list
• Variations of Linked List

3
Why Learning Linked List?

• Linked list is a common Abstract Data Type (ADT) in C++


• Compared with arrays, linked lists have distinct advantages:
- Linked list can easily grow or shrink in size. The programmer
do not need to know how many nodes will be in the list in advance
- Node insertion and deletion from a linked list is fast, since
none of other nodes have to be moved when a node is inserted into
or deleted from a linked list

4
Introduction to Linked List

• A linked list is a series of connected nodes, where each node is


a data structure
• A node contains:
– data: one or more data fields; can be different data types
– a pointer that can point to another node
• A linked list can contain 0 or more nodes
• The below example shows a linked list of 3 nodes, with the
list head (i.e., a pointer) pointing to the first node and the
NULL pointer signifying the end of the list

5
Introduction to Linked List

• The nodes of a linked list are usually dynamically allocated.


Nodes can be added to or removed from the linked list,
allowing the linked list to grow or shrink in size as the
program runs
Adding a node

Deleting a node

6
An Empty Linked List

• If a list currently contains 0 nodes, it is the empty list


• In this case, the list head points to a NULL pointer

NULL vs. nullptr:


• C++ inherited NULL from C. NULL is often defined as 0 or (void*) 0,
indicating that a pointer does not point to a valid memory location
• NULL can be implicitly converted to integer, potentially leading to
unexpected errors
• C++ 11 introduces nullptr with its own type (std::nullptr_t)

Make nullptr your default choice for representing null pointers in C++
7
Define a Linked List

• Declare a node:
struct Node
{
double value; //It can be other data types
Node *next;
};
No memory is allocated at this time
• Define a pointer to be used as the list head and initialize it to
nullptr
Node* head = nullptr;

8
Outline

• Introduction to Linked List


• Linked List Operations
– add a node to the end of the list
– delete a node
– traverse a linked list
– delete/destroy a linked list
• Variations of Linked List

9
Two Common Pointer Bugs in
implementing linked list operations
• Attempting to dereference a pointer via *p or p-> when
p==NULL or p == nullptr
• Attempting to dereference a pointer via *p or p-> when p is
not properly initialized

• NOTE: this error does not cause a syntax error, but instead
causes errors:
- Bus Error
- Segmentation violation
- Address protection violation

10
Add a Node at the End of the List

• Basic process:
– Create the new node
– Add node to the end of the list:
• If list is empty, set head pointer to this node
• Else,
– traverse the list to the end
– set pointer of last node to point to new node
• It is the basic operation for creating a linked list

11
Create a New Node
Node
• Allocate memory for the new node:
Node = new Node;
• Initialize the contents of the node:
Node->value = num; Node

• Set the pointer field to nullptr: num

Node->next = nullptr;
Node
num nullptr

12
Add a Node at the End of the List
#include <iostream>
using namespace std;
struct Node {
double value; // Can be any data type
Node* next; 12.5
};

void insertNode2ListEnd(Node*& head, double newValue) { 12.5 13.5


Node* newNode = new Node;
newNode->value = newValue;
newNode->next = nullptr; // New node is the last node

if (head == nullptr) { // The list is empty


head = newNode;
}
Program output:
else {// The list is not empty 1st Node: 12.5
Node* temp = head; 2nd Node: 13.5
while (temp->next != nullptr) {
temp = temp->next;
}
temp->next = newNode; // Link last node to new node
}
}

int main() {
Node* head = nullptr; // Create the head pointer
insertNode2ListEnd (head, 12.5);
insertNode2ListEnd (head, 13.5);
cout<<"1st Node: "<< head->value <<endl;
cout<<"2nd Node: "<< head->next->value<<endl;
return 0;
} 13
Add a Node at the End of the List
#include <iostream>
using namespace std;
struct Node {
double value; // Can be any data type
Node* next; 12.5
};

void insertNode2ListEnd(Node*& head, double newValue) { 12.5 13.5


Node* newNode = new Node;
newNode->value = newValue;
newNode->next = nullptr; // New node is the last node

if (head == nullptr) { // The list is empty


head = newNode;
}
else {// The list is not empty One common bug
Node* temp = head;
while (temp->next != nullptr) {
here: use Node* head
temp = temp->next; instead of Node*& head!
}
temp->next = newNode; // Link last node to new node
}
}

int main() {
Node* head = nullptr; // Create the head pointer
insertNode2ListEnd (head, 12.5);
insertNode2ListEnd (head, 13.5);
cout<<"1st Node: "<< head->value <<endl;
cout<<"2nd Node: "<< head->next->value<<endl;
return 0;
} 14
A Reference to Pointer
• Node*& head vs. Node* head
- A reference to a pointer: Node*& head
- A regular pointer: Node* head
• A reference to a pointer can ensure that any modifications to
head within the function can affect the original linked list

15
A Reference to Pointer vs a Regular
Pointer
#include <iostream>
using namespace std;
void modifyPointer(int* p) {
int x = 10;
p = &x; // This only modifies the local copy of pointer p, not the original pointer p in main
}
Program output:
int main() {
int a = 5; Before modifyPointer: 5
int* ptr = &a; After modifyPointer: 5

cout << "Before modifyPointer: " << *ptr << endl;


modifyPointer(ptr);
cout << “After modifyPointer: ” << *ptr << endl; //Still 5
return 0;
}

a
Addr: 9000 5 Need to use a reference to pointer to change
the content of the original pointer here!
ptr
x
Addr: 7000 9000 Addr: 5000
10
p
Addr: 6000 9000 16
A Reference to Pointer vs a Regular
Pointer
#include <iostream>
using namespace std;
void modifyPointer(int* p) {
int x = 10;
p = &x; // This only modifies the local copy of pointer p, not the original pointer p in main
}
Program output:
int main() {
int a = 5; Before modifyPointer: 5
int* ptr = &a; After modifyPointer: 5

cout << "Before modifyPointer: " << *ptr << endl;


modifyPointer(ptr);
cout << “After modifyPointer: ” << *ptr << endl; //Still 5
return 0;
}

a
Addr: 9000 5 Need to use a reference to pointer to change
the content of the original pointer here!
ptr
x
Addr: 7000 9000 Addr: 5000
10
p
Addr: 6000 9000 17
Delete a Node

• Used to remove a node from a linked list


• If list uses dynamic memory, then delete node from memory
• Requires two pointers: one to locate the node to be deleted,
one to point to the node before the node to be deleted
• Example: Suppose we want to delete the node of 7.9 from the
following linked list

18
Delete a Node
void remove(Node*& head, double number) {
• Basic process: Node *nodePtr, *previousNodePtr;

- Locating the node containing if (head == nullptr) return; // If the list is empty
// Determine if the first node is the one to delete
the element to be removed if (fabs(head->value - number) < 1e-9)
{
- Unhooking the node from nodePtr = head;
head = head->next;
the list delete nodePtr;
nodePtr = nullptr;
- Deleting the memory } else
{ // Initialize nodePtr to the list head
allocated to the node nodePtr = head;

// Skip nodes whose value member is not number


while (nodePtr != nullptr && fabs(nodePtr->value -number)>1e-9)
{
previousNodePtr = nodePtr;
nodePtr = nodePtr->next;
}

// Link the previous node to the node after nodePtr, then delete nodePtr.
if (nodePtr != nullptr)
{
previousNodePtr->next = nodePtr->next;
delete nodePtr;
nodePtr = nullptr;
}
}
}
19
Delete a Node
void remove(Node*& head, double number) {
• Basic process: Node *nodePtr, *previousNodePtr;

if (head == nullptr) return; // If the list is empty


// Determine if the first node is the one to delete
if (fabs(head->value - number) < 1e-9)
{
nodePtr = head;
head = head->next;
delete nodePtr;
nodePtr = nullptr;
} else
{ // Initialize nodePtr to the list head
nodePtr = head;

// Skip nodes whose value member is not number


while (nodePtr != nullptr && fabs(nodePtr->value -number)>1e-9)
{
previousNodePtr = nodePtr;
nodePtr = nodePtr->next;
}

// Link the previous node to the node after nodePtr, then delete nodePtr.
if (nodePtr != nullptr)
{
previousNodePtr->next = nodePtr->next;
delete nodePtr;
nodePtr = nullptr;
}
}
}
20
Delete a Node
void remove(Node*& head, double number) {
• Basic process: Node *nodePtr, *previousNodePtr;

if (head == nullptr) return; // If the list is empty


// Determine if the first node is the one to delete
if (fabs(head->value - number) < 1e-9)
{
nodePtr = head;
head = head->next;
delete nodePtr;
nodePtr = nullptr;
} else
{ // Initialize nodePtr to the list head
nodePtr = head;

// Skip nodes whose value member is not number


while (nodePtr != nullptr && fabs(nodePtr->value -number)>1e-9)
{
previousNodePtr = nodePtr;
nodePtr = nodePtr->next;
}

// Link the previous node to the node after nodePtr, then delete nodePtr.
if (nodePtr != nullptr)
{
previousNodePtr->next = nodePtr->next;
delete nodePtr;
nodePtr = nullptr;
}
}
}
21
Delete a Node
void remove(Node*& head, double number) {
• Basic process: Node *nodePtr, *previousNodePtr;

if (head == nullptr) return; // If the list is empty


// Determine if the first node is the one to delete
if (fabs(head->value - number) < 1e-9)
{
nodePtr = head;
head = head->next;
delete nodePtr;
nodePtr = nullptr;
} else
{ // Initialize nodePtr to the list head
nodePtr = head;

// Skip nodes whose value member is not number


while (nodePtr != nullptr && fabs(nodePtr->value -number)>1e-9)
{
previousNodePtr = nodePtr;
nodePtr = nodePtr->next;
}

// Link the previous node to the node after nodePtr, then delete nodePtr.
if (nodePtr != nullptr)
{
previousNodePtr->next = nodePtr->next;
delete nodePtr;
nodePtr = nullptr;
}
}
}
22
Delete a Node
void remove(Node*& head, double number) {
• Basic process: Node *nodePtr, *previousNodePtr;

if (head == nullptr) return; // If the list is empty


// Determine if the first node is the one to delete
if (fabs(head->value - number) < 1e-9)
{
nodePtr = head;
head = head->next;
delete nodePtr;
nodePtr = nullptr;
} else
{ // Initialize nodePtr to the list head
nodePtr = head;

// Skip nodes whose value member is not number


while (nodePtr != nullptr && fabs(nodePtr->value -number)>1e-9)
{
previousNodePtr = nodePtr;
nodePtr = nodePtr->next;
}

// Link the previous node to the node after nodePtr, then delete nodePtr.
if (nodePtr != nullptr)
{
previousNodePtr->next = nodePtr->next;
delete nodePtr;
nodePtr = nullptr;
}
}
}
23
Delete a Node
void remove(Node*& head, double number) {
• Basic process: Node *nodePtr, *previousNodePtr;

if (head == nullptr) return; // If the list is empty


// Determine if the first node is the one to delete
if (fabs(head->value - number) < 1e-9)
{
nodePtr = head;
head = head->next;
delete nodePtr;
nodePtr = nullptr;
} else
{ // Initialize nodePtr to the list head
nodePtr = head;

// Skip nodes whose value member is not number


while (nodePtr != nullptr && fabs(nodePtr->value -number)>1e-9)
{
previousNodePtr = nodePtr;
nodePtr = nodePtr->next;
}

// Link the previous node to the node after nodePtr, then delete nodePtr.
if (nodePtr != nullptr)
{
previousNodePtr->next = nodePtr->next;
delete nodePtr;
nodePtr = nullptr;
}
}
}
24
Outline

• Introduction to Linked List


• Linked List Operations
– add a node to the end of the list
– delete a node
– traverse a linked list
– delete/destroy a linked list
• Variations of Linked List

25
Traverse a Linked List
• Visit each node in a linked list: display contents, validate data,
etc.
• Basic process:
– set a pointer to the contents of the head pointer
– while pointer is not nullptr
• process data
• go to the next node by setting the pointer to the pointer field of the
current node in the list
– end while

nodePtr points to the node containing 2.5, then the node containing 7.9,
then the node containing 12.6, then points to nullptr, and the list
traversal stops

26
Traverse a Linked List
• Example: printList()
• Basic process:
– set a pointer to the contents of the head pointer
– while pointer is not nullptr
• process data
• go to the next node by setting the pointer to the pointer field of the
current node in the list
– end while

void printList(Node* head) {


Node* current = head;// Start at the head of the list

while (current) { //Equivalent to "current != nullptr"


cout << current->value << " -> ";
current = current->next;
}
cout << "NULL" << endl;
}

27
Traverse a Linked List
void printList(Node* head) {
Node* current = head;// Start at the head of the list

while (current) { //Equivalent to "current != nullptr"


cout << current->value << " -> ";
current = current->next;
}
cout << "NULL" << endl;
}

Program output:

28
Traverse a Linked List
void printList(Node* head) {
Node* current = head;// Start at the head of the list

while (current) { //Equivalent to "current != nullptr"


cout << current->value << " -> ";
current = current->next;
}
cout << "NULL" << endl;
}

Program output:

2.5 ->

29
Traverse a Linked List
void printList(Node* head) {
Node* current = head;// Start at the head of the list

while (current) { //Equivalent to "current != nullptr"


cout << current->value << " -> ";
current = current->next;
}
cout << "NULL" << endl;
}

Program output:

2.5 ->

2.5 -> 7.9 ->

30
Traverse a Linked List
void printList(Node* head) {
Node* current = head;// Start at the head of the list

while (current) { //Equivalent to "current != nullptr"


cout << current->value << " -> ";
current = current->next;
}
cout << "NULL" << endl;
}

Program output:

2.5 ->

2.5 -> 7.9 ->

2.5 -> 7.9 -> 12.6 ->

31
Traverse a Linked List
void printList(Node* head) {
Node* current = head;// Start at the head of the list

while (current) { //Equivalent to "current != nullptr"


cout << current->value << " -> ";
current = current->next;
}
cout << "NULL" << endl;
}

Program output:

2.5 ->

2.5 -> 7.9 ->

2.5 -> 7.9 -> 12.6 ->

2.5 -> 7.9 -> 12.6 -> NULL

32
Delete/Destroy a Linked List
• The nodes of a linked list are dynamically allocated
• When deleting or destroying a linked list, we must remove all
nodes used in the list, where we need to traverse the linked list

• Basic process:
– set a pointer nodePtr to the contents of the head pointer
– while pointer is not nullptr
• use another pointer garbage to keep track of the node to be deleted
• go to the next node by setting the pointer nodePtr to the pointer field
of the current node in the list
• deallocate the memory of the current node
– end while

33
Delete/Destroy a Linked List
• Basic process:
– set a pointer nodePtr to the contents of the head pointer
– while pointer is not nullptr
• use another pointer garbage to keep track of the node to be deleted
• go to the next node by setting the pointer nodePtr to the pointer field
of the current node in the list
• deallocate the memory of the current node
– end while

void destroyList(Node*& head)


{
Node *nodePtr = head; // Start at head of list
Node *garbage = nullptr;
while (nodePtr != nullptr)
{
// garbage keeps track of node to be deleted
garbage = nodePtr;
// Move on to the next node, if any
nodePtr = nodePtr->next;
// Delete the "garbage" node
delete garbage;
garbage = nullptr;
}
head = nullptr;
}
34
Delete/Destroy a Linked List
void destroyList(Node*& head)
{
Node *nodePtr = head; // Start at head of list
Node *garbage = nullptr;
while (nodePtr != nullptr)
{
// garbage keeps track of node to be deleted
garbage = nodePtr;
// Move on to the next node, if any
nodePtr = nodePtr->next;
// Delete the "garbage" node
delete garbage;
garbage = nullptr;
}
head = nullptr;
}

nodePtr

35
Delete/Destroy a Linked List
void destroyList(Node*& head)
{
Node *nodePtr = head; // Start at head of list
Node *garbage = nullptr;
while (nodePtr != nullptr)
{
// garbage keeps track of node to be deleted
garbage = nodePtr;
// Move on to the next node, if any
nodePtr = nodePtr->next;
// Delete the "garbage" node
delete garbage;
garbage = nullptr;
}
head = nullptr;
}

nodePtr

garbage
36
Delete/Destroy a Linked List
void destroyList(Node*& head)
{
Node *nodePtr = head; // Start at head of list
Node *garbage = nullptr;
while (nodePtr != nullptr)
{
// garbage keeps track of node to be deleted
garbage = nodePtr;
// Move on to the next node, if any
nodePtr = nodePtr->next;
// Delete the "garbage" node
delete garbage;
garbage = nullptr;
}
head = nullptr;
}
nodePtr

garbage
37
Delete/Destroy a Linked List
void destroyList(Node*& head)
{
Node *nodePtr = head; // Start at head of list
Node *garbage = nullptr;
while (nodePtr != nullptr)
{
// garbage keeps track of node to be deleted
garbage = nodePtr;
// Move on to the next node, if any
nodePtr = nodePtr->next;
// Delete the "garbage" node
delete garbage;
garbage = nullptr;
}
head = nullptr;
}
nodePtr

garbage
38
Delete/Destroy a Linked List
void destroyList(Node*& head)
{
Node *nodePtr = head; // Start at head of list
Node *garbage = nullptr;
while (nodePtr != nullptr)
{
// garbage keeps track of node to be deleted
garbage = nodePtr;
// Move on to the next node, if any
nodePtr = nodePtr->next;
// Delete the "garbage" node
delete garbage;
garbage = nullptr;
}
head = nullptr;
}
nodePtr

garbage
39
Delete/Destroy a Linked List
void destroyList(Node*& head)
{
Node *nodePtr = head; // Start at head of list
Node *garbage = nullptr;
while (nodePtr != nullptr)
{
// garbage keeps track of node to be deleted
garbage = nodePtr;
// Move on to the next node, if any
nodePtr = nodePtr->next;
// Delete the "garbage" node
delete garbage;
garbage = nullptr;
}
head = nullptr;
}
nodePtr

garbage
40
Delete/Destroy a Linked List
void destroyList(Node*& head)
{
Node *nodePtr = head; // Start at head of list
Node *garbage = nullptr;
while (nodePtr != nullptr)
{
// garbage keeps track of node to be deleted
garbage = nodePtr;
// Move on to the next node, if any
nodePtr = nodePtr->next;
// Delete the "garbage" node
delete garbage;
garbage = nullptr;
}
head = nullptr;
}
nodePtr

garbage
41
Delete/Destroy a Linked List
void destroyList(Node*& head)
{
Node *nodePtr = head; // Start at head of list
Node *garbage = nullptr;
while (nodePtr != nullptr)
{
// garbage keeps track of node to be deleted
garbage = nodePtr;
// Move on to the next node, if any
nodePtr = nodePtr->next;
// Delete the "garbage" node
delete garbage;
garbage = nullptr;
}
head = nullptr;
}
nodePtr

garbage
42
Delete/Destroy a Linked List
void destroyList(Node*& head)
{
Node *nodePtr = head; // Start at head of list
Node *garbage = nullptr;
while (nodePtr != nullptr)
{
// garbage keeps track of node to be deleted
garbage = nodePtr;
// Move on to the next node, if any
nodePtr = nodePtr->next;
// Delete the "garbage" node
delete garbage;
garbage = nullptr;
}
head = nullptr;
}

nodePtr

garbage
43
Delete/Destroy a Linked List
void destroyList(Node*& head)
{
Node *nodePtr = head; // Start at head of list
Node *garbage = nullptr;
while (nodePtr != nullptr)
{
// garbage keeps track of node to be deleted
garbage = nodePtr;
// Move on to the next node, if any
nodePtr = nodePtr->next;
// Delete the "garbage" node
delete garbage;
garbage = nullptr;
}
head = nullptr;
}

nodePtr

garbage
44
Delete/Destroy a Linked List
void destroyList(Node*& head)
{
Node *nodePtr = head; // Start at head of list
Node *garbage = nullptr;
while (nodePtr != nullptr)
{
// garbage keeps track of node to be deleted
garbage = nodePtr;
// Move on to the next node, if any
nodePtr = nodePtr->next;
// Delete the "garbage" node
delete garbage;
garbage = nullptr;
}
head = nullptr;
}

nodePtr

garbage
45
Outline

• Introduction to Linked List


• Linked List Operations
– add a node to the end of the list
– delete a node
– traverse a linked list
– delete/destroy a linked list
• Variations of Linked List

46
Variations of the Linked List
• There are many ways to link dynamically allocated data
structures together. Two variations of the linked list are the
doubly linked list and the circular linked list.

• Doubly linked list: unlike the above singly-linked list, where


each node is linked to a single other node, each node of a
doubly linked list points both the next node and the previous
node.

The last node and first node have pointers to the NULL address, which
can be used to check if we have reached either end.
Variations of the Linked List
• Circular linked list: The last node in this type of linked list
points to the first node, not to the NULL address
More about Linked List
• There are other linked list operations, e.g., list copy, list
append, compute the length of a linked list, etc., but the basic
ideas are more or less the same

• Better implementation: define a linked list class!! This is


object oriented programming after all

• The Standard Template Library (STL) provides a linked list


container (more specifically, doubly linked list), which will be
introduced in Week 12
References:

[1] Gaddis, Tony, Judy Walters, and


Godfrey Muganda. Starting Out with
C++ Early Objects, 6th edition. Ch17.
Pearson, 2016.

50
Questions?

Thank You!

You might also like