CSE240 Doubly
Linked Lists
BY GARRETT GUTIERREZ
What is a doubly linked list?
 A doubly linked list is a list of elements.
 Each element points to the next element in
the list as well as the previous element in the
list.
 Why use a doubly linked list over a single
linked list?
Doubly linked lists allow easy traversal forward
and backward through the list.
How to get started?
 Create either a struct or an object to represent a node
in the linked list.
 It has a reference to the previous and next items in the
linked list.
 Use a tail pointer, in addition to a head pointer.
struct node
{
int id;
char* name; // A pointer, not an array
struct node* previous; // pointer to previous node
struct node* next; // pointer to next node in list
};
Q1. What is the size of the
node?.
(A) 4 bytes
(B) 16 bytes
(C) more than 16 bytes?
(D) The size is unknown at
compilation.
Think: How to obtain
memory for name?
Insertion: Case by Case
 Inserting an element into a doubly linked list
is very similar to inserting an element into a
singly linked list.
 Additionally, just make the previous pointer
point to the previous item in the linked list.
 There are three cases for sorted insert:
1. Add at the beginning
2. Add at an arbitrary location
3. Add to the end
Case 0: The linked list is empty
 Make the new node the head
 Set previous and next
to NULL of head
 Set tail to head
head NULL
NULLhead name
id
previous next
if (head == NULL)
{
head = newNode;
head->next = NULL;
head->previous = NULL;
tail = head;
return;
}
tail
NULL
Q2. When is the tail pointer equals to the
head pointer? Select all that apply.
(A) When the list is empty
(B) When there is one node only
(C) When there are more than one node
(D) They never equal.
Case 1: Add element to beginning
Set newNode->next to head->next
Set head->previous to newNode
Set head to the newNode
Make the newNode previous NULL
head
NULL
if (strcmp(newNode->name,
head->name) < 0)
{
newNode->next = head;
head->previous = newNode;
head = newNode;
head->previous = NULL;
return;
}
name
id
previous next
name
id
previous next
name
id
previous next
head
NULL
newNode
The old head
NULL
NULL
Q3. Which node’s previous
pointer is NULL?
(A) The first node
(B) The second node
(C) The last node
(D) No node.
Case 2: Add at an arbitrary location
 Use a iterator pointer and a follower pointer.
 follower always is one element behind
iterator
struct node* iterator = head;
struct node* follower = iterator;
Case 2: Add to an arbitrary location
 Set newNode->next to iterator
 Set iterator->previous to newNode
 Set the newNode->previous to follower
 Set follower->next to newNode
head name
id
previous next
name
id
previous next
NULL
name
id
previous next
newNode
follower iterator
NULL
Case 3: Add to the end
 Go through the entire list until iterator is NULL
 Set follower->next to newNode
 Set newNode->previous to follower
 Set newNode->next to NULL
 Set the tail to newNode
head name
id
previous next
name
id
previous next
NULL
follower iterator
name
id
previous next
tail
NULL
Q4. Is case 3 included in case 2?
(A) Yes, case 3 can be simply
removed
(B) No. case 3 is not included in
case 2.
Explain your answer
Putting it Together
if (head == NULL) { // Case 0
head = newNode;
head->next = NULL;
head->previous = NULL;
tail = head;
return;
}
else { Case 1
if (strcmp(newNode->name, head-
>name) < 0) {
newNode->next = head;
head->previous = newNode;
head = newNode;
head->previous = NULL;
return;
}
}
};
iterator = head;
follower = iterator;
while (iterator != NULL) { // Case 2
if (strcmp(newNode->name, iterator->name) < 0)
{
newNode->next = iterator;
iterator->previous = newNode;
newNode->previous = follower;
follower->next = newNode;
return;
}
follower = iterator;
iterator = iterator->next;
}
follower->next = newNode; // Case 3
newNode->previous = follower;
newNode->next = NULL;
tail = newNode;
return;
Searching Doubly Linked List: Front
1. Start at the head.
2. Go until the iterator is
NULL
3. Compare the value of
the iterator with a value.
4. If found, return the
element.
5. Else, set iterator to next.
6. If not found, return NULL.
struct node* iterator = head;
while (iterator != NULL)
{
if (strcmp(iterator->name,
token) == 0)
{
return iterator;
}
iterator = iterator->next;
}
printf("The element does not
exist.nn");
return iterator;
Searching Doubly Linked List: Back
1. Start at the tail.
2. Go until the iterator is NULL
3. Compare the value of the
iterator with a value.
4. If found, return the element.
5. Else, set iterator to previous.
6. If not found, return NULL.
struct node* iterator = tail;
while (iterator != NULL)
{
if (strcmp(iterator->name,
token) == 0)
{
return iterator;
}
iterator = iterator->previous;
}
printf("The element does not
exist.nn");
return iterator;
Q5. How many lines of code are different
when searching forwards and backwards?
(A) 0 (B) 1 (C) 2 (D) 4
Which lines of code?
Deleting an Element
 Case 1: List only has one item
 Delete heap memory for name
 Delete heap memory for head
 Set head to NULL
 Set tail to NULL
NULLhead name
id
previous next
if (head == toDelete &&
head->next == NULL)
{
free(head->name);
free(head);
head = NULL;
tail = NULL;
return;
}
tail
NULL
Q6. Advance Question: Why
do call free twice?
free(head->name);
free(head);
To be discussed in memory
management section later.
Continue only if time permit
Deleting an Element
 Case 2: Remove head only
Set head to the next item in list
Delete memory for name
Delete memory of node
Make new head->previous NULL
else if (head == toDelete)
{
head =head ->next;
free(toDelete->name);
free(toDelete);
toDelete = NULL;
head->previous = NULL;
return;
}
head name
id
previous next
name
id
previous next
NULL
Old head New head
NULL NULL
Case 3: Delete at arbitrary location
 Set follower->next to item after iterator
 Set item after iterator’s previous to follower
 Delete memory for name
 Delete memory for node
 Set toDelete and iterator to NULL
head name
id
previous next
name
id
previous next
NULLname
id
previous next
toDeletefollower iterator
NULL
Case 3: Delete at the end
 Go through the entire list until iterator == tail
 Delete memory for name
 Delete memory for node
 Set tail to the follower
 Set follower->next to NULL
head name
id
previous next
name
id
previous next
follower iterator
name
id
previous next
tail
NULL
NULL
tail
if (iterator == tail)
{
free(iterator->name);
free(iterator);
tail = follower;
follower->next = NULL;
return;
}
Putting it all together
if (head == toDelete && head->next == NULL)
{
free(toDelete->name);
free(toDelete);
head = NULL;
tail = NULL;
return;
}
else if (head == toDelete)
{
head = head->next;
free(toDelete->name);
free(toDelete);
toDelete = NULL;
head->previous = NULL;
return;
}
while (iterator != NULL)
{
if (iterator == tail)
{
free(iterator->name);
free(iterator);
tail = follower;
follower->next = NULL;
return;
}
else if (strcmp(iterator->name, toDelete->name) == 0)
{
follower->next = iterator->next;
iterator->next->previous = follower;
free(iterator->name);
free(iterator);
iterator = NULL;
toDelete = NULL;
return;
}
follower = iterator;
iterator = iterator->next;
}
Printing Doubly Linked List: Front
1. Start at the head.
2. Go until the iterator is
NULL
3. Print the values of the
node.
4. Set iterator to next.
struct node* iterator = head;
while (iterator != NULL)
{
printf("Name: %sn”, iterator->name);
printf(“ID: %dn", iterator->id);
iterator = iterator->next;
}
Printing Doubly Linked List: Back
1. Start at the tail.
2. Go until the iterator is
NULL
3. Print the values of the
node.
4. Set iterator to previous.
struct node* iterator = tail;
while (iterator != NULL)
{
printf("Name: %sn”, iterator->name);
printf(“ID: %dn", iterator->id);
iterator = iterator->previous;
}

CSE240 Doubly Linked Lists

  • 1.
  • 2.
    What is adoubly linked list?  A doubly linked list is a list of elements.  Each element points to the next element in the list as well as the previous element in the list.  Why use a doubly linked list over a single linked list? Doubly linked lists allow easy traversal forward and backward through the list.
  • 3.
    How to getstarted?  Create either a struct or an object to represent a node in the linked list.  It has a reference to the previous and next items in the linked list.  Use a tail pointer, in addition to a head pointer. struct node { int id; char* name; // A pointer, not an array struct node* previous; // pointer to previous node struct node* next; // pointer to next node in list }; Q1. What is the size of the node?. (A) 4 bytes (B) 16 bytes (C) more than 16 bytes? (D) The size is unknown at compilation. Think: How to obtain memory for name?
  • 4.
    Insertion: Case byCase  Inserting an element into a doubly linked list is very similar to inserting an element into a singly linked list.  Additionally, just make the previous pointer point to the previous item in the linked list.  There are three cases for sorted insert: 1. Add at the beginning 2. Add at an arbitrary location 3. Add to the end
  • 5.
    Case 0: Thelinked list is empty  Make the new node the head  Set previous and next to NULL of head  Set tail to head head NULL NULLhead name id previous next if (head == NULL) { head = newNode; head->next = NULL; head->previous = NULL; tail = head; return; } tail NULL Q2. When is the tail pointer equals to the head pointer? Select all that apply. (A) When the list is empty (B) When there is one node only (C) When there are more than one node (D) They never equal.
  • 6.
    Case 1: Addelement to beginning Set newNode->next to head->next Set head->previous to newNode Set head to the newNode Make the newNode previous NULL head NULL if (strcmp(newNode->name, head->name) < 0) { newNode->next = head; head->previous = newNode; head = newNode; head->previous = NULL; return; } name id previous next name id previous next name id previous next head NULL newNode The old head NULL NULL Q3. Which node’s previous pointer is NULL? (A) The first node (B) The second node (C) The last node (D) No node.
  • 7.
    Case 2: Addat an arbitrary location  Use a iterator pointer and a follower pointer.  follower always is one element behind iterator struct node* iterator = head; struct node* follower = iterator;
  • 8.
    Case 2: Addto an arbitrary location  Set newNode->next to iterator  Set iterator->previous to newNode  Set the newNode->previous to follower  Set follower->next to newNode head name id previous next name id previous next NULL name id previous next newNode follower iterator NULL
  • 9.
    Case 3: Addto the end  Go through the entire list until iterator is NULL  Set follower->next to newNode  Set newNode->previous to follower  Set newNode->next to NULL  Set the tail to newNode head name id previous next name id previous next NULL follower iterator name id previous next tail NULL Q4. Is case 3 included in case 2? (A) Yes, case 3 can be simply removed (B) No. case 3 is not included in case 2. Explain your answer
  • 10.
    Putting it Together if(head == NULL) { // Case 0 head = newNode; head->next = NULL; head->previous = NULL; tail = head; return; } else { Case 1 if (strcmp(newNode->name, head- >name) < 0) { newNode->next = head; head->previous = newNode; head = newNode; head->previous = NULL; return; } } }; iterator = head; follower = iterator; while (iterator != NULL) { // Case 2 if (strcmp(newNode->name, iterator->name) < 0) { newNode->next = iterator; iterator->previous = newNode; newNode->previous = follower; follower->next = newNode; return; } follower = iterator; iterator = iterator->next; } follower->next = newNode; // Case 3 newNode->previous = follower; newNode->next = NULL; tail = newNode; return;
  • 11.
    Searching Doubly LinkedList: Front 1. Start at the head. 2. Go until the iterator is NULL 3. Compare the value of the iterator with a value. 4. If found, return the element. 5. Else, set iterator to next. 6. If not found, return NULL. struct node* iterator = head; while (iterator != NULL) { if (strcmp(iterator->name, token) == 0) { return iterator; } iterator = iterator->next; } printf("The element does not exist.nn"); return iterator;
  • 12.
    Searching Doubly LinkedList: Back 1. Start at the tail. 2. Go until the iterator is NULL 3. Compare the value of the iterator with a value. 4. If found, return the element. 5. Else, set iterator to previous. 6. If not found, return NULL. struct node* iterator = tail; while (iterator != NULL) { if (strcmp(iterator->name, token) == 0) { return iterator; } iterator = iterator->previous; } printf("The element does not exist.nn"); return iterator; Q5. How many lines of code are different when searching forwards and backwards? (A) 0 (B) 1 (C) 2 (D) 4 Which lines of code?
  • 13.
    Deleting an Element Case 1: List only has one item  Delete heap memory for name  Delete heap memory for head  Set head to NULL  Set tail to NULL NULLhead name id previous next if (head == toDelete && head->next == NULL) { free(head->name); free(head); head = NULL; tail = NULL; return; } tail NULL Q6. Advance Question: Why do call free twice? free(head->name); free(head); To be discussed in memory management section later.
  • 14.
  • 15.
    Deleting an Element Case 2: Remove head only Set head to the next item in list Delete memory for name Delete memory of node Make new head->previous NULL else if (head == toDelete) { head =head ->next; free(toDelete->name); free(toDelete); toDelete = NULL; head->previous = NULL; return; } head name id previous next name id previous next NULL Old head New head NULL NULL
  • 16.
    Case 3: Deleteat arbitrary location  Set follower->next to item after iterator  Set item after iterator’s previous to follower  Delete memory for name  Delete memory for node  Set toDelete and iterator to NULL head name id previous next name id previous next NULLname id previous next toDeletefollower iterator NULL
  • 17.
    Case 3: Deleteat the end  Go through the entire list until iterator == tail  Delete memory for name  Delete memory for node  Set tail to the follower  Set follower->next to NULL head name id previous next name id previous next follower iterator name id previous next tail NULL NULL tail if (iterator == tail) { free(iterator->name); free(iterator); tail = follower; follower->next = NULL; return; }
  • 18.
    Putting it alltogether if (head == toDelete && head->next == NULL) { free(toDelete->name); free(toDelete); head = NULL; tail = NULL; return; } else if (head == toDelete) { head = head->next; free(toDelete->name); free(toDelete); toDelete = NULL; head->previous = NULL; return; } while (iterator != NULL) { if (iterator == tail) { free(iterator->name); free(iterator); tail = follower; follower->next = NULL; return; } else if (strcmp(iterator->name, toDelete->name) == 0) { follower->next = iterator->next; iterator->next->previous = follower; free(iterator->name); free(iterator); iterator = NULL; toDelete = NULL; return; } follower = iterator; iterator = iterator->next; }
  • 19.
    Printing Doubly LinkedList: Front 1. Start at the head. 2. Go until the iterator is NULL 3. Print the values of the node. 4. Set iterator to next. struct node* iterator = head; while (iterator != NULL) { printf("Name: %sn”, iterator->name); printf(“ID: %dn", iterator->id); iterator = iterator->next; }
  • 20.
    Printing Doubly LinkedList: Back 1. Start at the tail. 2. Go until the iterator is NULL 3. Print the values of the node. 4. Set iterator to previous. struct node* iterator = tail; while (iterator != NULL) { printf("Name: %sn”, iterator->name); printf(“ID: %dn", iterator->id); iterator = iterator->previous; }