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

Lec13. Linked List

The document discusses linked lists and how to implement them using nodes. It explains what linked lists are, how to create list nodes with data and pointer fields, and how to connect multiple nodes to form a linked list. It also covers traversing a linked list using a current pointer variable instead of modifying the head pointer.

Uploaded by

Majd AL Kawaas
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)
43 views

Lec13. Linked List

The document discusses linked lists and how to implement them using nodes. It explains what linked lists are, how to create list nodes with data and pointer fields, and how to connect multiple nodes to form a linked list. It also covers traversing a linked list using a current pointer variable instead of modifying the head pointer.

Uploaded by

Majd AL Kawaas
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/ 46

Intro to Data Structure

Singly and Doubly


Linked List
Reading: Chapter 3
Data Structures and
Algorithms in C++
Second Edition
Why Data Structures?
• We have a list of N (= 10 million) students (with names and non-
contiguous IDs) stored in a file
• We want to support (infinitely many):
– Loads from disk (talk about memory)

– Insertions of new students

– Updates of student names

– Searches by name and/or ID

– Deletions of students

– Writes to disk

• How would you go about it?


• Arrays? 16-2
Why Data Structures?
• When would we sort the data?
• What would be the initial size of the array(s)?
• By how much do we increase the size of an array?
• Do we decrease the size?
• How do we deal with empty slots?
• Arrays are nice and simple for storing things in a certain order, but
they have drawbacks:
– They are not very adaptable
– For instance, we have to fix the size n of an array in advance, which makes
resizing an array difficult
– Insertions and deletions are difficult because elements need to be shifted
around

16-3
Singly Linked List
• We now explore the implementation of an alternate sequence,
known as the singly linked list
• A linked list, in its simplest form, is a collection of nodes that
together form a linear ordering

Copyright © 2017 Pearson Education, Ltd. All rights reserved. 16-4


Pointers to same type
• Objects can point to different type objects as fields
• Also, objects can point to same type objects as fields

• What would happen if we had a class that declared one of its own
type as a field?

class Strange {
public:
name Other
string name;
“Adam”
Strange *other;
};
• Strange object has two fields:
− One can store a single string name
− One is a pointer to another Strange object.
• We can use it to store a list of string values
A list node class
• List Node: a single element/object of a list structure.
• Each node contains its own data.
• Each list node object stores data and pointer(s):
– data can be of any primitive types or object of any class, etc.
– pointer (usually called next) is an object address that points to the next node
in the list.

Pseudocode
Class ListNode Data portion of Node
dataType data1;
dataType data2;

ListNode *next; link to another Node object

dat nex dat nex dat nex data next


a t a t a t 9 null
42 -3 17
What is a linked list ele
m
next

• A simple IntNode class : 18


class IntNode {
– member elem stores the element stored in this public:
node, which in this case is a integer int elem;
IntNode* next;
– member next stores a pointer to the next
IntNode();//optional
node };
• Linked lists gather objects of the same type in sequence, accessible
using pointers.
– These objects are usually called Nodes
• first, head, front, or list is used to keep track of the linked list.
– It is not a Node but a pointer to a node
– If you keep a reference to the front of the list, then you can get to anything in
it.
head ele nex ele nex ele nex elem next
m t m t m t 9 null
42 -3 17
List node client example
• Let us construct a list that stores the sequence of values [42, -3, 17].
• There are three values then we need three nodes that are linked together.
IntNode *list;
• The variable list is not itself a node but a variable capable of referring to a
node.
list ?

• ? Will be replaced with a reference to a node which means this box does not have
data or next field.
• We do not have the actual node yet. To have it, we should call new:
elem next
list = new IntNode(); list 0

• .
IntNode default construct initializes the fields as:
– Data initialized to 0
– Next initialized to null ( in these slides / indicates null)
#include <iostream>
using namespace std;
class IntNode {
public: List node
int elem;
IntNode* next; tester
IntNode();
}; example
int main() {
IntNode *list;
list = new IntNode();
list->elem = 42;
list->next = new IntNode();
list->next->elem = -3;
list->next->next = new IntNode();
list->next->next->elem = 17;
cout << list->elem;
cout <<" " << list->next->elem;
cout <<" " << list->next->next->elem;
}
IntNode::IntNode():elem (0), next(NULL){}

elem next elem next elem next


list 0 0-3 0
17 null
.

42

