0% found this document useful (0 votes)
62 views24 pages

Linked Lists Notes

This document introduces linked lists and their advantages over arrays for dynamic data structures. It discusses the structure of a linked list node with a data field and pointer to the next node. Examples are given of basic linked list operations like appending a node, adding a node at the beginning, and adding a node after a specified node. Functions are defined to implement these operations using pointers to dynamically allocate memory and adjust the links between nodes.

Uploaded by

shresth
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)
62 views24 pages

Linked Lists Notes

This document introduces linked lists and their advantages over arrays for dynamic data structures. It discusses the structure of a linked list node with a data field and pointer to the next node. Examples are given of basic linked list operations like appending a node, adding a node at the beginning, and adding a node after a specified node. Functions are defined to implement these operations using pointers to dynamically allocate memory and adjust the links between nodes.

Uploaded by

shresth
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/ 24

Linked Lists

Introduction
We have seen representation of linear
sequential allocation method of storage, as
unacceptable in cases like:

data structures by using


in, arrays. But this is

a. Unpredictable storage requirements:


The exact amount of data storage required by the program varies
with the amount of data being processed. This may not be available at
the time we write programs but are to be determined later.
For example, linked allocations are very beneficial in case of
polynomials. When we add two polynomials, and none of their degrees
match, the resulting polynomial has the size equal to the sum of the two
polynomials to be added. In such cases we can generate nodes (allocate
memory to the data member) whenever required, if we use linked
representation (dynamic memory allocation).

b. Extensive data manipulation takes place.


Frequently many operations like insertion, deletion etc, are to be
performed on the linked list.

Pointers are used for the dynamic memory allocation. These pointers are
always of same length regardless of which data element it is pointing to(
int, float, struct etc,). This enables the manipulation of pointers to be
performed in a uniform manner using simple techniques. These make us capable
of representing a much more complex relationship between the elements of a
data structure than a linear order method.
The use of pointers or links to refer to elements of a data structure
implies that elements, which are logically adjacent, need not be physically
adjacent in the memory. Just like family members dispersed, but still bound
together.

Singly Linked List [or] One way chain


This is a list, which may consist of an ordered set of elements that may
vary in number. Each element in this linked list is called as node. A node in
a singly linked list consists of two parts, a information part where the
actual data is stored and a link part, which stores the address of the
successor(next) node in the list. The order of the elements is maintained by
this explicit link between them. The typical node is as shown :
Info

Fig 1.

Data Structures (9067)

Link
NODE
Structure of a Node

- 1 -

Consider an example where the marks obtained by the students are stored
in a linked list as shown in the figure :

|data |Next|
--->

70

65

---> 45

---> 62

NULL

|<-NODE ->|
fig 2. Singly Linked List
In figure 2, the arrows represent the links. The data part of each node
consists of the marks obtained by a student and the next part is a pointer to
the next node. The NULL in the last node indicates that this node is the last
node in the list and has no successors at present. In the above the example
the data part has a single element marks but you can have as many elements as
you require, like his name, class etc.
There are several operations that we can perform on linked lists. We can
see some of them now. To begin with we must define a structure for the node
containing a data part and a link part. We will write a program to show how
to build a linked list by adding new nodes in the beginning, at the end or in
the middle of the linked list. A function display() is used to display the
contents of the nodes present in the linked list and a function delete(),
which can delete any node in the linked list .
typedef struct node
{
int data;
struct node *link;
}NODE;
# include < stdio.h >
# include < alloc.h >

/* required for dynamic memory */


/* allocation */

