Unit-2 - Linked List
Unit-2 - Linked List
Unit-2 - Linked List
Linked lists and arrays are similar since they both store collections of data. Array is the
most common data structure used to store collections of elements. Arrays are convenient
to declare and provide the easy syntax to access any element by its index number. Once
the array is set up, access to any element is convenient and fast. The disadvantages of
arrays are:
The size of the array is fixed. Most often this size is specified at compile time. This
makes the programmers to allocate arrays, which seems "large enough" than
required.
Linked lists have their own strengths and weaknesses, but they happen to be strong
where arrays are weak. Generally array's allocates the memory for all its elements in one
block whereas linked lists use an entirely different strategy. Linked lists allocate memory
for each element separately and only when necessary.
Here is a quick review of the terminology and rules of pointers. The linked list code
will depend on the following functions:
malloc() is a system function which allocates a block of memory in the "heap" and
returns a pointer to the new block. The prototype of malloc() and other heap functions
are in stdlib.h. malloc() returns NULL if it cannot fulfill the request. It is defined by:
Since a void * is returned the C standard states that this pointer can be converted to
any type. For example,
char *cp;
cp = (char *) malloc (100);
Attempts to get 100 bytes and assigns the starting address to cp. We can also use the
sizeof() function to specify the number of bytes. For example,
int *ip;
ip = (int *) malloc (100*sizeof(int));
free() is the opposite of malloc(), which de-allocates memory. The argument to free() is
a pointer to a block of memory in the heap a pointer which was obtained by a malloc()
function. The syntax is:
free (ptr);
The data items in the linked list are not in consecutive memory locations. They may be
anywhere, but the accessing of these data items is easier as each data item contains the
address of the next data item.
Linked lists have many advantages. Some of the very important advantages are:
1. Linked lists are dynamic data structures. i.e., they can grow or shrink during
the execution of a program.
2. Linked lists have efficient memory utilization. Here, memory is not pre-
allocated. Memory is allocated whenever it is required and it is de-allocated
(removed) when it is no longer needed.
3. Insertion and Deletions are easier and efficient. Linked lists provide flexibility
in inserting a data item at a specified position and deletion of the data item
from the given position.
4. Many complex applications can be easily carried out with linked lists.
Basically we can put linked lists into the following four items:
A single linked list is one in which all nodes are linked together in some sequential
manner. Hence, it is also called as linear linked list.
A double linked list is one in which all nodes are linked together by multiple links which
helps in accessing both the successor node (next node) and predecessor node (previous
node) from any arbitrary node within the list. Therefore each node in a double linked list
has two link fields (pointers) to point to the left node (previous) and the right node (next).
This helps to traverse in forward direction and backward direction.
A circular linked list is one, which has no beginning and no end. A single linked list can
be made a circular linked list by simply storing address of the very first node in the link
field of the last node.
A circular double linked list is one, which has both the successor pointer and predecessor
pointer in the circular manner.
1. Linked lists are used to represent and manipulate polynomial. Polynomials are
expression containing terms with non zero coefficient and exponents. For
example:
2. Represent very large numbers and operations of the large number such
as addition, multiplication and division.
A linked list allocates space for each element separately in its own block of memory called
a "node". The list gets an overall structure by using pointers to connect all its nodes
together like the links in a chain. Each node contains two fields; a "data" field to store
whatever element, and a "next" field which is a pointer used to link to the next node.
Each node is allocated in the heap using malloc(), so the node memory continues to exist
until it is explicitly de-allocated using free(). The front of the list is a pointer to
.
HEAP
The beginning of the linked list is stored in a "start" pointer which points to the first
node. The first node contains a pointer to the second node. The second node contains a
pointer to the third node, ... and so on. The last node in the list has its next field set to
NULL to mark the end of the list. Code can access any node in the list by starting at the
start and following the next pointers.
The start pointer is an ordinary local pointer variable, so it is drawn separately on the
left top to show that it is in the stack. The list nodes are drawn on the right to show that
they are allocated in the heap.
Implementation of Single Linked List:
Before writing the code to build the above list, we need to create a start node, used to
create and access other nodes in the linked list. The following structure definition willdo
(see figure 3.2.2):
Creating a structure with one data item and a next pointer, which will be pointing
to next node of the list. This is called as self-referential structure.
struct slinklist
{
int data; node: data next
struct slinklist* next;
};
Figure 3.2.2. Structure definition, single link node and empty list
Creation.
Insertion.
Deletion.
Traversing.
Creating a singly linked list starts with creating a node. Sufficient memory has to be
allocated for creating a node. The information is stored in the memory, allocated by using
the malloc() function. The function getnode(), is used for creating a node, after allocating
memory for the structure of type node, the information for the item (i.e., data) has to be
read from the user, set next field to NULL and finally returns theaddress of the node.
Figure 3.2.3 illustrates the creation of a node for single linked list.
node* getnode()
{ newnode
node* newnode;
newnode = (node *) malloc(sizeof(node)); 10 X
printf("\n Enter data: "); 100
scanf("%d", &newnode -> data);
newnode -> next = NULL;
return newnode;
}
The next field of the new node is made to point the first node (i.e.
start node) in the list by assigning the address of the first node.
The start pointer is made to point the new node by assigning the
address of the new node.
Figure 3.2.4 shows 4 items in a single linked list stored at different locations in
memory.
start
100
vo id createlist(int n)
{
int i;
node * new node;
node *temp;
for(i = 0; i < n ; i+ +)
{
new node = getnode();
if(start = = NULL)
{
start = new node;
}
else
{
temp = start;
while(temp - > next != NULL)
temp = temp - > next;
temp - > next = new node;
}
}
}
Insertion of a Node:
One of the most primitive operations that can be done in a singly linked list is the insertion
of a node. Memory is to be allocated for the new node (in a similar way that isdone while
creating a list) before reading the data. The new node will contain empty data field and
empty next field. The data field of the new node is then stored with the information read
from the user. The next field of the new node is assigned to NULL. The new node can then
be inserted at three different places namely:
The following steps are to be followed to insert a new node at the beginning of the list:
Figure 3.2.5 shows inserting a node into the single linked list at the beginning.
start
500
100
void insert_at_beg()
{
node *newnode;
newnode = getnode();
if(start == NULL)
{
start = newnode;
}
else
{
newnode -> next = start;
start = newnode;
}
}
Inserting a node at the end:
The following steps are followed to insert a new node at the end of the list:
Figure 3.2.6 shows inserting a node into the single linked list at the end.
start
100
50
void insert_at_end()
{
node *newnode, *temp;
newnode = getnode();
if(start == NULL)
{
start = newnode;
}
else
{
temp = start;
while(temp -> next != NULL)
temp = temp -> next;
temp -> next = newnode;
}
}
The following steps are followed, to insert a new node in an intermediate position in the
list:
Store the starting address (which is in start pointer) in temp and prev pointers.
Then traverse the temp pointer upto the specified position followed by prev
pointer.
After reaching the specified position, follow the steps given below:
prev -> next = newnode;
newnode -> next = temp;
Figure 3.2.7 shows inserting a node into the single linked list at a specified intermediate
position other than beginning and end.
start temp
100
50 300
500 new node
The function insert_at_mid(), is used for inserting a node in the intermediate position.
void insert_at_mid()
{
node *newnode, *temp, *prev;
int pos, nodectr, ctr = 1;
newnode = getnode();
printf("\n Enter the position: ");
scanf("%d", &pos);
nodectr = countnode(start);
if(pos > 1 && pos < nodectr)
{
temp = prev = start;
while(ctr < pos)
{
prev = temp;
temp = temp -> next;
ctr++;
}
prev -> next = newnode;
newnode -> next = temp;
}
else
{
printf("position %d is not a middle position", pos);
}
}
Deletion of a node:
Another primitive operation that can be done in a singly linked list is the deletion of a
node. Memory is to be released for the node to be deleted. A node can be deleted from
the list from three different places namely.
The following steps are followed, to delete a node at the beginning of the list:
Figure 3.2.8 shows deleting a node at the beginning of a single linked list.
start
200
X
200 300 400
temp
The function delete_at_beg(), is used for deleting the first node in the list.
void delete_at_beg()
{
node *temp;
if(start == NULL)
{
printf("\n No nodes are exist..");
return ;
}
else
{
temp = start;
start = temp -> next;
free(temp);
printf("\n Node deleted ");
}
}
Deleting a node at the end:
The following steps are followed to delete a node at the end of the list:
Figure 3.2.9 shows deleting a node at the end of a single linked list.
start
100
10 200 20 300 30 X 40
100 200 300
The function delete_at_last(), is used for deleting the last node in the list.
void delete_at_last()
{
node *temp, *prev;
if(start == NULL)
{
printf("\n Empty List..");
return ;
}
else
{
temp = start;
prev = start;
while(temp -> next != NULL)
{
prev = temp;
temp = temp -> next;
}
prev -> next = NULL;
free(temp);
printf("\n Node deleted ");
}
}
Deleting a node at Intermediate position:
The following steps are followed, to delete a node from an intermediate position in the
list (List must contain more than two node).
Figure 3.2.10 shows deleting a node at a specified intermediate position other than
beginning and end from a single linked list.
Start
100
10 20 30 40
The function delete_at_mid(), is used for deleting the intermediate node in the list.
void delete_at_mid()
{
int ctr = 1, pos, nodectr;
node *temp, *prev;
if(start == NULL)
{
printf("\n Empty List..");
return ;
}
else
{
printf("\n Enter position of node to delete: ");
scanf("%d", &pos);
nodectr = countnode(start);
if(pos > nodectr)
{
printf("\nThis node doesnot exist");
}
if(pos > 1 && pos < nodectr)
{
temp = prev = start;
while(ctr < pos)
{
prev = temp;
temp = temp -> next;
ctr ++;
}
prev -> next = temp -> next;
free(temp);
printf("\n Node deleted..");
}
else
{
printf("\n Invalid position..");
getch();
}
}
}
To display the information, you have to traverse (move) a linked list, node by node from
the first node, until the end of the list is reached. Traversing a list involves the following
steps:
The function traverse() is used for traversing and displaying the information stored in
the list from left to right.
void traverse()
node *temp;
temp = start;
printf("\n The contents of List (Left to Right):
\n"); if(start == NULL )
printf("\n Empty List");
else
printf("X");
Alternatively there is another way to traverse and display the information. That is in
reverse order. The function rev_traverse(), is used for traversing and displaying the
information stored in the list from right to left.
void rev_traverse(no de *st)
{
if(st = = NULL)
{
return;
}
else
{
rev_traverse(st - > next);
printf("%d - >", st - > data);
}
}
The following code will count the number of nodes exist in the list using recursion.
A header node is a special dummy node found at the front of the list. The use of header
node is an alternative to remove the first node in a list. For example, the picture below
shows how the list with data 10, 20 and 30 would be represented using a linked list
without and with a header node:
100
10 200 20 300 30 X
100 200 300
sta rt
400
Note that if your linked lists do include a header node, there is no need for the special
case code given above for the remove operation; node n can never be the first node in
the list, so there is no need to check for that case. Similarly, having a header node can
simplify the code that adds a node before a given node n.
Note that if you do decide to use a header node, you must remember to initialize an
empty list to contain one (dummy) node, you must remember not to include the header
node in the count of "real" nodes in the list.
It is also useful when information other than that found in each node of the list is needed.
For example, imagine an application in which the number of items in a list is often
calculated. In a standard linked list, the list function to count the number of nodes has
to traverse the entire list every time. However, if the current length is maintained in a
header node, that information can be obtained very quickly.
Another alternative is to allocate the nodes in blocks. In fact, if you know the maximum
size of a list a head of time, you can pre-allocate the nodes in a single array. The result
is a hybrid structure an array based linked list. Figure 3.5.1 shows an example of null
terminated single linked list where all the nodes are allocated contiguously in an array.
start a
100 b
200 300 X
c
100 200
Conceptual structure d
Implementation
A double linked list is a two-way list in which all nodes will have two links. This helps in
accessing both successor node and predecessor node from the given node position. It
provides bi-directional traversing. Each node contains three fields:
Left link.
Data.
Right link.
The left link points to the predecessor node and the right link points to the successor
node. The data field stores the required data.
Many applications require searching forward and backward thru nodes of a list.
For example searching for a name in a telephone directory would need forward
and backward scanning thru a region of the whole list.
Creation.
Insertion.
Deletion.
Traversing.
A double linked list is shown in figure 3.3.1.
start
X 200 100 20 300 200 30 X
100 200
The start
pointer holds
the address Stores the next
of the first last node is NULL.
node of the
list.
The beginning of the double linked list is stored in a "start" pointer which points to the
set to NULL.
struct dlinklist
node: left data right
struct dlinklist *left;
int data;
struct dlinklist *right;
}; start
Creating a double linked list starts with creating a node. Sufficient memory has to be
allocated for creating a node. The information is stored in the memory, allocated by using
the malloc() function. The function getnode(), is used for creating a node, after allocating
memory for the structure of type node, the information for the item (i.e., data) has to be
read from the user and set left field to NULL and right field also set to NULL (see figure
3.2.2).
node* getnode()
{
node* newnode;
newnode = (node *) malloc(sizeof(node));
printf("\n Enter data: "); X 10 X
scanf("%d", &newnode -> data);
newnode -> left = NULL;
newnode -> right = NULL;
return newnode;
}
The following
newnode =getnode();
The left field of the new node is made to point the previous node.
The previous nodes right field must be assigned with address of the
new node.
void createlist(int n)
{
int i;
node * new node;
node *tem p;
for(i = 0; i < n; i+ +)
{
new node = getnode();
if(start = = NULL)
{
start = new node;
}
else
{
temp = start;
while(temp - > right)
temp = temp - > right;
tem p - > right = new no de;
new node - > left = temp;
}
}
}
Figure 3.4.3 shows 3 items in a double linked list stored at different locations.
start
100
The following steps are to be followed to insert a new node at the beginning of the list:
newnode=getnode();
The function dbl_insert_beg(), is used for inserting a node at the beginning. Figure
3.4.4 shows inserting a node into the double linked list at the beginning.
start
400
X 40 100
400
The following steps are followed to insert a new node at the end of the list:
newnode=getnode();
temp = start;
while(temp -> right != NULL)
temp = temp -> right;
temp -> right = newnode;
newnode -> left = temp;
The function dbl_insert_end(), is used for inserting a node at the end. Figure 3.4.5
shows inserting a node into the double linked list at the end.
start
100
200
300 40 X
400
The following steps are followed, to insert a new node in an intermediate position in the
list:
newnode=getnode();
Ensure that the specified position is in between first node and last node. If
not, specified position is invalid. This is done by countnode() function.
Store the starting address (which is in start pointer) in temp and prev pointers.
Then traverse the temp pointer upto the specified position followed by prev
pointer.
After reaching the specified position, follow the steps given below:
The function dbl_insert_mid(), is used for inserting a node in the intermediate position.
Figure 3.4.6 shows inserting a node into the double linked list at a specified intermediate
position other than beginning and end.
Start
100 40 200
100
400
200 30
300
Deleting a node at the beginning:
The following steps are followed, to delete a node at the beginning of the list:
temp = start;
start = start -> right;
start -> left = NULL;
free(temp);
The function dbl_delete_beg(), is used for deleting the first node in the list. Figure
3.4.6 shows deleting a node at the beginning of a double linked list.
start
200
The following steps are followed to delete a node at the end of the list:
temp = start;
while(temp -> right != NULL)
{
temp = temp -> right;
}
temp -> left -> right = NULL;
free(temp);
The function dbl_delete_last(), is used for deleting the last node in the list. Figure 3.4.7
shows deleting a node at the end of a double linked list.
start
100
X 10 200 100 20 X
200
The following steps are followed, to delete a node from an intermediate position in the
list (List must contain more than two nodes).
Ensure that the specified position is in between first node and last
node. If not, specified position is invalid.
The function delete_at_mid(), is used for deleting the intermediate node in the list. Figure
3.4.8 shows deleting a node at a specified intermediate position other than beginning
and end from a double linked list.
Start
100
100 200
To display the information, you have to traverse the list, node by node from the first
node, until the end of the list is reached. The function traverse_left_right() is used for
traversing and displaying the information stored in the list from left to right.
The following steps are followed, to traverse a list from left to right:
To display the information from right to left, you have to traverse the list, node by node
from the first node, until the end of the list is reached. The function traverse_right_left()
is used for traversing and displaying the information stored in the list from right to left.
The following steps are followed, to traverse a list from right to left:
The following code will count the number of nodes exist in the list (using recursion).
It is just a single linked list in which the link field of the last node points back to the
address of the first node. A circular linked list has no beginning and no end. It is necessary
to establish a special pointer called start pointer always pointing to the first node of the
list. Circular linked lists are frequently used instead of ordinary linked list because many
operations are much easier to implement. In circular linked list no null pointers are used,
hence all pointers contain valid address.
Creation.
Insertion.
Deletion.
Traversing.
newnode = getnode();
start = newnode;
temp = start;
while(temp -> next != NULL)
temp = temp -> next;
temp -> next = newnode;
The following steps are to be followed to insert a new node at the beginning of the
circular list:
newnode = getnode();
start = newnode;
newnode -> next = start;
last = start;
while(last -> next != start)
last = last -> next;
newnode -> next = start;
start = newnode;
last -> next = start;
The function cll_insert_beg(), is used for inserting a node at the beginning. Figure 3.6.2
shows inserting a node into the circular single linked list at the beginning.
start
500
5 100
500
The following steps are followed to insert a new node at the end of the list:
newnode = getnode();
start = newnode;
newnode -> next = start;
temp = start;
while(temp -> next != start)
temp = temp -> next;
temp -> next = newnode;
newnode -> next = start;
Figure 3.6.3 shows inserting a node into the circular single linked list at the end.
start
100
50 100
The following steps are followed, to delete a node at the beginning of the list:
After deleting the node, if the list is empty then start = NULL.
The function cll_delete_beg(), is used for deleting the first node in the list. Figure 3.6.4
shows deleting a node at the beginning of a circular single linked list.
start
200
10 20 30
40 200
200 300 400
temp
The following steps are followed to delete a node at the end of the list:
temp = start;
prev = start;
while(temp -> next != start)
{
prev = temp;
temp = temp -> next;
}
prev -> next = start;
After deleting the node, if the list is empty then start = NULL.
The function cll_delete_last(), is used for deleting the last node in the list.
Figure 3.6.5 shows deleting a node at the end of a circular single linked list.
start
100
The following steps are followed, to traverse a list from left to right:
If
temp = start;
do
{
printf("%d ", temp -> data);
temp = temp -> next;
} while(temp != start);
Polynomial Manipulation
Polynomial manipulations are one of the most important applications of linked lists.
Polynomials are an important part of mathematics not inherently supported as a data
type by most languages. A polynomial is a collection of different terms, each comprising
coefficients, and exponents. It can be represented using a linked list. This representation
makes polynomial manipulation efficient.
While representing a polynomial using a linked list, each polynomial term represents a
node in the linked list. To get better efficiency in processing, we assume that the term
of every polynomial is stored within the linked list in the order of decreasing exponents.
Also, no two terms have the same exponent, and no term has a zero coefficient and
without coefficients. The coefficient takes a value of 1.
o The first part contains the value of the coefficient of the term.
o The second part contains the value of the exponent.
o The third part, LINK points to the next term (next node).
The structure of a node of a linked list that represents a polynomial is shown
below:
Consider a polynomial P(x) = 7x2 + 15x3 - 2 x2 + 9. Here 7, 15, -2, and 9 are the
coefficients, and 4,3,2,0 are the exponents of the terms in the polynomial. On
representing this polynomial using a linked list, we have
Observe that the number of nodes equals the number of terms in the polynomial. So we
have 4 nodes. Moreover, the terms are stored to decrease exponents in the linked list.
Such representation of polynomial using linked lists makes the operations like
subtraction, addition, multiplication, etc., on polynomial very easy.
Addition of Polynomials:
To add two polynomials, we traverse the list P and Q. We take corresponding terms of
the list P and Q and compare their exponents. If the two exponents are equal, the
coefficients are added to create a new coefficient. If the new coefficient is equal to 0,
then the term is dropped, and if it is not zero, it is inserted at the end of the new linked
list containing the resulting polynomial. If one of the exponents is larger than the other,
the corresponding term is immediately placed into the new linked list, and the term with
the smaller exponent is held to be compared with the next term from the other list. If
one list ends before the other, the rest of the terms of the longer list is inserted at the
end of the new linked list containing the resulting polynomial.
Let us consider an example an example to show how the addition of two polynomials is
performed,
Q (x) = 5x3 + 4 x2 - 5
These polynomials are represented using a linked list in order of decreasing exponents
as follows:
To generate a new linked list for the resulting polynomials that is formed on the addition
of given polynomials P(x) and Q(x), we perform the following steps,
1. Traverse the two lists P and Q and examine all the nodes.
2. We compare the exponents of the corresponding terms of two polynomials. The first
term of polynomials P and Q contain exponents 4 and 3, respectively. Since the exponent
of the first term of the polynomial P is greater than the other polynomial Q, the term
having a larger exponent is inserted into the new list. The new list initially looks as shown
below:
3. We then compare the exponent of the next term of the list P with the exponents of the
present term of list Q. Since the two exponents are equal, so their coefficients are added
and appended to the new list as follows:
4. Then we move to the next term of P and Q lists and compare their exponents. Since
exponents of both these terms are equal and after addition of their coefficients, we get
0, so the term is dropped, and no node is appended to the new list after this,
5. Moving to the next term of the two lists, P and Q, we find that the corresponding terms
have the same exponents equal to 0. We add their coefficients and append them to the
new list for the resulting polynomial as shown below: