Unit 3 - Linked Lists
Unit 3 - Linked Lists
Singly linked lists, linked stacks and queues, doubly linked lists and
dynamic storage management, circular linked list, Applications of
Stacks, Queues and Linked lists.
Abstract Data Type (ADT)
• An Abstract Data Type is:
• Set of values
• Set of operations which can be uniformly applied to these values
• Set of Axioms
What is List?
• Countable number of ordered values
• Each occurrence of a value is a distinct item
• Implemented differently in different programming
languages
• Linked list is an implementation of list
List Abstract Data Type
• List ADT has:
• Values based on what type of data list stores
• Main operations:
• new() : creates a new list
• prepend(L, key): add element key to front of list L
• append(L, key): add element key to end of list L
• remove(L, key): removes element key from list L
• search(L, key): find location of element key in L
• head(L): returns the first object in L
• isEmpty(L): checks whether list L is empty or not
• Axioms:
• Based on implementation
Drawbacks with Array
• Is array also a list?
Drawbacks with Array
• Is array also a list?
• Yes, certainly.
a b c d
Dynamic Memory Allocation(1)
• Allocate memory to elements one at a time as needed,
have each element keep track of the next element
• Result is referred to as linked list of elements, track next
element with a pointer
Linked List
Jane Anne Bob
More Terminology
• A node’s successor is the next node in the sequence
• The last node has no successor
• A node’s predecessor is the previous node in the
sequence
• The first node has no predecessor
• A list’s length is the number of elements in it
• A list may be empty (contain no elements)
• Linked list in context of C are sometime referred as List
• Until not specified, linked list refers to Singly-Linked List
LL with 3 nodes (dynamic)
void main() { /*assume data is int */
LinekedList ListStart = NULL; /*safe to give a legal
value*/
Pictorially In Memory
ListStart ListStart
0
100
ListStart = (Eptr)malloc(sizeof(Estruct));
/* ListStart points to memory allocated at location 108 */
ListStart ListStart Data Next
? ? 108 ? ?
Data Next 100 108
}
Declaration of LL
• Because the node of linked list contains 2 components it
should be declared as class or struct
struct nodeType
{
int info;
nodeType *link;
};
Properties of LL
VALUE EXPLANATION
head 2000
Because head is 2000 and the info of
head -> info 17
the node at location 2000 is 17
head -> link 2800
Because head -> link is 2800 and the
head -> link -> info 92
info of the node at location 2800 is 92
• Suppose that current is a pointer which has type as
pointer head. Then, the statement : current=head copies
the value of head into current
value
current 2000
current -> info 17
current -> link 2800
current -> link -> info 92
Insertion in Linked List
• Involves two step:
• Finding the correct position
• Doing the work to add the node
ListStart
5 9 6 X
Last
Insertion in Linked List (End)
• Find last of list
• Add new node to list
• Save element in data field of new node
• Save NULL in next field of new node
• Make last node’s next pointer to point new node
Last
Insertion in Linked List (Between)
• Find the node you want to insert after
ListStart
5 9 6 X
After
Insertion in Linked List (Between)
• Find the node you want to insert after
• Add new node to list
• Save element in data field of new node
• Save address of following node in next field of new node
• Save address of new node in “after” node
After
Item insertion to LL
• Consider linked list before insertion
• variable declaration
nodeType *head, *p, *q, *newnode;
• Suppose that p points to the node with info 65, and a new
node with info 50 is to be created and inserted after p
newNode = new nodeType;//create newNode
newNode -> info = 50;//store 50 in the new node
newNode -> link = p -> link;
p -> link = newNode;
p -> link = newNode;
newNode -> link = p -> link;
• newNode points back to itself and the remainder of the list is lost
• by using to pointers insertion code can be simplified
• suppose q points to the node with info 34
newNode -> link = q;
p -> link = newNode;
Above statements insert newNode between p and q
Print a Linked List
• Use a “walker” to examine list from start to end
void printList() {
node *temp = start; /*temp is walker variable*/
while (temp != NULL) {
cout<<temp->data;
temp = temp->next;
}
}
findP
• Search 4
ListStart
5 9 6 X
findP
Deletion in Linked List
• Involves two steps:
• Find the node to be deleted
• Change its predecessor to point its successor
• the node with info 34 is removed from the list. However, the
memory is still occupied by this node, and this memory is
inaccessible; that
• is, this node is dangling. To deallocate the memory, we need a
pointer to this node.
Deallocate deleted node
• The following statements delete the node from the list and deallocate the memory
occupied by this node.
q = p->link;
p->link = q->link;
delete q;
Building LL
• Suppose that the nodes are in the usual info-link form,
and info is of type int.
• Assume to process the following data: 2, 15, 8, 24, 34
• Will be needed:
• three pointers to build the list: one to point to the first node in the
list, which cannot be moved;
• one to point to the last node in the list;
• and one to create the new node.
nodeType *first, *last, *newNode;
int num;
Building LL…
Forward LL
Pseudo code of building Backward LL
• 1. Initialize first to NULL.
• 2. For each item in the list,
• Create the new node, newNode.
• Store the item in newNode.
• Insert newNode before first.
• Update the value of the pointer first.
C++ function to build Backward LL
nodeType* buildListBackward()
{
nodeType *first, *newNode;
int num;
cout<<"Enter a list of integers ending with -1."<<endl;
cin >> num;
first = NULL;
while (num != -1)
{
newNode = new nodeType; //create a node
newNode->info = num; //store the data in newNode
newNode->link = first; //put newNode at the beginning of the list
first = newNode; //update the head (first) pointer of the list
cin >> num; //read the next number
}
return first;
} //end buildListBackward
Linked List Variation: Dummy Head Node
Using "dummy" first (head) node:
Empty linked list
ListStart
?
Sample list:
ListStart
? 5 9 6
• Why?
• No special case for inserting/deleting at beginning
• Header (ListStart) does not change after it is initialized
• Disadvantage
• cost of one extra element
Linked List Variation: Sorted List
• Idea: Keep the items on the list in a sorted order
• sort based on data value in each node
• Advantages:
• already sorted
• operations such as delete, find, etc. need not search to the end of the
list if the item is not in list
• Disadvantages
• insert must search for the right place to add element (slower than simply
adding at beginning)
Doubly Linked List
• Each node contain data, link to its successor and a link to
its predecessor
• Two headers pointing to first and last node respectively or
pointing to NULL (if list is empty)
myDL
First L Last
a b c
Doubly Linked List
• Advantages:
• Can be traversed in either direction (may be essential for some
programs)
• Some operations, such as deletion and inserting before a node,
become easier
• Disadvantages:
• Requires more space
• List manipulations are slower (because more links must be
changed)
• Greater chance of having bugs (because more links must be
manipulated)
Insertion in DLL
• Change forward and backward pointers accordingly
• Insert element “d” after “a”
myDL
First L Last
a b c
New Node
d
Insertion in DLL
• Change forward and backward pointers accordingly
• Eg. Insert element “d” after “a”
myDL
First L Last
a b c
New Node
d
Deletion in DLL
• Change forward and backward pointers accordingly
• Insertion and Deletion in beginning and last are special
cases and should be handled differently
• Eg. Delete “b” from previous list
myDL
First L Last
a X b X c
X X
Deletion in DLL
• Change forward and backward pointers accordingly
• Insertion and Deletion in beginning and last are special
cases and should be handled differently
• Eg. Delete “b” from previous list
myDL
First L Last
a c
Stack using LL
• Since all the action happens at the top of a stack, a
singly-linked list (SLL) is a fine way to implement it
• The header of the list points to the top of the stack
myStack:
44 97 23 17
myStack:
NULL
Stack using LL
• Initialize stack; set header to NULL
• push(44)
myStack:
44 NULL
Stack using LL
• Initialize stack; set header to NULL
• push(44)
• push(97)
myStack:
97 44 NULL
Stack using LL
• Initialize stack; set header to NULL
• push(44)
• push(97)
• push(23)
myStack:
23 97 44 NULL
Stack using LL
• Initialize stack; set header to NULL
• push(44)
• push(97)
• push(23)
• pop()
myStack:
97 44 NULL
Stack using LL
• Initialize stack; set header to NULL
• push(44)
• push(97)
• push(23)
• pop()
• push(17)
myStack:
17 97 44 NULL
Stack using LL
• Initialize stack; set header to NULL
• push(44)
• push(97)
• push(23)
• pop()
• push(17)
• pop()
myStack:
97 44 NULL
Stack using LL details
• With a linked-list representation, overflow will not happen
(unless you exhaust memory, which is another kind of
problem)
• Underflow can happen, and should be handled the same
way as for an array implementation
• When a node is popped from a list, and the node
references an object, the reference (the pointer in the
node) does not need to be set to NULL
• Unlike an array implementation, it really is removed--you can no
longer get to it from the linked list
Queue using LL
• In a queue, insertions occur at one end, deletions at the
other end
• If you know where the last node in a list is, it’s hard to
remove that node, but it’s easy to add a node after it
• Hence,
• Use the first element in an SLL as the front of the queue
• Use the last element in an SLL as the rear of the queue
• Keep pointers to both the front and the rear of the SLL
Enqueueing a Node
• Create a new node
last
first New Node
44 97 23 X 17 X
Enqueueing a Node
• Create a new node
• Change pointer of last node to point new node
last
first New Node
44 97 23 17 X
Enqueueing a Node
• Create a new node
• Change pointer of last node to point new node
• Change last pointer to point to new node
last
first New Node
44 97 23 17 X
Dequeueing a Node
• Change “first” to point to second node
last
first
44 97 23 17 X
Dequeueing a Node
• Change “first” to point to second node
• Optionally, set deleted node free
last
first
44 97 23 17 X
Queue using LL details
• With a linked-list representation, overflow will not happen
(unless you exhaust memory, which is another kind of
problem)
• Underflow can happen, and should be handled the same
way as for an array implementation
• When a node is dequeued from a list, and the node
references an object, the reference (the pointer in the
node) does not need to be set to NULL
• Unlike an array implementation, it really is removed--you can no
longer get to it from the linked list
Polynomial Representation in LL
• Represent polynomial expression using Linked List
• A node in linked list stores coefficient and exponent of
each term in polynomial expression
• Eg.
5 12 2 9 -1 3 NULL
Polynomial Addition
• Consider Two polynomial expressions
while (L1 != NULL) //if L2 has reached end, append remaining terms of L1
L3->coff = L1->coff; L3->pow = L1->pow; L1 = L1->next;
while (L2 != NULL) //if L1 has reached end, append remaining terms of L2
L3->coff = L2->coff; L3->pow = L2->pow; L1 = L2->next;
Example Polynomial Addition
L1
5 12 2 9 -1 3 NULL
L2
5 11 -4 9 2 3 -1 1 NULL
L3
NULL
Example Polynomial Addition
L1
5 12 2 9 -1 3 NULL
L2
5 11 -4 9 2 3 -1 1 NULL
L3
5 12 NULL
Example Polynomial Addition
L1
5 12 2 9 -1 3 NULL
L2
5 11 -4 9 2 3 -1 1 NULL
L3
5 12 5 11 NULL
Example Polynomial Addition
L1
5 12 2 9 -1 3 NULL
L2
5 11 -4 9 2 3 -1 1 NULL
L3
5 12 5 11 -2 9 NULL
Example Polynomial Addition
L1
5 12 2 9 -1 3 NULL
L2
5 11 -4 9 2 3 -1 1 NULL
L3
5 12 5 11 -2 9 1 3 NULL
Example Polynomial Addition
L1
5 12 2 9 -1 3 NULL
L2
5 11 -4 9 2 3 -1 1 NULL
L3
5 12 5 11 -2 9 1 3
-1 1 NULL
Algo for Polynomial Subtraction
• Represent two polynomials in two linked lists L1 and L2
• Create a third linked list L3, with coefficient of L2 negated
• Perform the algo for addition of list L1 and L3
Sparse Matrices
• Sparse: Many elements are zero
• Dense: Many elements are non-zero
Diagonal Tridiagonal
a1 0 0 0 a1 b1 0 0
0 a2 0 0 c1 a2 b2 0
0 0 a3 0 0 c2 a3 b3
0 0 0 a4 0 0 c3 a4
Example: 00304
00570
00000
02600
Array Representation of USM
Example: 00304
00570
00000
02600
Element 0 1 2 3 4 5
Row 1 1 2 2 4 4
Column 3 5 3 4 2 3
Value 3 4 5 7 2 6
LL Representation of USM
Example:0 0 3 0 4 Row 1 1 2 2 4 4
00570
LL = Column 3 5 3 4 2 3
00000
02600 Value 3 4 5 7 2 6
1 3 3 1 5 4 2 3 5 2 4 7
4 2 2 4 3 6 NULL
Array of LL Representation of USM
Example:0 0 3 0 4
00570
00000
02600
3 3 5 4 NULL
3 5 4 7 NULL
NULL
2 2 3 6 NULL
Row[]
Memory Requirements (Approx.)
• 500 x 500 matrix with 1994 nonzero elements
• Non-Empty CLL
ListStart
5 9 6
• Header Node
-1 5 9 6
Traversing in CLL
void print(Eptr ListStart) {
Eptr temp = ListStart;
print (temp->data);
while (temp->next != ListStart) {
print (temp->data);
temp = temp->next;
}
}
Advantages of CLL
• Some operations can be made efficient in CLL compare to
Singly LL like search multiple entries subsequently
• CLL are useful when element of lists are to be visited in
“Loop” fashion
Insertion in CLL
Insert in Empty CLL
• Change Header to point new node and new node to point
itself
Insert at Start
• Create new node; point to existing first node
• Change last node to point to new node; change header
Insert in middle
• Change new node to point successor of the node after
which node is inserted
• Change predecessor to point to new node
Deletion in CLL
Delete Last node
• If node points to itself, set header to point to null