Unit 3
Unit 3
LILIST: Introduction, Dynamic memory allocation, Single Linked list, Advantages and disadvantages of
Si Single linked list, single linked list vs Array, Representation of a linked list in memory,
O Operations: insertion, deletion, search Implementation of stack, Queue using linked list, Circular
L linked list, Double linked list.
Ptr is a pointer of type cast_type.The malloc returns a pointer to an area of memory with size
byte_size.The parameter passed to malloc() is of the type byte_size. This type is declared in the
header file alloc.h. byte_size is equivalent to the unsigned int data type. Thus, in compilers where
an int is 16 bits in size, malloc() can allocate a maximum of 64KB at a time, since the maximum
value of an unsigned int is 65535.
Return value:
On success, i.e., if free memory is available, malloc() returns a pointer to the newly allocated
memory. Usually, it is generic pointer. Hence, it should be typecast to appropriate data type
before using it to access the memory allocate.
.
Ex: 1) malloc(30); allocates 30 bytes of memory and returns the address of byte0.
2) malloc(sizeof(float)); allocates 4 bytes of memory and returns the address of byte0.
calloc( ) provides access to the C memory heap, which is available for dynamic allocation of
variable-sized blocks of memory.
Unlike malloc(), the function calloc( ) accepts two arguments: n and ele_size. The parameter n
specifies the number of items to allocate and ele_size specifies the size of each item.
Return value:
✔ On success, i.e., if free memory is available, calloc( ) returns a pointer to the newly
allocated memory. Usually, it is generic pointer. Hence, it should be typecast to
appropriate data type before using it to access the memory allocated.
✔ On failure, i.e., if enough free memory does not exist for block, calloc( ) returns NULL.
Ex: 1) calloc(3,5); allocates 15 bytes of memory and returns the address of byte0.
2) calloc(6,sizeof(float)); allocates 24 bytes of memory and returns the address of byte0.
The function realloc() allocates new memory space of size newsize to the pointer variable ptr and
returns a pointer to the first byte of the new memory block.
ptr is the pointer to the memory block that is previously obtained by calling malloc(), calloc() or
realloc(). If ptr is NULL pointer, realloc() works just like malloc().
Return value:
✔ On success, this function returns the address of the reallocated block, which might be
different from the address of the original block.
✔ On failure, i.e., if the block can’t be reallocated or if the size passed is 0, the function
returns NULL.
The function realloc() is more useful when the maximum size of allocated block cann’t be
decided in advance.
A singly linked list, or simply a linked list, is a linear collection of data items. The linear order is
given by means of POINTERS. These types of lists are often referred to as linear linked list.
* Each item in the list is called a node.
* Each node of the list has two fields:
1. Data - contains the element being stored in the list.
2. Next address- contains the address of the next node in the list.
* The last node in the list contains NULL pointer to indicate that it is the end of the list.
A new node can be inserted into linked list which requires resetting of pointers.
Inserting a new node into the list has 4 situations
b). Inserting a node at the end of a linked list involves the following steps:
/*
Function for inserting a node at end*/
void insert_end()
{
struct node *ptr,*new_node;
int ele;
printf("Enter -1 to end the list \nEnter element");
scanf("%d",&ele);
new_node=(struct node *)malloc(sizeof(struct node));
new_node->data=ele;
new_node->next=NULL;
ptr=start;
while(ptr->next!=NULL)
ptr=ptr->next;
ptr->next=new_node;
}
c).Inserting a node after a given node involves following steps:
c). Deleting the node after the given node involves the following steps
1. Search for the given key element by using search function and assign key element address to
keyptr
2. Take pointer variable Aptr which points to next field of keyptr
3. Set next field of keyptr to next field of Aptr
4. Deallocate memory for Aptr node from list
1. Linked list is Dynamic data structure- It is not necessary to know in advance the number
of elements to be stored in the list . At run time we can allocate as much memory as we
can. Though we can allocate any number of nodes in linked list.
2. Linked list can grow and shrink during run time.
3. Insertion and deletion operations are easier.-We can insert any node at any place easily
and similarly we can remove it easily. In insertion operation we have to just update next
link of node.
4. Efficient memory utilization i.e; no need to pre allocate memory.-Memory is allocated at
run time as per requirement, so that linked list data structure provides us strong command
on memory utilization
5. Faster access time, can be expanded in constant time without memory over head.
6. Linear data structures such as stack, queue can be easily implemented using linked list.
In an array, elements are stored in contiguous memory Address of the memory location allocated to the new element is stored
location or consecutive manner in the memory. in the previous node of linked list, hence formaing a link between the
two nodes/elements.
In case of linked list, a new element is stored at the first free and
To implement a stack using linked list we need to define a node which in turn consists of data and
a pointer to the next node. The advantage of representing stacks using linked lists is that we can
decide which end should be the top of the stack.
In our example we will select front end as the top of the stack in which we can add and remove
data.
The working principle of stack is LIFO. Using a linked list is one way to implement a stack so
that it can handle essentially any number of elements. The operations performed on a stack are
push ( ) and pop ( ).When implementing a stack using linked lists, pushing elements on to the
stack and popping elements from the stack is performed at the same end i.e. TOP.
Like stacks when implementing a queue using linked list a node must be defined .Front end of
Queue is used to remove data and rear end is used to add data. The advantage of representing a
queue using linked list is that it allows us to select any end to add and remove data items. So, we
can select the end of the linked list as rear and beginning of the list as front.
The working principle of queue is FIFO. Using a linked list is one way to implement a queue so
that it can handle essentially any number of elements. The operations performed on a queue are
enqueue ( ) and dequeue ( ).When implementing a queue using linked lists, inserting elements to
the queue is done at one end and deletion of elements from the queue is done at the other end.
Inserting a node at the Rear end:
1. If queue is empty, then display message “ Queue is empty – no deletion is possible” and
exit.
2. Otherwise, Take pointer variable ptr which points toFRONT.
3. Set FRONT points to the next field of FRONT.
4. Deallocate memory for ptr node from list.
A circularly linked list, or simply circular list, is a linked list in which the last node always points
to the first node. This type of list can be build just by replacing the NULL pointer at the end of the
list with a pointer which points to the first node. There is no first or last node in the circular list.
Advantages:
● Any node can be traversed starting from any other node in the list.
● There is no need of NULL pointer to signal the end of the list and hence, all pointers
contain valid addresses.
● In contrast to singly linked list, deletion operation in circular list is simplified as the search
for the previous node of an element to be deleted can be started from that item itself.
Conceptual view of circular linkedlist
Linked list provides to insert or delete nodes whenever necessary. First we have to create the
nodes. This is possible by using self referential structure, pointers and dynamic memory
allocation functions like malloc.First we have to declare structure and create memory by using
malloc function.
struct node
{
int data;
struct node *next;
};
struct node *newnode,*start=NULL;
newnode=(struct node *) malloc(sizeof(struct node));
The above statement will allocate a block of memory whose size is equal to size of node of type
structure and its address is assigned to pointer variable newnode. This pointer indicates the
beginning of linked list
}
}
a). Inserting a node at the beginning of a circular linked list involves the following steps:
b). Inserting a node at the end of a circular linked list involves the following steps:
The memory space of deleted node may be released for reuse .The process of deletion also
involves search for the item to be deleted.
c). Deleting the node after the given node involves the following steps
1. Search for the given key element by using search function and assign key element address to
keyptr
2. Take pointer variable Aptr which points to next field of keyptr
3. Set next field of keyptr to next field of Aptr
4. Deallocate memory for Aptr node from list
/*Function for deleting a node after given node*/
void delete_after()
{
struct node *keyptr,*Aptr;
int key;
printf("\nEnter the key element");
scanf("%d",&key);
keyptr= search(key);
if(keyptr==NULL)
printf("\nKey is not found");
else
{
Aptr=keyptr->next;
keyptr->next=Aptr->next;
free(Aptr);
}
}
d). Deleting the node before the given node involves the following steps
1. Search for the given key element by using search function and assign key element address
to keyptr
2. Take pointer variable ptr which points to START
3. Move ptr such that next field of ptr = keyptr and preptr points to ptr(address of before
node of ptr)
4. Set next field of keyptr to next field of ptr
5. Deallocate memory for ptr node from list
In a singly linked list, each element contains a pointer to the next element. We have seen this
before. In single linked list, traversing is possible only in one direction. Sometimes, we have to
traverse the list in both directions to improve performance of algorithms. To enable this, we
require links in both the directions, that is, the element should have pointers to the right element
as well as to its left element. This type of list is called doubly linked list.
Doubly linked list is defined as a collection of elements, each element consisting of three fields:
• Pointer to left element,
• Data field, and
• Pointer to right element.
Left link of the leftmost element is set to NULL which means that there is no left element to that.
And right link of the rightmost element is set to NULL which means that there is no right element
to that.
struct node
{
struct node *prev;
int data;
struct node *next;
};
struct node *newnode,*start=NULL;
newnode=(struct node *) malloc(sizeof(struct node));
The above statement will allocate a block of memory whose size is equal to size of node of type
structure and its address is assigned to pointer variable newnode. This pointer indicates the
beginning of linked list
while(ptr->next!=NULL)
ptr=ptr->next;
ptr->next=newnode;
newnode->prev=ptr;
}
printf("Enter -1 to end the list \nEnter element");
scanf("%d",&ele);
}
}
a). Inserting a node at the beginning of a doubly linked list involves the following steps:
b). Inserting a node at the end of a linked list involves the following steps:
else
{
newnode->prev=keyptr->prev;
newnode->next=keyptr;
keyptr->prev->next=newnode;
keyptr->prev=newnode;
}
}
2.Deleting a node from double linked list
Deleting a node from the list is easier than insertion as only one pointer needs to be changed.
Here again we have four different situations
a). Deleting the first node
b). Deleting the last node
c). Deleting the node after the given node
d). Deleting the node before the given node
The memory space of deleted node may be released for reuse .The process of deletion also
involves search for the item to be deleted.
1. Search for the given key element by using search function and assign key element address
to keyptr
2. Take pointer variable Aptr which points to next field of keyptr
3. Set next field of keyptr to next field of Aptr
4. Set next field of Aptr of prev field points to keyptr
5. Deallocate memory for Aptr node from list
/*Function for deleting a node after given node*/
void delete_after()
{
struct node *keyptr,*Aptr;
int key;
printf("\nEnter the key element");
scanf("%d",&key);
keyptr= search(key);
if(keyptr==NULL)
printf("\nKey is not found");
else
{
Aptr=keyptr->next;
keyptr->next=Aptr->next;
Aptr->next->prev=keyptr;
free(Aptr);
}
}
d). Deleting the node before the given node involves the following steps
1. Search for the given key element by using search function and assign key element address to
keyptr
2. Take pointer variable preptr which points to prev field of keyptr
3. Set prev field of keyptr to prev field of preptr
4. Set prev field of preptr of next field to keyptr
5. Deallocate memory for ptr node from list
/*Function for deleting a node before given node*/
void delete_before()
{
struct node *preptr,*keyptr;
int key;
printf("\nEnter the key element");
scanf("%d",&key);
keyptr= search(key);
if(keyptr==NULL)
printf("\nKey is not found");
else
{
preptr=keyptr->prev;
keyptr->prev=preptr->prev;
preptr->prev->next=keyptr;
free(preptr);
}
}