Professional Documents
Culture Documents
Data Next
Head 2 5 8 10 15 ∅
Linked-lists – Traversal
void traverse (handle head)
{
handle current = head;
while ( current != φ ) {
process data at current;
current = next field of current element
}
} Head 2 5 8 10 15 ∅
curren
t
Linked-List
Add an Element after current element
void add (handle current, data_type data)
{
handle new_element;
new_element = get a new element; //step 1
data field of new_element = data; //step 1
next field of new element = next field of current; //step 2
next field of current = new_element; //step 3
}
Linked-List – Insertion
Head 2 5 8 10 15 ∅
6
Curr Step 1
new_element = get a new element;
New_Element data field of new_element = data;
Head 2 5 8 10 15 ∅
Curr Step 2
6
New_Element next field of New_Element =
next field of current;
Head 2 5 8 10 15 ∅
Curr 6
Step 3
New Element next field of current = new_element;
Linked-List – Warning:
Fragile, Handle Links With Care
• If one link is broken, you loose access to all subsequent
elements.
• What happens if you swap the following two lines in
add:
next field of new element = next field of current; //step 2
next field of current = new_element; //step 3
to
next field of current = new_element; //step 2
next field of new element = next field of current; //step 3
Head 2 5 8 10 15 ∅
7
Step 1 Curr
new_element = get a new element
data field of new_element = data New Element
Head 2 5 8 10 15 ∅
7
Curr
Step 2
New Element next field of current = new_element;
Head 2 5 8 10 15 ∅
7
Curr
New Element
Linked-List
Delete an Element after current element
void delete (handle current)
{
handle temp = next field of current;
next field of current = next filed of next element of current
// same as next field of temp
discard temp
}
Linked List - Deletion
Head 5 6 9 12 15 ∅
Head 5 6 9 12 15 ∅
Head 5 6 9 12 15 ∅
temp
This element is no longer
Curr accessible
Garbage
Head 2 5 8 10 15 ∅
7
Curr
New Element
Linked-lists
Array Implementation
• Handle is the index of the next element in the array
struct node {
element_type data; // data
int next; // pointer to the next
};
Linked-lists
Array Implementation
class List {
private:
int head;
int available;
int size;
node * NodeList;
public:
List (int s = 10); // constructor - default size =
10
~List( ) { delete [ ] NodeList; } // destructor
void printList();
int search (int data);
bool add (int data); // add in ascending order
void remove (int data); // delete node from the list
}
Linked-lists – Array Implementation
List::List(int s)
{
if (s <= 0) size = 10; else size = s;
nodeList = new node [size]; // create array
for (int i = 0; i < size-1; i++) // initialize
nodeList[i].next = i+1; // points to the next
nodeList [size-1].next = -1; // last node – there is no next
available = 0;
head = -1; // -1 is used as φ
}
index 0 1 2 3 4 5 6 7 8 9
next 1 2 3 4 5 6 7 8 9 -1 available = 0
data - - - - - - - - - - head = -1
bool List::add (elem_type data) {
int curr, prev, temp;
if (available == -1) // check if space is available
return false;
else {
temp = nodeList [available].next; // step 1 – initialize
nodeList [available].data = data;
prev = curr = head; // search – where to insert
while (curr != -1 && nodeList [curr].data < data ) {
prev = curr;
curr = nodeList [curr].next;
}
nodeList [available].next = curr; // insert – step 2
if (curr == head) // insert – step 3: reset head
head = available;
else
nodeList [prev].next = available; // insert – step 3
available = temp; // reset available
return true;
}
}
Initial state (available = 0, head = -1)
index 0 1 2 3 4 5 6 7 8 9
next 1 2 3 4 5 6 7 8 9 -1
data - - - - - - - - - -
index 0 1 2 3 4 5 6 7 8 9
next -1 2 3 4 5 6 7 8 9 -1
data 5 - - - - - - - - -
Add 7 (available = 2, head = 0)
index 0 1 2 3 4 5 6 7 8 9
next 1 -1 3 4 5 6 7 8 9 -1
data 5 7 - - - - - - - -
index 0 1 2 3 4 5 6 7 8 9
next 1 2 -1 4 5 6 7 8 9 -1
data 5 7 8 - - - - - - -
Add 6 (available = 4, head = 0)
index 0 1 2 3 4 5 6 7 8 9
next 3 2 -1 1 5 6 7 8 9 -1
data 5 7 8 6 - - - - - -
index 0 1 2 3 4 5 6 7 8 9
next 3 2 -1 1 0 6 7 8 9 -1
data 5 7 8 6 2 - - - - -
Add 7 (available = 1, head = 4)
index 0 1 2 3 4 5 6 7 8 9
next 3 5 -1 2 0 6 7 8 9 -1
data 5 - 8 6 2 - - - - -
index 0 1 2 3 4 5 6 7 8 9
next 3 0 -1 2 1 6 7 8 9 -1
data 5 4 8 6 2 - - - - -
void List::remove (elem_type data)
{
int curr, prev;
curr = prev = head; // search
while (curr != -1 && l->nodeList [curr].data < data ) {
prev = curr;
curr = nodeList [curr].next;
}
if (curr != -1) { // if not end of list
if (nodeList[curr].data == data) { // if found
if (curr == head) { // if it is the first node
head = nodeList[head].next;
}
else
nodeList [prev].next = nodeList[curr].next;
nodeList[curr].next = available; // add curr to available list
avialable = curr; // reset available
}
}
}
Delete 2 (available = 4, head = 1)
index 0 1 2 3 4 5 6 7 8 9
next 3 0 -1 2 5 6 7 8 9 -1
data 5 4 8 6 - - - - - -
index 0 1 2 3 4 5 6 7 8 9
next 3 0 4 -1 5 6 7 8 9 -1
data 5 4 - 6 - - - - - -
Linked List - Implementation using
Dynamically Allocated Storage
• Handle will be the pointer (memory address) of an element
in the linked list.
• Space may be acquired at run-time on request from free
store using new.
• At a point in time when a memory area pointed to by a
pointer is no longer required, it can be returned back to
free store using delete.
• We should always return storage after we no longer need
it.
• Once an area is freed, it is improper and quite dangerous to
use it.
Dangling References
A dangling reference is an access path that continues to exist
after the life time of the associated data object.
delete q; q = NULL; p
What happens to p? q φ
p
q = p;
q
Class LinkedList {
private:
Node * head;
public:
LinkedList() { head = NULL; }
void add (int data);
void remove (int data);
void print ();
~LinkedList();
};
void LinkedList:: print()
{
Node *current = head;
while (current != NULL) {
cout << current->data;
current = current->next;
}
Head 2 5 8 10 15 ∅
curren
t
bool LinkedList::add(int data)
{
Node *temp = new Node;
if (temp == NULL) return false;
else {
temp->data = data;
Node *current, *previous;
current = head;
while (current != NULL && current->data < data;) {
previous = current;
current = current->next;
}
temp -> next = current; temp
if (current == head) head = temp;
else previous->next = temp;
9
return true;
}
}
Head 2 5 8 10 15 ∅
Previous Current
void LinkedList::remove(int data)
{
Node *current, *previous;
current = head;
while (current != NULL && current->data < data) {
previous = current;
current = current->next
}
if (current != NULL && current->data == data) {
if (current == head)
head = head -> next;
else
previous->next = current->next;
delete current;
}
}
Linked List Implementation of Stacks
struct Node {
int data;
Node *previous;
};
Class Stack {
private:
Node * stk_ptr;
public:
Stack() { stk_ptr = NULL; }
void push (int data);
bool pop (int &data);
bool isEmpty () { stk_ptr == NULL; }
~Stack();
};
Linked List Implementation of Stacks
bool Stack::push (int data)
{
Node * temp = new Node;
if (temp == NULL) return false;
else {
temp->data = data;
temp->previous = stk_ptr;
stk_ptr = temp;
return true;
}
φ
}
Stk_ptr temp
bool Stack::pop (int &data)
{
Node * temp = stk_ptr;
if (!isEmpty()) {
data = temp->data;
stk_ptr = stk_ptr->previous;
delete temp;
return true;
}
else
return false;
}
φ
Stk_ptr
temp
Linked List
Head
A
2 5 8 10 15 ∅
Head
A
2 5 8 10 15 ∅
temp1 temp2
A Function Returning An Object
LinkedList emit()
{
LinkedList temp;
temp.add(7); temp.add(20); temp.add(5); temp.add(8);
// build the linked list
return temp;
}
void usingEmit()
{
LinkedList myList = emit();
myList.add(2); // what happens?
}
• This is illegal! Why?
• Head of myList is a dangling reference!
• Just before leaving the function
Head 2 5 8 10 15 ∅
temp
Head
“hidden
temp”
Head
temp
Head
2 5 8 10 15 ∅
“hidden
temp”
Deep vs Shallow Copy
• myList = yourList
Summary
• Destructor
• Copy constructor
• Assignment operator overloading
• Check for out of memory condition
void LinkedList::add(int data)
{
Node *temp = new Node;
temp->data = data;
Node *current, *previous;
current = head;
while (current != NULL && current->data < data) {
previous = current;
current = current->next
}
temp -> next = current;
if (current == head) head = temp;
else previous->next = temp;
}
void LinkedList::remove(int data)
{
Node *current, *previous;
current = head;
while (current != NULL && current->data < data) {
previous = current;
current = current->next;
}
if (current != NULL && current->data == data) {
if (current == head)
head = head -> next;
else
previous->next = current->next;
delete current;
}
}
Eliminating Boundary Conditions – Dummy Head Node
Class LinkedList {
private:
Node head; // instead of Node *head
public:
LinkedList() { head.next = NULL; }
void add (int data);
void remove (int data);
void print ();
~LinkedList();
};
∅ Empty list
head
2 5 8 10 15 ∅
head
void LinkedList:: print()
{
Node *current = head.next;
while ( current != NULL) {
cout << current->data;
current = current->next;
}
}
void LinkedList::add(int data)
{
Node *temp = new Node;
temp->data = data;
Node *current, *previous;
previous = &head;
current = previous->next;
while ( current != NULL && current->data < data) {
previous = current;
current = current->next
}
temp -> next = current;
// if (current == head) head = temp; // take this out
// else previous->next = temp;
previous->next = temp;
}
Linked-List
Inserting a Node
previous current
2 5 8 10 15 ∅
head
1
temp->next = current;
previous->next = temp;
temp
void LinkedList::remove(int data)
{
Node *current, *previous;
previous = &head;
current = previous->next;
while (current != NULL && current->data < data) {
previous = current;
current = current->next;
}
if (current != NULL && current->data == data) {
// if (current == head)
// head = head -> next;
// else
previous->next = current->next;
delete current;
}
}
Linked-List
Deleting a Node
previous current
head 2 5 8 10 15 ∅
previous->next = current->next;
delete current;
Linked-List
Deleting the Node pointed to by a
pointer ‘p’, having no previous pointer
p t
head
2 5 8
10
10 15 ∅
2 5 8 10 15
2 5 8 10 15
Linked-List
Deleting the Node pointed to by a pointer ‘p’, having no previous pointer
p->data = p->next->data;
t = p->next; 5
p->next = t->next;
delete t; 7 12
Boundary Conditions
Class CircularList {
private:
Node head; // instead of Node *head
public:
CircularList() { head.next = &head; }
void add (int data);
void remove (int data);
void print ();
~CircularList();
};
head
void CircularList::add(int data)
{
Node *temp = new Node;
temp->data = data;
Node *current, *previous;
previous = &head;
current = previous->next;
while ( current != &head && current->data < data ) {
current = current->next ;
previous = current;
}
temp -> next = current;
previous->next = temp;
}
2 5 8 10 15
head
Advantages
• Every node is accessible from any node.
• That is, from a given node, all nodes can be
reached by simply following the links.
• Example: Round Robin Queue for resource
sharing such as process scheduling
Doubly Linked-List
• Some times it is important to be able to go
back and forth from a given point in the list.
• We can achieve it with the help of doubly
linked lists.
struct DoubleListNode {
int data;
DoubleListNode *next;
DoubleListNode *previous;
};
p == p->next->previous
p == p->previous->next
Doubly Linked-List
Class DoublyLinkedList {
private:
DoubleListNode head;
public:
DoublyLinkedList() { head.next = head.previous = &head; }
void add (int data);
void remove (int data);
void print ();
~DoublyLinkedList();
};
Doubly Linked-List
2 5 7 10 15
Doubly Linked-List
Inserting a Node
2 5 7 10 15
p->previous = current;
current 6 p->next = current->next;
current->next->previous = p;
current->next = p;
p
Order is very important!
Doubly Linked-List
Inserting a Node
Undesirable links
2 5 7 10 15
2 5
7 10 15
current
current->previous->next = current->next;
current->next ->previous = current->previous;
delete current;