Output 42 -3 17
List node with constructor, private data, friends
#include <iostream>
using namespace std;

class IntNode {
private:
int elem;
IntNode* next;
public:
IntNode();
IntNode(int elem);
friend void manipulateList(IntNode *p);
};

void manipulateList(IntNode *p);

int main() {
IntNode *list;
manipulateList(list);
}

IntNode::IntNode():elem (0), next(NULL){}


IntNode::IntNode(int elem):elem (elem), next(NULL){}

void manipulateList(IntNode *list){


list = new IntNode(43);
list->next = new IntNode(-3);
list->next->next = new IntNode(17);
list->next->next->next = NULL;
cout << list->elem <<" " << list->next->elem <<" "
<< list->next->next->elem;
}
List node w/ constructor
void manipulateList(IntNode *list){
list = new IntNode(42);
list->next = new IntNode(-3);
list->next->next = new IntNode(17);
list->next->next->next = NULL;
cout << list->elem <<" " << list->next->elem <<" "
<< list->next->next->elem;
}

elem next elem next elem next


list 0 0 017
.

42 -3 null

Output 42 -3 17
Pointers vs. objects
variable = value; //assume left side is a pointer variable, right can be an address
null
a variable (left side of = ) is an arrow (the base of an arrow)
a value (right side of = ) is an object (a box; what an arrow points at)
• For the list at right: ele nex
– q = a->next; p m t
2
means to make q point at 20
– a->next = p; 1 ele nex 2 ele nex
a m m
means to adjust where points t1 t
Reassigning references 10 20
• a->next = b->next; q
– "Make the variable a->next refer to the
same value as b->next." elem next elem next
a
– Or, "Make a->next point to the same 10 20
place that b->next points."
elem next elem next
b
30 40
Traversing a list?
• Suppose we have a long chain of list nodes:

ele next ele next ele next


head m m ... m
10 20 990
• How would we print the data values in all the nodes?
– Start at the head of the list.
– While (there are more nodes to print):
• Print the current node's element.
• Go to the next node.
• How do we walk through the nodes of the list?
while (head != null) {
cout << head->elem;
head = head->next; // move to next node
}
• What's wrong with this approach?
– it loses the linked list as it prints it!)
Traversing a list with a current reference
• Don't change list. Make another variable, and change that.
– A IntNode variable is NOT a IntNode object
IntNode* current = head;
• What happens to the picture below when we write:
current = current->next;

ele nex ele nex ele nex


head m m m
t t ... t
current 10 20 990

• The correct way to print every value in the list:


IntNode* current = head;
while (current != null) {
cout << current->elem;
current = current->next; // move to next node
}
– Changing current does not damage the list.
A IntLinkedList class
• Let's write a class named IntLinkedList with the following interface
bool empty() const; // is list empty?
void addFront(int value); // add to front of list
int front() const; // get front element
void removeFront(); // remove front item
list
void showList(); //print the elements
//we can add more methods when needed
– The list is internally implemented as a chain of linked nodes
• The IntLinkedList keeps a reference to its head as a field
• NULL is the end of the list; a NULL head signifies an empty list

InLinkedtList
IntNode IntNode IntNode
head ele nex ele nex ele nex
empty() m t m t m t
addFront(value)
front() 42 -3 17
removeFront(i)
showList()
A IntLinkedList class
class IntNode {
private:
int elem;
IntNode* next;
public:
IntNode();
IntNode(int data);
friend class IntLinkedList;
};
class IntLinkedList {
private:
IntNode *head;

public:
IntLinkedList();
~IntLinkedList();
void addFront(int value); // add to front of list
bool empty() const; // is list empty?
int front() const; // get front element
void removeFront(); // remove front item list
void showList();
};
Adding to an empty list or to its front
• Before adding -3, list is empty:
head ele next
m
head -3
ele next
v m
42
– To add -3, we must create a new node and attach it to the list.
head = new IntNode(-3);
– To add 42 to the front, we must create a new node and attach it
to the list.
IntNode *v = new IntNode(42);
v->next = head;
head = v;
void IntLinkedList::addFront(int value){
IntNode *v = new IntNode(value);
v->next = head;
head = v;
}
Getting/removing the front node
• To get the front node element: return head->elem
ele next ele next ele next
m m m
head
42 -3 17
int IntLinkedList::front() const {
return head->elem;
}

