Linked List
Linked List
INTRODUCTION: Dynamic allocation is a pretty unique feature to C (amongst high level languages). It
enables us to create data types and structures of any size and length to suit our programs need within
the program.
char *cp;
cp = malloc(100);
attempts to get 100 bytes and assigns the start address to cp.
Also it is usual to use the sizeof() function to specify the number of bytes:
int *ip;
ip = (int *) malloc(100*sizeof(int));
Some C compilers may require to cast the type of conversion. The (int *) means coercion to an integer
pointer. Coercion to the correct pointer type is very important to ensure pointer arithmetic is
performed correctly. I personally use it as a means of ensuring that I am totally correct in my coding
and use cast all the time.
int *ip;
ip = (int *) calloc(100, sizeof(int));
Realloc is a function which attempts to change the size of a previous allocated block of memory. The
new size can be larger or smaller. If the block is made larger then the old contents remain unchanged
and memory is added to the end of the block. If the size is made smaller then the remaining contents
are unchanged.
If the original block size cannot be resized then realloc will attempt to assign a new block of memory
and will copy the old block contents. Note a new pointer (of different value) will consequently be
returned. You must use this new value. If new memory cannot be reallocated then realloc returns
NULL
Thus to change the size of memory allocated to the *ip pointer above to an array block of 50 integers
instead of 100, simply do:
Releasing memory: When you have finished with a piece of memory allocated in this way you should
be sure to free it up using the free function:
free(p);
where p must be a pointer to some memory allocated by malloc. If you fail to free up memory after
you have finished with it your program will gradually use more and more memory until the computer
runs out. Horrible things happen if you try to use memory after it has been freed.
LINKED LIST:
In a sequential representation, the items of a stack or a queue are implicitly ordered by sequential
order of storage. Suppose that items of stack or queue were explicitly ordered, that is each item
contained within itself the address of the next item.
Such an explicit ordering gives rise to a new data structure called LINKED LIST.
Definition: A LINKED LIST or ONE WAY LIST is a linear collection of data elements called nodes
where the linear order is given by means of pointers. i.e each node is divided into two parts : the first
part contains information of element, and the second part called link field or next pointer field
contains address of next node in list.
START
REPRESENTATION:
To maintain it in memory requires two linear arrays. We call them as INFO and LIST.
INFO[K] Information Part
LINK[K] Next pointer field
START Beginning of the list
NULL End of list
PRIMITIVE OPERATIONS: The following primitive operations can be performed on linked list.
Traversing
Insertion
Deletion
We traverse the LIST in order to process each node exactly once. Our traversing algorithm uses a
pointer variable p which points to node that is currently being processed. Accordingly pnext points
to next node to be processed.
INSERTION INTO A LINKED LIST: Insertion operation on linked list basically comes up in various
situations
START
500
500
10 X
START
600
600 500
20 10 X
START
600
20 10 30 X
START
600
20 10 40 30 X
DELETION FROM A LINKED LIST: Deletion operation on linked list basically comes up in various
situations:
void delete_at_begin(void) {
NODE *p;
if(start==NULL)
return;
else {
p=start;
start=start->next;
printf("\n deleted item = %d ",p->info);
free(p);
}
}
START
600
20 10 40 30 X
START
600
10 40 30 X
C routine for deleting a node at the end of the list:
void delete_at_end(void) {
NODE *p,*loc;
if(start==NULL)
return;
else if(start->next==NULL) {
p=start;
start=NULL;
printf("\n deleted item = %d ",p->info);
free(p);
}
else {
loc=start;
p=start->next;
while(p->next!=NULL) {
loc=p;
p=p->next;
}
loc->next=NULL;
fflush(stdout);
printf("\n deleted item = %d ",p->info);
free(p);
}
}
START
600
20 10 40 30 X
START
600
20 10 40 X
C routine for deleting a node at a particular position in the list:
void delete_at_pos() {
NODE *p,*temp;
int i,loc;
printf("\n enter the location (position) at which to delete : ");
scanf("%d",&loc);
if(start==NULL)
printf("\n EMPTY LIST ");
else {
p=start;
for(i=1;i<loc;i++) {
temp=p;
p=p->next;
}
printf("\n deleted item = %d ",p->info);
temp->next=p->next;
free(p);
}
}
START
600
20 10 40 30 X
START
600
20 40 30 X
Linked implementation of a stack:
The operation of adding an element to the front of a linked list is quite similar to that of pushing an
element onto a stack. In both cases, a new item is added as the only immediately accessible item in a
collection. A stack can be accessed only from the pointer to its first element. Similarly, the operation of
removing the first element from a linked list is analogous to popping a stack. In both cases the only
immediately accessible item of a collection is removed from that collection, and the next item becomes
immediately accessible.
Thus we have discovered another way of implementing a stack. A stack may be represented by a linear
linked list. The first node of the list is the top of the stack. If an external pointer s points to such a
linked list, the operation push(s, x) may be implemented by
p=getnode ();
info (p) =x;
next (p) =s;
s=p;
The operation empty (s) is merely a test of whether s equals null. The operation x=pop(s) removes the
first node from a nonempty list and signals underflow if the list is empty;
if (empty(s)) {
printf (‘stack underflow’);
exit (1);
}
else {
p = s;
s = next (p);
x = info (p);
freenode (p);
} /* end if */
STACK
500
500
10 X
Pushing element 20 at the top of the stack
START
600
600 500
20 10 X
The advantage of the implementation of stacks is that all stacks being used by a program can share the
same available list. When any stack needs a node, it can obtain it from the single available list. When
any stack no longer needs a node, it returns the node to that same available list. As long as the total
amount of space needed by all the stacks at any one time is less than the amount of space initially
available to them all, each stack is able to grow and shrink to any size.
Let us now examine how to represent a queue as a linked list. Recall that items are deleted from the
front of a queue and inserted at the rear. Let a pointer to the first element of a list represent the rear of
the queue, as depicted below
QUEUE
600
600 500
20 10 X
QUEUE
600
20 10 30 X
Under the list representation, a queue q consists of a list and two pointers, q.front and q. rear. The
operations empty (q) and x = remove (q) are completely analogous to empty(s) and x = pop(s), with
the pointer q.front replacing s. However, special attention is required when the last element is
removed from a queue. In that case, q.rear must be null. The algorithm for x = remove (q) is therefore
as follows:
if (empty (q)){
printf (“queue underflow”);
exit (1);
}
p=q.front;
x=info(p);
q.front = next(p);
if (q.front == null)
q. rear = null;
freenode (p);
return (x);
p= getnode();
info (p) = x;
next (p) = null;
if (q.rear == null)
q.front = p;
else
next (q. rear) = p;
q. rear =p;
What are the disadvantages of representing a stack or queue by a linked list? Clearly, a node in a linked
list occupies more storage than a corresponding element in an array, since two pieces of information
per element are necessary in a list node (info and next), where as only one piece of information is
needed in the array implementation. However the space used for a list node is usually not twice the
space used by an array element, since the element in such a list usually consists of structures with
many sub fields.
Another disadvantage is the additional time spent in managing the available list. Each addition and
deletion of an element from a stack or a queue involves a corresponding deletion or addition to the
available list.
The advantage of using linked lists is that all the stacks and queues of a program have access to the
same free list of nodes. Nodes not used by one stack may be used by another, as long as the total
number of nodes in use at any one time is not greater than the total number of nodes available.
Given a pointer p to a node in a linear list, we cannot reach any of the nodes that precede node(p).
Suppose that a small change is made to the structure of the linear list, so that the next field in the last
node contains a pointer back to the first node rather than a NULL pointer. Such a list is called circular
list. Illustrated below:
500 600 700
10 20 30
Notice that the only difference between this list and the basic list is the fact that the last node does not
point to the null address. It now points to the "first" node in the list. Instead of using the null address
to test for the "end" of the list we now need to use the beginning address!
Notice also that the only thing that identifies the "start" of the list is where the entry pointer happens
to be pointing. It would make no difference if we were to shift the entry pointer to any of the nodes in
the list. However we must have at least one entry pointer into the list otherwise we end up with an
isolated list which cannot be accessed at all.
#include<stdio.h>
#include<conio.h>
#include<malloc.h>
#include<process.h>
struct node {
int info;
struct node *next;
}*start=NULL,*last=NULL;
500
10
After tracing the above routine we get the following data structure.
600 500
20 10
return start;
}
600 500
20 10
Insert 30 at the end of the list.
After tracing the above routine we get the following data structure.
20 10 30
return start;
}
20 10 30
After tracing the above routine we get the following data structure.
500 700
10 30
// routine for deletion @ end of circular list
return start;
}
500 700
10 30
After tracing the above routine we get the following data structure.
500
10
Thus so far we have been restricted to traversing linear linked list in only one direction. In certain
applications, it is very desirable and sometimes indispensable that a list may be traversed in either the
forward or reverse manner. This property of a linked list gave birth to another variation called as
DOUBLY LINKED LIST or TWO WAY LIST.
Double linked list is a linear collection of elements called as NODES, where each node is divided into
three parts.
FIRST LAST
600 700
X 20 10 30 X
NOTE: The FORW pointer of the last node and BACK pointer of the first node in case of double linked
list is always a NULL POINTER.
#include<stdio.h>
#include<conio.h>
#include<malloc.h>
#include<process.h>
struct node {
int info;
struct node *next;
struct node *prev;
};