22CS201 DATA STRUCTURES
II SEMESTER CSE
LINKED LIST
[Link] SELVI
ASSISTANT PROFESSOR
CSE DEPARTMENT
R.M.D ENGINEERING COLLEGE
Introduction
• A linked list is a data structure which can change
during execution.
– Successive elements are connected by pointers.
– Last element points to NULL.
– It can grow or shrink in size during execution of a
program.
– It can be made just as long as required.
head
– It does not waste memory space.
A B C
• Keeping track of a linked list:
– Must know the pointer to the first element of the
list (called start, head, etc.).
• Linked lists provide flexibility in allowing the
items to be rearranged efficiently.
– Insert an element.
– Delete an element.
Illustration: Insertion
A B C
Item to be
tmp X inserted
A B C
curr
X
Pseudo-code for insertion
typedef struct nd {
struct item data;
struct nd * next;
} node;
void insert(node *curr)
{
node * tmp;
tmp=(node *) malloc(sizeof(node));
tmp->next=curr->next;
curr->next=tmp;
}
Illustration: Deletion
Item to be deleted
A B C
tmp
curr
A B C
Pseudo-code for deletion
typedef struct nd {
struct item data;
struct nd * next;
} node;
void delete(node *curr)
{
node * tmp;
tmp=curr->next;
curr->next=tmp->next;
free(tmp);
}
In essence ...
• For insertion:
– A record is created holding the new item.
– The next pointer of the new record is set to link it to
the item which is to follow it in the list.
– The next pointer of the item which is to precede it
must be modified to point to the new item.
• For deletion:
– The next pointer of the item immediately preceding
the one to be deleted is altered, and made to point
to the item following the deleted item.
Array versus Linked Lists
• Arrays are suitable for:
– Inserting/deleting an element at the end.
– Randomly accessing any element.
– Searching the list for a particular value.
• Linked lists are suitable for:
– Inserting an element.
– Deleting an element.
– Applications where sequential access is required.
– In situations where the number of elements cannot
be predicted beforehand.
22CS201 DATA STRUCTURES
II SEMESTER CSE
LINKED LIST-TYPES
[Link] SELVI
ASSISTANT PROFESSOR
CSE DEPARTMENT
R.M.D ENGINEERING COLLEGE
Types of Lists
• Depending on the way in which the links are
used to maintain adjacency, several different
types of linked lists are possible.
– Linear singly-linked list (or simply linear list)
head
• One we have discussed so far.
A B C
– Circular linked list
• The pointer from the last element in the list points back
to the first element.
head
A B C
– Doubly linked list
• Pointers exist between adjacent nodes in both
directions.
• The list can be traversed either forward or backward.
• Usually two pointers are maintained to keep track of
head tail
the list, head and tail.
A B C
Basic Operations on a List
• Creating a list
• Traversing the list
• Inserting an item in the list
• Deleting an item from the list
• Concatenating two lists into one
List is an Abstract Data Type
• What is an abstract data type?
– It is a data type defined by the user.
– Typically more complex than simple data types like
int, float, etc.
• Why abstract?
– Because details of the implementation are hidden.
– When you do some operation on the list, say insert
an element, you just call a function.
– Details of how the list is implemented or how the
insert function is written is no longer required.
Conceptual Idea
Insert
List
implementation
Delete
and the
related functions
Traverse
Example: Working with linked list
• Consider the structure of a node as follows:
struct stud {
int roll;
char name[25];
int age;
struct stud *next;
};
/* A user-defined data type called “node” */
typedef struct stud node;
node *head;
Creating a List
How to begin?
• To start with, we have to create a node (the
first node), and make head point to it.
head = (node *)
malloc(sizeof(node));
head
roll
name next
age
Contd.
• If there are n number of nodes in the initial
linked list:
– Allocate n records, one by one.
– Read in the fields of the records.
– Modify the links of the records so that the chain is
head formed.
A B C
node *create_list()
{
int k, n;
node *p, *head;
printf ("\n How many elements to enter?");
scanf ("%d", &n);
for (k=0; k<n; k++)
{
if (k == 0) {
head = (node *) malloc(sizeof(node));
p = head;
}
else {
p->next = (node *) malloc(sizeof(node));
p = p->next;
}
scanf ("%d %s %d", &p->roll, p->name, &p->age);
}
p->next = NULL;
return (head);
}
• To be called from main() function as:
node *head;
………
head = create_list();
Traversing the List
What is to be done?
• Once the linked list has been constructed and
head points to the first node of the list,
– Follow the pointers.
– Display the contents of the nodes as they are
traversed.
– Stop when the next pointer points to NULL.
void display (node *head)
{
int count = 1;
node *p;
p = head;
while (p != NULL)
{
printf ("\nNode %d: %d %s %d", count,
p->roll, p->name, p->age);
count++;
p = p->next;
}
printf ("\n");
}
• To be called from main() function as:
node *head;
………
display (head);
Inserting a Node in a List
How to do?
• The problem is to insert a node before a
specified node.
– Specified means some value is given for the node
(called key).
– In this example, we consider it to be roll.
• Convention followed:
– If the value of roll is given as negative, the node
will be inserted at the end of the list.
Contd.
• When a node is added at the beginning,
– Only one next pointer needs to be modified.
• head is made to point to the new node.
• New node points to the previously first element.
• When a node is added at the end,
– Two next pointers need to be modified.
• Last node now points to the new node.
• New node points to NULL.
• When a node is added in the middle,
– Two next pointers need to be modified.
• Previous node now points to the new node.
• New node points to the next node.
void insert (node **head)
{
int k = 0, rno;
node *p, *q, *new;
new = (node *) malloc(sizeof(node));
printf ("\nData to be inserted: ");
scanf ("%d %s %d", &new->roll, new->name, &new->age);
printf ("\nInsert before roll (-ve for end):");
scanf ("%d", &rno);
p = *head;
if (p->roll == rno) /* At the beginning */
{
new->next = p;
*head = new;
}
else
{
while ((p != NULL) && (p->roll != rno))
{
q = p;
p = p->next;
} The pointers
q and p
if (p == NULL) /* At the end */ always point
{ to consecutive
q->next = new; nodes.
new->next = NULL;
}
else if (p->roll == rno)
/* In the middle */
{
q->next = new;
new->next = p;
}
}
}
• To be called from main() function as:
node *head;
………
insert (&head);
Deleting a node from the list
What is to be done?
• Here also we are required to delete a
specified node.
– Say, the node whose roll field is given.
• Here also three conditions arise:
– Deleting the first node.
– Deleting the last node.
– Deleting an intermediate node.
void delete (node **head)
{
int rno;
node *p, *q;
printf ("\nDelete for roll :");
scanf ("%d", &rno);
p = *head;
if (p->roll == rno)
/* Delete the first element */
{
*head = p->next;
free (p);
}
else
{
while ((p != NULL) && (p->roll != rno))
{
q = p;
p = p->next;
}
if (p == NULL) /* Element not found */
printf ("\nNo match :: deletion failed");
else if (p->roll == rno)
/* Delete any other element */
{
q->next = p->next;
free (p);
}
}
}
22CS201 DATA STRUCTURES
II SEMESTER CSE
STACK
[Link] SELVI
ASSISTANT PROFESSOR
CSE DEPARTMENT
R.M.D ENGINEERING COLLEGE
A Last-in First-out (LIFO) List
In Out
C B A B C
Also called a
STACK
Example 3 :: Last-In-First-Out STACK
Assume:: stack contains integer elements
void push (stack *s, int element);
/* Insert an element in the stack */
int pop (stack *s);
/* Remove and return the top element */
void create (stack *s);
/* Create a new stack */
int isempty (stack *s);
/* Check if stack is empty */
int isfull (stack *s);
/* Check if stack is full */
push
pop
create
STACK
isempty
isfull
Contd.
• We shall look into two different ways of
implementing stack:
– Using arrays
– Using linked list
Stack Implementations: Using Array
and Linked List
STACK USING ARRAY
PUSH
top
top
STACK USING ARRAY
POP
top
top
Stack: Linked List Structure
PUSH OPERATION
top
Stack: Linked List Structure
POP OPERATION
top
Basic Idea
• In the array implementation, we would:
– Declare an array of fixed size (which determines the maximum size of
the stack).
– Keep a variable which always points to the “top” of the stack.
• Contains the array index of the “top” element.
• In the linked list implementation, we would:
– Maintain the stack as a linked list.
– A pointer variable top points to the start of the list.
– The first element of the linked list is considered as the stack top.
Declaration
#define MAXSIZE 100 struct lifo
{
struct lifo int value;
{ struct lifo *next;
int st[MAXSIZE]; };
int top; typedef struct lifo
}; stack;
typedef struct lifo
stack; stack *top;
stack s;
ARRAY LINKED LIST
Stack Creation
void create (stack *s) void create (stack **top)
{ {
s->top = -1; *top = NULL;
/* s->top points to /* top points to NULL,
last element indicating empty
pushed in; stack */
initially -1 */ }
}
LINKED LIST
ARRAY
Pushing an element into the stack
void push (stack *s, int element)
{
if (s->top == (MAXSIZE-1))
{
printf (“\n Stack overflow”);
exit(-1);
}
else
{
s->top ++;
s->st[s->top] = element;
}
}
ARRAY
void push (stack **top, int element)
{
stack *new;
new = (stack *) malloc(sizeof(stack));
if (new == NULL)
{
printf (“\n Stack is full”);
exit(-1);
}
new->value = element;
new->next = *top;
*top = new;
}
LINKED LIST
Popping an element from the stack
int pop (stack *s)
{
if (s->top == -1)
{
printf (“\n Stack underflow”);
exit(-1);
}
else
{
return (s->st[s->top--]);
}
}
ARRAY
int pop (stack **top)
{
int t;
stack *p;
if (*top == NULL)
{
printf (“\n Stack is empty”);
exit(-1); LINKED LIST
}
else
{
t = (*top)->value;
p = *top;
*top = (*top)->next;
free (p);
return t;
}
}
Checking for stack empty
int isempty (stack *s) int isempty (stack *top)
{ {
if (s->top == -1) if (top == NULL)
return 1; return (1);
else else
return (0); return (0);
} }
ARRAY LINKED LIST
Checking for stack full
int isfull (stack *s) • Not required for linked list
{ implementation.
if (s->top == • In the push() function, we
(MAXSIZE–1)) can check the return value of
malloc().
return 1;
– If -1, then memory cannot be
else
allocated.
return (0);
}
ARRAY LINKED LIST
Example main function :: array
#include <stdio.h> push(&A,30);
#define MAXSIZE 100 push(&B,100); push(&B,5);
struct lifo printf (“%d %d”, pop(&A),
{ pop(&B));
int st[MAXSIZE];
int top; push (&A, pop(&B));
}; if (isempty(&B))
typedef struct lifo stack; printf (“\n B is empty”);
main() }
{
stack A, B;
create(&A); create(&B);
push(&A,10);
push(&A,20);
Example main function :: linked list
#include <stdio.h> push(&A,30);
struct lifo push(&B,100);
{ push(&B,5);
int value;
printf (“%d %d”,
struct lifo *next;
pop(&A), pop(&B));
};
typedef struct lifo stack; push (&A, pop(&B));
main() if (isempty(B))
{ printf (“\n B is
stack *A, *B; empty”);
create(&A); create(&B); }
push(&A,10);
push(&A,20);
22CS201 DATA STRUCTURES
II SEMESTER CSE
QUEUE
[Link] SELVI
ASSISTANT PROFESSOR
CSE DEPARTMENT
R.M.D ENGINEERING
COLLEGE
A First-in First-out (FIFO) List
In Out
B A
C B A
Also called a QUEUE
Example 4 :: First-In-First-Out QUEUE
Assume:: queue contains integer elements
void enqueue (queue *q, int element);
/* Insert an element in the queue */
int dequeue (queue *q);
/* Remove an element from the queue */
queue *create();
/* Create a new queue */
int isempty (queue *q);
/* Check if queue is empty */
int size (queue *q);
/* Return the no. of elements in queue */
enqueue
dequeue
create
QUEUE
isempty
size
Queue Implementation using Linked
List
Basic Idea
• Basic idea:
– Create a linked list to which items would be added
to one end and deleted from the other end.
– Two pointers will be maintained:
• One pointing to the beginning of the list (point from
where elements will be deleted).
• Another pointing to the end of the list (point where Rear
new elements will be inserted).
Front DELETION INSERTION
QUEUE: LINKED LIST STRUCTURE
ENQUEUE
front rear
QUEUE: LINKED LIST STRUCTURE
DEQUEUE
front rear
QUEUE using Linked List
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
struct node{
char name[30];
struct node *next;
};
typedef struct node _QNODE;
typedef struct {
_QNODE *queue_front, *queue_rear;
} _QUEUE;
_QNODE *enqueue (_QUEUE *q, char x[])
{
if(q->queue_rear==NULL)
_QNODE *temp;
{
temp= (_QNODE *)
q->queue_rear=temp;
malloc (sizeof(_QNODE));
q->queue_front=
if (temp==NULL){
q->queue_rear;
printf(“Bad allocation \n");
}
return NULL;
else
}
{
strcpy(temp->name,x);
q->queue_rear->next=temp;
temp->next=NULL;
q->queue_rear=temp;
}
return(q->queue_rear);
}
char *dequeue(_QUEUE *q,char x[])
{ else{
_QNODE *temp_pnt; strcpy(x,q->queue_front->name);
temp_pnt=q->queue_front;
if(q->queue_front==NULL){ q->queue_front=
q->queue_rear=NULL; q->queue_front->next;
printf("Queue is empty \n"); free(temp_pnt);
return(NULL); if(q->queue_front==NULL)
} q->queue_rear=NULL;
return(x);
}
}
void init_queue(_QUEUE *q)
{
q->queue_front= q->queue_rear=NULL;
}
int isEmpty(_QUEUE *q)
{
if(q==NULL) return 1;
else return 0;
}
main()
{
int i,j;
char command[5],val[30];
_QUEUE q;
init_queue(&q);
command[0]='\0';
printf("For entering a name use 'enter <name>'\n");
printf("For deleting use 'delete' \n");
printf("To end the session use 'bye' \n");
while(strcmp(command,"bye")){
scanf("%s",command);
if(!strcmp(command,"enter")) {
scanf("%s",val);
if((enqueue(&q,val)==NULL))
printf("No more pushing please \n");
else printf("Name entered %s \n",val);
}
if(!strcmp(command,"delete")) {
if(!isEmpty(&q))
printf("%s \n",dequeue(&q,val));
else printf("Name deleted %s \n",val);
}
} /* while */
printf("End session \n");
}
Problem With Array Implementation
ENQUEUE DEQUEUE
Effective queuing storage area of array gets reduced.
0 N
front
front rearrear
Use of circular array indexing
Queue: Example with Array Implementation
#define MAX_SIZE 100
typedef struct { char name[30];
} _ELEMENT;
typedef struct {
_ELEMENT q_elem[MAX_SIZE];
int rear;
int front;
int full,empty;
} _QUEUE;
Queue Example: Contd.
void init_queue(_QUEUE *q)
{q->rear= q->front= 0;
q->full=0; q->empty=1;
}
int IsFull(_QUEUE *q)
{return(q->full);}
int IsEmpty(_QUEUE *q)
{return(q->empty);}
Queue Example: Contd.
void AddQ(_QUEUE *q, _ELEMENT ob)
{
if(IsFull(q)) {printf("Queue is Full \n"); return;}
q->rear=(q->rear+1)%(MAX_SIZE);
q->q_elem[q->rear]=ob;
if(q->front==q->rear) q->full=1; else q->full=0;
q->empty=0;
return;
}
Queue Example: Contd.
_ELEMENT DeleteQ(_QUEUE *q)
{
_ELEMENT temp;
[Link][0]='\0';
if(IsEmpty(q)) {printf("Queue is EMPTY\n");return(temp);}
q->front=(q->front+1)%(MAX_SIZE);
temp=q->q_elem[q->front];
if(q->rear==q->front) q->empty=1; else q->empty=0;
q->full=0;
return(temp);
}
Queue Example: Contd.
main() #include <stdio.h>
{ #include <stdlib.h>
int i,j; #include <string.h>
char command[5];
_ELEMENT ob;
_QUEUE A;
init_queue(&A);
command[0]='\0';
printf("For adding a name use 'add [name]'\n");
printf("For deleting use 'delete' \n");
printf("To end the session use 'bye' \n");
Queue Example: Contd.
while (strcmp(command,"bye")!=0){
scanf("%s",command);
if(strcmp(command,"add")==0) {
scanf("%s",[Link]);
if (IsFull(&A))
printf("No more insertion please \n");
else {
AddQ(&A,ob);
printf("Name inserted %s \n",[Link]);
}
}
Queue Example: Contd.
if (strcmp(command,"delete")==0) {
if (IsEmpty(&A))
printf("Queue is empty \n");
else {
ob=DeleteQ(&A);
printf("Name deleted %s \n",[Link]);
}
}
} /* End of while */
printf("End session \n");
}