• To remove the front node: void IntLinkedList::removeFront(){


IntNode *v = head; IntNode *v = head;
Head = head->next; head = head->next;
delete v;
delete v;
v=NULL;
}

v
ele next ele next ele next
m m m
head
42 -3 17
Check If a list is empty and print a list
• To check if a list is empty or not just we check the head
return (head==NULL); bool IntLinkedList::empty() const{
return (head==NULL);
}

• To print every value in the list, we have to traverse it:


void IntLinkedList::showList(){
IntNode *v = head;
while (v!=NULL){
cout << v->elem << " ";
v=v->next;
}
}

ele nex ele nex ele nex


head m m m
t t ... t
v 10 20 990

16-19
Construct and destruct
• To check if a list is empty or not just we check the head
IntLinkedList::IntLinkedList():head(NULL) {}
IntLinkedList *list;
list = new IntLinkedList();
List->addFront(5);
list head ele next
m
empty()
addFront(value) 5
front()
removeFront(i)
show()

• To destruct a list, we have to remove all the dynamically allocates


nodes IntLinkedList::~IntLinkedList(){
while (!empty()) removeFront();
}

ele nex ele nex ele nex


head m m m
t t ... t
10 20 990
IntLinkedList::IntLinkedList():head(NULL) {}
IntLinkedList::~IntLinkedList(){
while (!empty()) removeFront();
}
void IntLinkedList::addFront(int value){
IntNode *v = new IntNode(value);
v->next = head;
head = v;
}
bool IntLinkedList::empty() const { return (head==NULL); }

int IntLinkedList::front() const { return head->elem;}