main()
{
NODE *p;
P = NULL;

/* empty linked list */

printf(\n No of elements in the linked list = %d,


count(p));
append(&p,1); /* adds node at the end of the list */
append(&p,2);
append(&p,3);
append(&p,4);
append(&p,17);
clrscr();
display(p);

Data Structures (9067)

- 2 -

add_beg(&p,999);/* adds node at the beginning of the


list */
add_beg(&p,888);
add_beg(&p,777);
display(p);
add_after(p,7,0); /* adds node after specified node */
add_after(p,2,1);
add_after(p,1,99);
disply(p);
printf(\n No of elements in the linked list = %d,
count(p));
delete(&p,888);
delete(&p,1);
delete(&p,10);

/* deletes the node specified */

disply(p);
printf(\n No of elements in the linked list = %d,
}
To begin with the variable p has been declared as
This pointer is a pointer to the first node in the list.
nodes get added to the list, p will always be the first
list. When no node exists in the linked list , p will
indicate that the linked list is empty. Now we will write
these functions.

pointer to a node.
No matter how many
node in the linked
be set to NULL to
and discuss each of

Function to add a node at the end of the linked list


append( NODE **q, int num)
{
NODE *temp, *r;
temp = *q;
if( *q == NULL) /*list empty, create the first node */
{
temp = malloc(sizeof(NODE));
temp->data = num;
temp->link = NULL;
*q = temp;
}
else
{
temp = *q;
while(temp->link != NULL ) /* goto the end of */
temp = temp->link;
/* list */

Data Structures (9067)

- 3 -

r = malloc(sizeof(NODE));
r->data = num;
r->link = NULL;
temp->link = r;

/* add node at the */


/* end of the list */

}
}

The append() function has to deal with two situations:


a. The node is being added to an empty list.
b. The node is being added to the end of the linked list.

In the first case, the condition


if( *q == NULL )
gets satisfied. Hence space is allocated for the node using malloc() .
Data and the link part of this node are set up using the statements :
temp->data = num;
temp->link = NULL;
Lastly p is made to point to this node, since the first node has been
added to the linked list and p must always point to the first node. Note that
*q is nothing but equal to p.
In the other case, when the linked list is not empty, the condition :
if( *q == NULL)
would fail, since *q (i.e. p is non-NULL). Now temp is made to point to the
first node in the linked list through the statement,
temp = *q;
Then using temp we have traversed through the entire linked list using the
statements:
while(temp->link != NULL)
temp=temp->link;
The position of the pointer before and after traversing the linked list is
shown below:
p temp

--->

Data Structures (9067)

---> 3

--->

NULL

- 4 -

temp

--->

---> 3

--->

NULL
node
being
added.

Fig 3. Node being added at the end of a SLL

Each
point to
condition
the space

time through the loop the statement temp= temp->link makes temp
the next node in the list. When temp reaches the last node the
temp->link != NULL would fail. Once outside the loop we allocate
for the new node through the statement

r = malloc(sizeof(NODE));
Once the space has been allocated for the new node its data part is
filled with num and the link part with NULL. Note that this node is now going
to be the last node in the list.
All that now remains is connecting the previous last node to this new
last node. The previous node is being pointed to by temp and the new last
node is by r. they are connected through the statement
temp->link = r;
There is often a confusion amongst
temp=temp->link makes temp point to the
understand this with the help of an
containing 4 nodes temp is pointing to
figure below:

the beginners as to how the statement


next node in the linked list. Let us
example. Suppose in a linked list
the first node. This is shown in the

temp
150

1 400

2 700

3 910

4 NULL

150

400

700

910

Fig 4. Actual representation of a SLL in memory


Instead of showing the links to the next node the above diagram shows
the addresses of the next node in the link part of each node. When we execute
the statement temp = temp-> link, the right hand side yields 400. This
address is now stored in temp. As a result, temp starts positioning nodes
present at address 400. In effect the statement has shifted temp so that it
has started positioning to the next node in the linked list.

Function to add a node at the beginning of the linked list

Data Structures (9067)

- 5 -

add_beg( NODE **q, int num)


{
temp = malloc(sizeof(NODE));
temp->data = num;
temp->link = *q;
*q = temp;
}
Suppose there are already 5 nodes in the list and we wish to add a new
node at the beginning of this existing linked list. This situation is shown
in the figure below.
temp

--->

---> 3

---> 4

--->17 NULL

Before Addition
temp p

999 ---> 1

---> 2

---> 3

---> 4

--->17 NULL

After Addition
Fig 5. Addition of a node in the beginning of a SLL
For adding a new node at the beginning, firstly space is allocated for
this node and data is stored in it through the statement
temp->data = num;
Now we need to make the link part of this node point to the existing
first node. This has been achieved through the statement
temp->link = *q;
Lastly this new node must be made the first node in the list. This has
been attained through the statement
*q = temp;

Function to add a node after the specified node


add_after(NODE *q, int loc, int num)
{
NODE *temp, *t;
int i;
temp = q;

Data Structures (9067)

- 6 -

for( i=0 ; i<loc; i++)


{
temp = temp->link;
if(temp == NULL)
{
printf( There are less than %d elements in
the list,loc);
return;
}
}
r = malloc(sizeof(NODE));
r->data = num;
r->link = temp->link;
temp->link = r;
}
The add_after() function permits us to add a new node after a specified
number of nodes in the linked list.
To begin with, through a loop we skip the desired number of nodes after
which a new node is to be added. Suppose we wish to add a new node containing
data as 99 after the third node in the list. The position of pointers once
the control reaches outside the for loop is shown below:
P

temp

--->

---> 3

---> 4

--->17 NULL

99
Before Insertion
P

temp

--->

---> 3

--->17 NULL

r
99
After Insertion
Fig 6. Insertion of a node in the specified position

Data Structures (9067)

- 7 -

The space is allocated for the node to be inserted and 99 is stored in


the data part of it. All that remains to be done is readjustment of links
such that 99 goes in between 3 and 4. this is achieved trough the statements
r->link = temp->link;
temp->link = r;
The first statement makes link part of node containing 99 to point to
the node containg 4. the second statement ensures that the link part of the
node containing 3 points to the new node.

Functions for display and count


These functions are very simple
explanation is required for them.

and

straightforward.

So

no

further

/* function to count the number of nodes in the linked list */


count(NODE *q)
{
int c = 0;
while( q != NULL) /* traverse the entire list */
{
q = q->link;
c++;
}
return (c);
}

/* function to display the contents of the linked list */


display(NODE *q)
{
printf(\n);
while( q != NULL) /* traverse the entire list */
{
printf(%d,q->data);
q=q->link;
}
}

Function to delete the specified node from the list


delete(NODE **q, int num)
{
NODE *old, *temp;
temp = *q;

Data Structures (9067)

- 8 -

while( temp != NULL)


{
if(temp->data == num)
{
if(temp == q) /*if it is the first node */
{
*q = temp->link;
free(temp); /* release the memory */
return;
}
else
{
old->link == temp->link;
free(temp);
return;
}
}
else
{
old = temp;
temp=temp->link;
}
}
printf(\n Element %d not found,num);
}
In this function
through the while
loop , we have traversed through
the entire linked list, checking at each node, whether it is the node to be
deleted. If so, we have checked if the node is the first node in the linked
list. If it is so, we have simply shifted p to the next node and then deleted
the earlier node.
If the node to be deleted is an intermediate node, then the position of
various pointers and links before and after deletion are shown below.
P

old

--->

---> 3

temp

---> 4

--->17 NULL

node to be deleted = 4
Before deletion

old

--->

Data Structures (9067)

--->

--->

17 NULL

- 9 -

temp

This node gets deleted.

After deletion
Fig 7. Deletion of a node from SLL
Though the above linked list depicts a list of integers, a linked list
can be used for storing any similar data. For example, we can have a linked
list of floats, character array, structure etc.

Doubly Linked Lists [or] Two-way chain


In a singly linked list we can traverse in only one direction (forward),
i.e. each node stores the address of the next node in the linked list. It has
no knowledge about where the previous node lies in the memory. If we are at
the 12th node(say) and if we want to reach 11th node in the linked list, we
have to traverse right from the first node. This is a cumbersome process.
Some applications require us to traverse in both forward and backward
directions. Here we can store in each node not only the address of the next
node but also the address of the previous node in the linked list. This
arrangement is often known as a Doubly linked list . The node and the
arrangement is shown below:

<--------

INFO

PREV

--------->
NEXT

NODE
Fig 8. Node structure of a DLL

NULL

20

15

70

60 NULL

Fig 9. Doubly Linked List


The left pointer of the leftmost node and the right pointer of the
rightmost node are NULL indicating the end in each direction.
The following program implements the doubly linked list.
/* program to maintain a doubly linked list*/
# include < alloc.h >

Data Structures (9067)

- 10 -

typedef struct node


{
int data;
struct node *prev, *next;
}NODE;

main()
{
NODE *p;
p = NULL;

/* empty doubly linked list */

d_append(&p,11);
d_append(&p,21);
clrscr();
display(p);
printf(\n No of elements in the doubly linked list =
%d, count(p));

d_add_beg(&p,33);
d_add_beg(&p,55);
disply(p);
printf(\n No of elements in the doubly linked list =
%d, count(p));
d_add_after(p,1,4000);
d_add_after(p,2,9000);
disply(p);
printf(\n No of elements in the linked list = %d,
count(p));
d_delete(&p,51);
d_delete(&p,21);
disply(p);
printf(\n No of elements in the linked list = %d,
}

/* adds a new node at the beginning of the list*/


d_add_beg( NODE **s, int num)
{
NODE *q;
/* create a new node */
q = malloc(sizeof(NODE));

Data Structures (9067)

- 11 -

/* assign data
q->prev =
q->data =
q->next =

and pointers*/
NULL;
num;
*s;

/* make the new node as head node */


(*s)-> prev = q;
*s = q;
}

/* adds a new node at the end of the doubly linked list*/


d_append( NODE **s, int num)
{
NODE *r, *q =*s;
if( *s ==
{
*s =
( *s
( *s

NULL) /*list empty, create the first node */


malloc(sizeof(NODE));
)->data = num;
)->next =( *s )->prev = NULL;

}
else
{
while(q->next != NULL ) /* goto the end of */
q = q->next;
/* list */
r = malloc(sizeof(NODE));
r->data = num;
r->next = NULL;
r->prev = q;
q->next = r;

/* add node at the */


/* end of the list */

}
}
/* adds a new node after the specified number of nodes */
d_add_after(NODE *q, int loc, int num)
{
NODE *temp;
int i;
/* skip to the desired position*/
for( i=0 ; i<loc; i++)
{
q = q->next;
if(q == NULL)
{

Data Structures (9067)

- 12 -

printf( There are less than %d elements in


the list,loc);
return;
}
}
/* insert a new node */
q = q->prev;
temp = malloc(sizeof(NODE));
temp->data = num;
temp->prev = q;
temp->next = q->next;
temp->next->prev = temp;
q->next = temp;
}
/* counts the number of nodes present in the linked list */
count(NODE *q)
{
int c = 0;
while( q != NULL)
{
q=q->next;
c++;
}
return (c);

/* traverse the entire list */

/* Function to display the contents of the doubly linked list */


/* in left to right order */
displayLR(NODE *q)
{
printf(\n);
while( q != NULL) /* traverse the entire list */
{
printf(%d,q->data);
q=q->next;
}
}

/* Function to display the contents of the doubly linked list */


/* in right to left order */
displayRL(NODE *q)
{
printf(\n);

Data Structures (9067)

- 13 -

while( q->next != NULL) /* traverse the entire list */


{
q=q->next;
}
while( q != NULL)
{
printf(%d,q->data);
q=q->prev;
}
}
/* to delete the specified node from the list. */
d_delete(NODE **s, int num)
{
NODE *q= *s;
/* traverse the entire linked list */
while( q != NULL)
{
if(q->data == num)
{
if(q == *s) /*if it is the first node */
{
*s = (*s)->next;
(*s)-> prev = NULL;
}
else
{
/* if the node is last node */
if( q->next == NULL)
q->prev->next = NULL;
else
/* node is intermediate */
{
q->prev->next = q->next;
q->next->prev = q->prev;
}
free(q);
}
return;

/* after deletion */
}
q = q->next ; /* goto next node if not found */
}
printf(\n Element %d not found,num);
}
As you must have realized by now any operation on linked list involves
adjustments of links. Since we have explained in detail about all the

Data Structures (9067)

- 14 -

functions for singly linked list , it is not necessary to give step-by-step


working anymore. We can understand the working of doubly linked lists with
the help of diagrams. We have shown all the possible operations in a doubly
linked list along with the functions used in diagrams below:
Addition of new node to an empty linked list
Case 1: Addition to an empty list
Related function : d_append()
p = *s = NULL
Before Addition
P

NULL

NULL

New node
After Addition

Case 2: Addition to an existing linked list


Related function : d_append()
P

99

Before Appending
P

Data Structures (9067)

99

- 15 -

After Appending
Addition of new node at the beginning.
Related Function : d_add_beg()
p

33

Before Addition

33

After Addition

Fig 10. Addition of

Data Structures (9067)

nodes at various positions

in the DLL

- 16 -

Insertion of a new node after a specified node


Related function : d_add_after()
p

temp

66

New Node
Before Insertion

N 1

temp

66

After Insertion
Fig 11. Insertion of

node in the DLL

Deletion Of a Node
Case 1: Deletion of first node
Related function : d_delete()
p

55

Node to be deleted : 55
Before Deletion

Data Structures (9067)

- 17 -

After Deletion

Case 2: Deletion of the last node


Related function : d_delete()
p

88

Node to be deleted : 88
Before Deletion

After Deletion

Case 3: Deletion of the intermediate node


Related function : d_delete()
p

77

Node to be deleted : 77
Before Deletion

Data Structures (9067)

- 18 -

After Deletion
Fig 11.Deletion of

nodes from various positions

in the DLL

Applications of the linked lists


In computer science linked lists are extensively used in Data Base
Management Systems Process Management, Operating Systems, Editors etc.
Earlier we saw that how singly linked list and doubly linked list can be
implemented using the pointers. We also saw that while using arrays vary
often the list of items to be stored in an array is either too short or too
big as compared to the declared size of the array. Moreover, during program
execution the list cannot grow beyond the size of the declared array. Also,
operations like insertions and deletions at a specified location in a list
require a lot of movement of data, thereby leading to an inefficient and
time-consuming algorithm.
The primary advantage of linked list over an array is that the linked
list can grow or shrink in size during its lifetime. In particular, the
linked list s maximum size need not be known in advance. In practical
applications this often makes it possible to have several data structures
share the same space, without paying particular attention to their relative
size at any time.
The second advantage of providing flexibility in allowing the items to
be rearranged efficiently is gained at the expense of quick access to any
arbitrary item in the list. In arrays we can access any item at the same time
as no traversing is required.
We are not suggesting that you should not use arrays at all. There are
several applications where using arrays is more beneficial than using linked
lists. We must select a particular data structure depending on the
requirements.
Let us now see some more applications of the linked lists, like merging
two
lists
and
how
the
linked
lists
can
be
used
for
polynomial
representations.
Function to Merge the two lists.
Merge(NODE *p, NODE *q, NODE **s)
{
NODE *z;
/* If both lists are empty */
if(p==NULL && q == NULL)
{

Data Structures (9067)

- 19 -

return;
}
/* traverse both linked lists till the end. If end of any one linked
list is encountered then the loop is terminated */
while( p != NULL && q != NULL)
{
/* if node being added in the first list */
if ( *s == NULL)
{
*s = malloc(sizeof(NODE));
z = *s;
}
else
{
z->link = malloc(sizeof(NODE));
z = z->link;
}
if( p->data < q->data)
{
z->data = p->data;
p = p->link;
}
else
{
if( p->data > q->data)
{
z->data = q->data;
q = q->link;
}
else
{
if( p->data == q->data)
{
z->data = q->data;
q = q->link;
p = p->link;
}
}
}
}
/* if end of first list has not been reached */
while( p != NULL)
{
z->link = malloc(sizeof(NODE));
z = z->link;
z->data = p->data;
p = p->link;

Data Structures (9067)

- 20 -

}
/* if end of second list has not been reached */
while( q != NULL)
{
z->link = malloc(sizeof(NODE));
z = z->link;
z->data = q->data;
q = q->link;
}
z->link = NULL;
}
In this program, assume that structure NODE with data and link is
available. Also using add() used for singly linked list earlier we have two
linked lists. Three pointers point to three linked lists. The merge function
can be called to merge the two linked lists. This merged list is pointed to
by the pointer third. While merging two lists it is assumed that the lists
themselves are in ascending order.

Linked lists and Polynomials.


Polynomials can be maintained using a linked list. To have a polynomial
like 5x4 _ 2x3 + 7x2 + 10x 8 , each node should consist of three elements,
namely coefficient, exponent and a link to the next item. While maintaining
the polynomial it is assumed that the exponent of each successive term is
less than that of the previous term. If this is not the case you can also use
a function to build a list, which maintains this order. Once we build a
linked list to represent the polynomial we can perform operations like
addition and multiplication. Consider the program given below.
/* program to add two polynomials */
typedef struct node
{
float coeff;
int exp;
struct node *link;
}PNODE;
void p_append(PNODE **, float, int);
void p_addition(PNODE *, PNODE *, PNODE **);

main()
{
PNODE (first, *second, *total;
int i = 0;
first = second = total = NULL;/* empty linked lists */

Data Structures (9067)

- 21 -

p_append(&first,1,4,5);
p_append(&first,1,5,4);
p_append(&first,1,7,2);
p_append(&first,1,8,1);
p_append(&first,1,9,0);
clrscr();
display_p(first);
p_append(&second,1,5,6);
p_append(&second,2,5,5);
p_append(&second,-3,5,4);
p_append(&second,4,5,3);
p_append(&second,6,5,1);
display_p(second);
p_addition(first,second, &total)
display_p(total);
};
The function to append the polynomial p_append() and display_p() are
similar to our functions for singly linked list. So they are expected to be
written by the user. The function to add two polynomials is given below.

void p_addition(PNODE *x, PNODE *y, PNODE **s)


{
PNODE *z;
/* if both lists are empty */
if( x == NULL && y == NULL )
return;
/* traverse till one node ends */
while( x != NULL && y != NULL )
{
if ( *s == NULL)
{
*s = malloc(sizeof(PNODE));
z = *s;
}
else
{
z->link = malloc(sizeof(PNODE));
z = z->link;
}
/* store a term of larger degree if polynomial */
if( x->exp < y->exp)

Data Structures (9067)

- 22 -

{
z->coeff = y->coeff;
z->exp = y->exp;
y = y->link;
/* goto the next node */
}
else
{
if( x->exp > y->exp)
{
z->coeff = x->coeff;
x->exp = x->exp;
x = x->link;
/* goto the next node */
}
else
{
if( x->exp == y->exp)
{
z->coeff = x->coeff + y->coeff;
x->exp = x->exp;
x = x->link;
/* goto the next node */
y = y->link;
/* goto the next node */
}
}
}
}
/*assign remaining elements of the first polynomial to the
result */
while( x != NULL)
{
if( *s == NULL)
{
*s = malloc(sizeof(PNODE));
z = *s;
}
else
{
z->link = malloc(sizeof(PNODE));
z = z->link;
}
z->coef = x->coef;
z->exp = x->exp;
x = x->link;
}
/*assign remaining elements of the second polynomial to the
result */
while( y != NULL)
{
if( *s == NULL)
{

Data Structures (9067)

- 23 -

*s = malloc(sizeof(PNODE));
z = *s;
}
else
{
z->link = malloc(sizeof(PNODE));
z = z->link;
}
z->coef = y->coef;
z->exp = y->exp;
y = y->link;
}
z->link = NULL; /* at the end of list append NULL*/
}
In this program two polynomials are built and pointed by the pointers
first and second. Next the function p_addition() is called to carry out the
addition of these two polynomials. In this function the linked lists
representing the two polynomials are traversed till the end of one of them is
reached. While doing this traversal the polynomials are compared on term-byterm basis. If the exponents of the two terms being compared are equal then
their coefficients re added and the result is stored in the third polynomial.
If the exponents are not equal then the bigger exponent is added to the third
polynomial. During the traversal if the end of one list is reached the
control breaks out of the while loop. Now the remaining terms of that
polynomial are simply appended to the resulting polynomial. Lastly the result
is displayed.
Exercises:
1. WAP for adding and deleting nodes from an ascending order linked list.
2. WAP to reverse a singly linked list by adjusting the links.
3. Write programs for reversing a doubly linked list (though it does not
serve any purpose it will give practice to manipulate the pointers.
4. WAP to delete a node after the specified node and before a specified
node using both singly and doubly linked lists.
5. WAP to break a linked list into two linked lists using both SLL and
DLL.
6. Write a program to add two polynomials using a DLL.
7. WAP to multiply two polynomials for both SLL and DLL.
8. WAP to add two long integers. Each integer may contain 15 to 20 digits,
which can be stored in nodes, a digit each or more depending on the
users choice. Add these long integers (from least significant digit
backwards) and display the resultant list.

Data Structures (9067)

- 24 -

You might also like