void IntLinkedList::removeFront(){
IntNode *v = head;
head = head->next;
delete v;
v=NULL;
}
void IntLinkedList::showList() {
IntNode *v = head;
while (v!=NULL){
cout << v->elem << " ";
v=v->next;
}
}
int main() {
IntLinkedList *list = new IntLinkedList();
list->addFront(43);
list->addFront(143);
list->addFront(243);
list->showList();

list head
ele next
empty() ele next m
addFront(value)
ele next m
front() m 43
removeFront(i) 143
show() 243
Implementing Singly Linked List of String Nodes
• Similar to what we have done with IntNode and IntLinkedNode, we define
two classes StringNode and StringLinkedList
– member elem in StringNode stores the element stored in this node, which in this
case is a string and memember next stores a pointer to the next node
– We make StringLinkedList class a friend to StringNode, so that it can access
the StringNode’s private members
class StringNode { // a node in a list of strings
private:
string elem; // element value
StringNode* next; // next item in the list
friend class StringLinkedList; // provide StringLinkedList access
};

class StringLinkedList { // a linked list of strings


public:
StringLinkedList(); // empty list constructor
~StringLinkedList(); // destructor
bool empty() const; // is list empty?
const string& front() const; // get front element
void addFront(const string& e); // add to front of list
Void removeFront(); // remove front item list
private:
StringNode* head; // pointer to the head of list
}; CMPS 212 16-23
Implementing a Singly Linked List
StringLinkedList::StringLinkedList():head(NULL) {} // constructor

StringLinkedList::~StringLinkedList(){ // destructor
while (!empty()) removeFront();
}

void StringLinkedList::addFront(const string& e) { // add to front of list


StringNode* v = new StringNode; // create new node
v−>elem = e; // store data
v−>next = head; // head now follows v
head = v; // v is now the head
}
bool StringLinkedList::empty() const { // is list empty?
return (head==NULL);
}

string& StringLinkedList::front() const { // get front element


return head->elem;
}

void StringLinkedList::removeFront(){ // remove front item


StringNode* old = head; // save current head
head = old−>next; // skip over old head
delete old; // delete the old head
} CMPS 212 16-24
Insertion to/removal from the Front of a Singly Linked List

CMPS 212 16-25


Implementing Generic Singly Linked List
• Similar to what we have done, we define two template classes SNode and SLinkedList

template <class> class SLinkedList; //you add this line to let SNode become aware of

//template class SLinkedList


template <class E>
class SNode {
private:
E elem;
SNode<E> * next;
friend class SLinkedList<E>;
};
template <typename E> //typename or class keywords
class SLinkedList {
private:
Snode<E> *head;
public:
SLinkedList();
~SLinkedList();
void addFront(const E & value); // add to front of list
bool empty() const; // is list empty?
E & front() const; // get front element
void removeFront(); // remove front item list
void showList();
}; CMPS 212 16-26
Implementing a Generic Singly Linked List
template <typename E>
SLinkedList<E>::SLinkedList():head(NULL) {}

template <typename E>


SLinkedList<E>::~SLinkedList(){
while (!empty()) removeFront();
}

template <typename E>


void SLinkedList<E>::addFront(const E & value){
SNode<E> *v = new SNode<E>;
v->elem = value;
v->next = head;
head = v;
}

template <typename E>


bool SLinkedList<E>::empty() const{
return (head==NULL);
}

template <typename E>


E& SLinkedList<E>::front() const {
return head->elem;
}
CMPS 212 16-27
template <typename E>
void SLinkedList<E>::removeFront(){
SNode<E> *v = head;
Implementing a
head = head->next;
delete v;
Generic Singly
}
v=NULL;
Linked List
template <class E>
void SLinkedList<E>::showList(){
SNode<E> *v = head;
cout << endl ;
while (v!=NULL){
cout << v->elem << " ";
v=v->next;
}
cout << endl ;
}

int main() {
SLinkedList<string> list;
string first = "Laure";
list.addFront("kkkk");
list.addFront(first);
cout <<endl<<list.front();
SLinkedList<int> *list1 = new SLinkedList<int>();
list1->addFront(1);
list1->addFront(6);
list1->showList();
cout <<endl<<list1->front();
}
Arrays vs. Linked Lists

• How would you keep a linked list sorted?


• How would you search for an elements (by value or by index)?
• How would you insert an element at a specific position?
• How would you solve our students problem?
– We are going to add more methods/operations/ behaviors

– Improve the list to have links in both directions

– Introduce Tree later on in this course

CMPS 212 29
Adding to the tail of the list
• Consider following list:
data next data next
head 42 -3
data next
current v 17
– To add a node, we must modify the next pointer of the node before the
place you want to add/change
IntNode *v = new IntNode(17);
IntNode current = head;
while (current->next != null) {
current = current->next;
}
current->next = v; void IntLinkedList::addEnd(int value){
IntNode *v = new IntNode(value);
if (head==NULL)
head=v;
else{
IntNode *current = head;
while (current->next!=NULL){
current=current->next;
}
current->next=v;
}
}
Remove from the tail of the list
• Consider following list:
data next data next data next
head 42 -3 17

v
• In order to delete a node, we need to update the next link of the
node immediately preceding the deleted node

void IntLinkedList::removeEnd(){
if (head->next==NULL)
removeFront();
else{
IntNode *v = head;
while (v->next->next!=NULL){
v=v->next;
}
delete v->next;
v->next = NULL;
}
}
The size() method
// Returns current number of elements
int IntLinkedList::size(){
int count = 0;
IntNode * current = head;
while( current != NULL) {
current = current->next;
count++;
}
return count;
}

count 3
01
2
data next data next data next
head 42 -3 17
current
Adding a node between two nodes
• Consider the following list:
element 0 element 1 element 2
head data next data next data next
42 -3 17
before data next
5
v

• To add a node between two nodes, we first point to the node before
the location of the new node (Example: to add at index 2)
IntNode *v = new IntNode(5);
IntNode *before = head;
for (int i = 0; i < index - 1; i++)
before = before->next;
v->next = before->next;
before->next = v;
remove a node between two nodes
// Removes value at given index from list.
// Precondition: 0 <= index < size()
void IntLinkedList::remove(int index){
IntNode* v = head;
if (index == 0) {
// special case: removing first element
head = head->next;
} else {
IntNode* current = head;
// removing from elsewhere in the list
for (int i = 0; i < index - 1; i++) {
current = current->next;
}
v= current->next;
current->next = current->next->next;
}
delete v;
v=NULL;
}
data next data next data next
front 42 -3 17
current
v
Doubly Linked Lists
• Removing/adding an element at the tail of a singly linked list is not
easy.
– Indeed, it is time consuming to remove/add any node other than the head in a
singly linked list,
– we do not have a quick way of accessing the node immediately preceding the
one we want to remove or add.
– For some applications, it would be nice to have a way of going both directions
in a linked list.
• Concretly, How to see a doubly linked list?
• A sequence of nodes « back to back ».
• Each node gives one hand to its successor and one hand to its predecessor.
Doubly Linked List
• Doubly linked list allows to traverse backward as well as forward
through the list.
–Each node has two references to other nodes instead of one
next: points to the next node in the list
• Last node has no next node (no successor)
 prev: points to the previous node in the list
• first node has no previous node (no predecessor)
–Each list uses two pointer to access its first and last nodes
 header : refers to the first node
trailer : refers to the last node

trailer

header

JFK PVD SFO AAA

next next next next null

null prev prev prev prev


Doubly Linked List- DNode class
typedef string Elem; // list element type
class DNode { // doubly linked list node
private:
Elem elem; // node element value
DNode* prev; // previous node in list
DNode* next; // next node in list
public:
DNode();
DNode(const Elem & data);
friend class DLinkedList; // allow DLinkedList access
};

trailer

header

JFK PVD SFO AAA

next next next next null

null prev prev prev prev

37
Doubly Linked List- DLinkedList
class DLinkedList { // doubly linked list
public:
DLinkedList(); // constructor
~DLinkedList(); // destructor
bool empty() const; // is list empty?
const Elem& front() const; // get front element
const Elem& back() const; // get back element
void addFront(const Elem& e); // add to front of list
void addBack(const Elem& e); // add to back of list
void removeFront(); // remove from front
void removeBack(); // remove from back
private: // local type definitions
private:
DNode* header;
DNode* trailer;

};

trailer

header

JFK PVD SFO AAA

next next next next null

null prev prev prev prev


Doubly Linked List- DLinkedList
DNode::DNode():elem(""), next(NULL), prev(NULL){}
DNode::DNode(const Elem & data):elem(data), next(NULL), prev(NULL){}

DLinkedList::DLinkedList(): header(NULL), trailer(NULL) { }


DLinkedList::D̃LinkedList() { // destructor
while (!empty()) removeFront(); // remove all
}

bool DLinkedList::empty() const {


return ((header==NULL) && (trailer==NULL));
}

const Elem& DLinkedList::front() const { // get front element


return header−>elem;
}

const Elem& DLinkedList::back() const { // get back element


return trailer−>elem;
}
Doubly Linked List- DLinkedList
void DLinkedList::addFront(const Elem & value){
DNode* v = new DNode(value);
if (header == NULL) //check if it is an empty list
trailer = v;
else trailer null
header->prev = v; header
v->next = header; null
header = v;
} v

value

next null

null prev

trailer

header
v

value AAA BBB CCC DDD


null next next next next
next null
null prev prev prev prev 40
null prev
Doubly Linked List
void DLinkedList::addBack(const Elem& e) { // add to back of list
DNode* v = new DNode(e);
if (trailer == NULL) //check if the list is empty
header = v;
else
tailer->next = v;
v->prev = trailer;
trailer = v;
}

trailer
v
header

aaa bbb ccc ddd


e
next next next next null
next null
null prev prev prev prev
null prev

41
Doubly Linked List-Deletion
void DLinkedList::removeFront()
{
DNode* v=header;
if (header->next == NULL) //if only one item in the list
trailer = NULL;
else
header->next->prev = NULL;
header = header->next;
delete v;
v=NULL;
}
trailer

header

ssss aaaa bbbb dddd

next next next next null

v null prev prev prev prev


null
Doubly Linked List-Deletion
void DLinkedList::removeBack()
{
DNode* v = trailer;
if (trailer->prev == NULL) //if only one item in the list
header = NULL;
else
trailer->prev->next = NULL;
trailer = trailer->prev;
delete v;
v=NULL;
}
trailer

header

aaaa bbbb nnnn null gggg


next next next next null

null prev prev prev prev

v
Doubly Linked List
•Forward Traversal: start at the first node until the end of the list
DNode *current = header;
while (current != null)
current = current->next;

trailer

header

aaa nnnn jjjj frfff

next next next next null


null prev prev prev prev

current

44
Doubly Linked List
•Backward Traversal: start at the last node until the beginning of the list
DNode current =trailer;
while (current != NULL)
current = current->prev;

trailer

header

aaa bbb vvv xxxx

next next next next null


null prev prev prev prev

current

45
Doubly Linked List
Add a node at a specific insertion point in the list
DNode *v = new DNode(e);
DNode *current = header;

while (current != NULL && key != current->data)


current = current->next;
current->prev->next = v;
v->prev = current->prev;
v->next = current;
current->prev = v;

trailer
header current

aaaa bbbb target ddd

next next next next null

null prev prev prev prev


e

next

prev
v 46

You might also like