Professional Documents
Culture Documents
ADS Unit III 2
ADS Unit III 2
ADS Unit III 2
1. Pointers in C Programming
Each memory cell (or Byte) in the computer is associated with a unique number called an address that can be used to
access that location. The picture below represents several bytes of a computer's memory. In the picture, addresses FFD1
thru FFDD are shown.
Memory
cell
F F F F F F F F F F F F F
F F F F F F F F F F F F F
D D D D D D D D D D D D D Address
1 2 3 4 5 6 7 8 9 A B C D
Whenever a variable is defined in a program, somewhere in the memory sufficient numbers of memory cell (byte) are
assigned to it to store the value of the variable. During the lifetime of the variable, the address is not changed but the
value may change. Consider the statement
int max = 456;
Let us assume that addresses of two bytes (since data type of max is int) of memory assigned to max be FFD3 and
FFD4.
FFD3 Address
Note: the data type of all pointer variables is fix (as is stored address and address is an integer value) but they points to
different data type. A pointer is definitely NOT an integer.
void main()
{
int *ip;
float *fp;
double *dp;
printf("ip=%d\tfp=%d\tdp=%d\n",sizeof(ip),sizeof(fp),sizeof(dp));
By Dr. M. M. Raghuwanshi, YCCE,Nagpur
Notes On Algorithms and Data Structures
Output:
ip=4 fp=4 dp=4
Note: To differentiate data and address we are using hex numbers to represent address and decimal numbers to represent
data.
1.2 Declaration
A pointer is a derived data type in C. Pointer must be declared before it is use. Declarations begins with data type
followed by indirection or dereference operator (*) followed by pointer variable name.
Syntax:
Data_type * pointer_variable;
The reason for associating data type to pointer is to know to what type of data it points to.
Example:
int *ip;
Here pointer ip points to integer data. The dereference operator looks up the value that exists at an address. Thus,
“pointer variable” really means “variable of a pointer type”.
The pointer itself is not of that type, it is of type pointer to that type. A given pointer only points to one particular
type, not to all possible types.
In pointer declaration, each pointer variable must be prefix by dereference operator
int *ip, *iq, *ir;
float *fa, *fb;
The convention is to place the * closer to pointer variable rather than the data type.
int* ip;
is same as
int *ip;
Also declaration
int* ip, a, b;
does not mean that ip, a and b are pointer variables rather its actual meaning is ip is pointer variable and a & b are
non-pointer variables (int *ip, a, b).
Compiler always associate the * with pointer variable rather then data type thus allowing us to declare pointer variables
and non-pointer variables in a single declaration.
int *ip, a, x, *iq;
in above declaration ip & iq are pointer variables and a & b are non-pointer variables.
float *fp;
The addresses shown in output for in ip and fp are some random (garbage) addresses.
When a pointer is declared but not initialized to any address it always contains some random address. It is necessary that
pointer must point to some meaningful memory location prior to its use. The pointer when initialized is said to reference
another variable, or to contain of a memory location. Allocating a pointer and allocating a pointee for it to point to be two
separate steps.
Note: Don’t try to assign manually some integer value to pointer as address is an integer value. It is always better to use
some mechanism to get an address of a memory location.
There are two ways to get address of memory location
1. By using address operator (&) to get the address of a variable
2. By requesting operating system to get a block of memory
}
Output:
&x=FFF4 x=55
&y=FFF0 y=34.78
Pointer variable can be initialised by using address of variable which is already declared.
void main()
{
int x=55;
float y= 34.78;
int *ip;
float *fp;
It may be observed that the hexadecimal addresses shown in output are in decreasing order, supporting the fact that all
automatic variables are created in the program’s stack area and the stack always grows from a higher address to lower
one.
Pointers of different types are not the same. There are no implicit conversions from one to the other. We must associate a
pointer to a particular data type. Let us consider following code
1: int *ip;
2: float x=12.78;
3: ip=&x;
At the time of compilation this code gives an error in line no 3 that says the compiler can not convert (float *) to
(int *). Here code is trying to coerce ip to point to some float data but ip is a pointer to integer data. Basically ip
is a pointer variable hence it can take any address but in real sense, “pointer variable” is a “variable of a pointer type” thus
implicit assignment of address of data type other than data type of pointer results into error. One can use cast operator for
explicit assignment.
Example: ip=(int *)&x.
C is not too fussy about assigning values of different type (not strongly type checked).
calloc Allocates space for an array of elements initializes them to zero and
returns a pointer to the memory
free Frees previously allocated space
realloc Modifies the size of previously allocated space.
A block of memory may be allocated using the function malloc. It takes the following form:
#include <stdlib.h>
The malloc function reserves a block of memory of specified size and returns a pointer of type void. This means that
we can assign it to any type of pointer. The malloc() doesn't care how the memory allocated will be used, malloc()
just returns a pointer to a series of bytes. One can't do anything with a void pointer except acknowledge its existence
until we convert (type cast) it to another variable type.
C has the ability to convert one type of variable to another type by using cast operator. The syntax is simple, put the
variable type you want to convert to inside parentheses.
A size is an unsigned integer value. C has a sizeof operator, which computes the size, in bytes, of a variable or data
type. It is advisable to use sizeof operator to specify the size of variable or data type because size of variable and data
type is compiler and machine dependent.
#include<stdio.h>
#include<stdlib.h>
void main()
{
int *ip;
float *fp, *fq;
ip=(int *)malloc(sizeof(int));
fp=(float *)malloc(sizeof(float));
fq=(float *)malloc(8));
printf("sizeof(ip):%d\tsizeof(*ip):%d\n",sizeof(ip),sizeof(*ip));
printf("sizeof(fp):%d\tsizeof(*fp):%d\n",sizeof(fp),sizeof(*fp));
printf("sizeof(fq):%d\tsizeof(*fq):%d\n",sizeof(fq),sizeof(*fq));
}
Output:
sizeof(ip):2 sizeof(*ip):2
sizeof(fp):2 sizeof(*fp):4
sizeof(fq):2 sizeof(*fq):4
The cast operators (int *) or (float *) give integer or float pointer to memory. The size of a pointer is how many
bytes it takes to store the address, not the size of the memory block the pointer is pointing to. Hence size of fp and fq is
2 bytes and size of memory block pointer by fp and fq is 4 bytes even though the block pointed by fq is of 8 bytes.
According to the conceptual view the program instructions and global & static variables are kept in a permanent storage
area and local area variables are stored in stacks. The memory space that is located between these two regions is available
for dynamic allocation during the execution of the program. The free memory region is called the heap.
#include<stdio.h>
#include<stdlib.h>
int x;
By Dr. M. M. Raghuwanshi, YCCE,Nagpur
Notes On Algorithms and Data Structures
void main()
{
int a;
int *ip;
ip=(int *)malloc(sizeof(int));
Output:
global: &x :00AA
pointer: ip:0586
local: &a :FFF4
0000
Program
Instruction
Permanent Data like
(Data
global and static
Segment)
variables
Heap
Stack
FFFF
The size of heap keeps changing when program is executed due to creation and death of variables that are local for
functions and blocks. Therefore, it is possible to encounter memory overflow during dynamic allocation process. In such
situations, the memory allocation functions mentioned above will return a null pointer. A null pointer points nowhere
hence it is not a pointer one can use. Therefore, whenever malloc is used it is vital to check the returned pointer before
using it.
Compile time storage of a variable is allocated and released by the system in accordance with its storage class. With the
dynamic runtime allocation, it is a responsibility of programmer to release the space when it is not required. The release of
storage space becomes important when the storage is limited. When block of memory is no longer needed and also there is
no intension to reuse that block, then such block may be released for future use. Dynamically allocated memory is de-
allocated with the free function. The syntax of free function is
By Dr. M. M. Raghuwanshi, YCCE,Nagpur
Notes On Algorithms and Data Structures
#include<stdio.h>
#include<stdlib.h>
void main()
{
int *ip = (int *)malloc(sizeof(int));
if(ip == NULL)
{
printf("ERROR: out of memory\n");
exit(1);
}
*ip=678;
printf("*ip:%d\n", *ip);
free(ip);
}
Output:
ip:0598 *ip:678
Memory allocated with malloc lasts as long as programmer wants it to. It does not disappear automatically when a
function ends.
ip = &a;
iq = ip;
Statement iq = ip do pointer assignment. After pointer assignment, the two pointers are said to be "sharing" the
pointee. That two or more entities can cooperatively share a single memory structure is a key advantage of pointers.
Sharing can be used to provide efficient communication between parts of a program.
One can use pointers with the assignment operators if the following conditions are met:
The left-hand operand is a pointer and the right-hand operand is a null pointer constant.
One operand is a pointer to an object or incomplete type; the other is a pointer to void (whether qualified or not).
By Dr. M. M. Raghuwanshi, YCCE,Nagpur
Notes On Algorithms and Data Structures
Both of the operands are pointers to compatible types (whether qualified or not).
In the last two cases, the type pointed to by the left-hand side must have at least the same qualifiers as the type pointed to
by the right-hand side (possibly more).
#include<stdio.h>
void main()
{
int a=56, *ip=&a, b=6;
*ip=*ip + 5;
printf("value of 'a' after addition:%d\n", a);
ip= &b;
*ip=7 * *ip;
printf("value of 'b' after multiplication:%d\n", b);
}
Output:
value of 'a' after addition:61
value of 'b' after multiplication:42
A single pointer variable can be used to point different variables or memory locations. Binary operator * is used for
multiplication and unary operator * is used for indirection. Indirection allows the contents of a variable to be accessed and
manipulated without using the name of the variable.
Note: A dereference operation on an un-initialized pointer gives a serious runtime error. Each pointer must be assigned a
pointee before it can support dereference operations.
Like other variables, pointer variables can be used in arithmetic or logical expressions.
#include<stdio.h>
void main()
{
int a=5, b=7, *ip1=&a, *ip2=&b;
int y, sum, z;
y=*ip1**ip2;
sum=sum+*ip1;
z= 5* - *ip2 / *ip1;
printf("y = %d\t sum = %d\t z = %d\n", y, sum, z);
printf(" a<b = %d\n", *ip1 < *ip2);
}
Output:
y = 35 sum = 5 z = -7
a<b = 1
Multiple dereference operation starts at the pointer and follows its address link to access its pointee.
#include<stdio.h>
By Dr. M. M. Raghuwanshi, YCCE,Nagpur
Notes On Algorithms and Data Structures
void main()
{
int a=56;
int *pa = &a;
int **pb = &pa;
int ***pc = &pb;
2. Ordered List
The data objects linear lists, stacks, queues, polynomials, and matrices are ordered lists. Polynomials are ordered by
exponent while matrices are ordered by rows and columns. There are two types of representation for ordered lists.
1. Sequential representation
2. Linked representation
In Sequential representation sequential mapping can be used to represent ordered lists. Sequential representation has the
property that successive nodes of data object are stored at a fixed distance apart. Sequential scheme is supported by static
allocation strategy. Arrays are probably the most common data structure used to represent sequential scheme. The linear
relationship between the data elements of an array is reflected by the physical position of the data in memory, not by any
information contained in the data element themselves. This makes it easy to compute the address of an element in an
array. In most languages, arrays are convenient to declare. The advantages of sequential representation are
1. Easy to implement (e.g. create & Traverse)
2. Easy to access any element in list (random access)
and disadvantages are
1. Wastage of memory space
2. There is lot of data movements in order to perform insertion, deletion, sorting or merging operations.
3. Merging require an additional space
Also when problem demands for several ordered lists (like multiple stacks & queues) of varying sizes, sequential
representation again proved to be inadequate, by storing each list in a different array of maximum size. Storage may be
wasted.
Linked representation is an alternate representation for ordered lists that will overcome the disadvantages of sequential
representation. Unlike a sequential representation where successive elements of a list are located at fix distance apart, in a
linked representation these elements may be placed anywhere in a memory. Another way of saying this is that in
sequential representation order of element is same as is ordered list, while in linked representation these two sequences
need not be the same. In linked list a list in stored in memory have each element in list containing a field called link or
pointer, which contain the address of next element in the list
index 0 1 2 3 4
element 3 6 8 11 15
Here the entire array is allocated as one block of memory. Each element in the list gets its own space in the array. Any
element can be accessed directly using its index. The address of any element is computed by using fast address arithmetic.
Now if we want to store an ordered list in an array using linked representation, following information is required
1. Which is the first element? (or marking of the first element)
2. Current element (i.e. element in processing) has information about next element
3. Which is the last element? (or marking of the last element)
The elements of an ordered list are stored in the array at any place and index of an array does not indicate their order in
the list. Index only signifies position of element in an array. An extra field (i.e. link) must be associated with each element
to keep information about next element. The NULL value in link field of an element indicated that this element is the last
element in an ordered list. Also the information about first element is stored in some variable.
first
index 0 1 2 3 4
element 6 15 3 8 11
link 3 N 0 4 1
In this representation the link field of current element always stores the index of next element in an ordered list. This
linked representation has their own strengths and weaknesses, but they happened to be strong where sequential
representation is weak.
Let us insert value 9 in the given ordered list. The new ordered list is [3, 6, 8, 9, 11, 13]. To implement this new ordered
list in linked representation; append 9 in the array and link field of element 9 will take value from link field of element 8
(i.e. previous element to element 9) & link field of element 8 will be set to index of element 9.
first
index 0 1 2 3 4 5
element 6 15 3 8 11 9
link 3 N 0 5 1 4
Just by setting the two link fields and without moving single element of the list it is easy to insert new element in the
ordered list that is represented in linked form. Similarly it is easy to delete any element from the ordered list too.
3. Linked Lists
Linked lists are among the simplest and most common data structures. They are linear data structure. They can be used to
implement several other common abstract data types, including ordered list, stacks, queues, polynomial etc.
A linked list allocates space for each element separately in its own block of memory called a "linked list element" or
"node" when necessary. The list gets is overall structure by using pointers to connect all its nodes together like the links in
a chain. Each node contains two fields: "data" field to store an element of a list and “link" field is a pointer used to link
one node to another node. So link is always pointer to node.
15 20
struct node
{
By Dr. M. M. Raghuwanshi, YCCE,Nagpur
Notes On Algorithms and Data Structures
int data;
struct node *link;
};
Variable link is a pointer to the same structure in which it is declared leads to self-referencing pointer (recursively defined
struct). By using dynamic memory allocation (like a call to malloc()), memory from heap is allocated to each node in a
linked list.
first=(struct node*)malloc(sizeof(struct node));
The start of a linked list is stored in a "head" or “first” 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 a linked list
has its link field set to NULL to mark the end of a list.
second 8
second
first
5 8 N
first 5 8 N
Note: Visiting and Processing data in each node of a list at least once is known as traversal of the list. In linked list
information about the first node is available and also the last node is marked by NULL in the link field. Hence traversal
starts from the first node, it processes data in the first node and then it reaches to the second node by using link field of
first node. In this way after processing a current node pointer moves to the next node and this movement continues till one
reaches to the last node.
{
int data;
struct node *link;
};
void main()
{
struct node *first, *second, *temp;
/* allocate memory to first node and put some data in that node */
first=(struct node*)malloc(sizeof(struct node));
first->data=5;
/* allocate memory to second node and put some data in that node */
second=(struct node*)malloc(sizeof(struct node));
second->data=8;
void main()
{
struct node *first, *second, *third, *temp;
/* allocate memory to first node and put some data in that node */
first=(struct node*)malloc(sizeof(struct node));
first->data=5;
/* allocate memory to second node and put some data in that node */
second=(struct node*)malloc(sizeof(struct node));
second->data=8;
/* allocate memory to third node and put some data in that node */
By Dr. M. M. Raghuwanshi, YCCE,Nagpur
Notes On Algorithms and Data Structures
void main()
{
struct node *head, *curr, *next, *temp;
int i, n;
The typical run of above program to create a singly linked list of n (=3)three nodes is shown below. Variable head always
holds the address of first node in the list. Variable curr always keeps address of a last node added (tail pointer) in the list.
Since new node is always added after the last node in the list hence one always need address of last node. Variable next
gets address of newly created node.
head 5
3. curr always points to a node that is appended (added at the end) in the list: curr=head;
head 5
curr
head next
5 8
curr
head 5 next
8 2
curr
6. To mark the end of the list, the link field of last node is set to NULL: curr->link=NULL;
head 5 next
8 2 N
curr
head 5 8 2 N
Note: The best way to design and think about code of linked list is to use a drawing to see how the pointer operations are
setting up memory. Take this opportunity to practice looking at memory drawings and using them to think about pointer
intensive code. One will be able to understand many of the later, more complex functions only by making memory
drawings like this on your own.
There are two ways to write function to create singly linked list (SLL) of n nodes.
a. Keeping Head Pointer (info about first node) local to calling function and use parameter passing technique
struct node * create(int n)
{
void create(int n)
{
int i;
By Dr. M. M. Raghuwanshi, YCCE,Nagpur
Notes On Algorithms and Data Structures
if(n <= 0 )
head=NULL;
else
{
curr=(struct node*)malloc(sizeof(struct node));
printf("enter data for 1 node:");
scanf("%d", &curr->data);
head=curr;
for(i=1; i<n; i++)
{ /* --Create rest of the n-1 nodes-- */
next=(struct node*)malloc(sizeof(struct node));
printf("enter data for %d node:",i+1);
scanf("%d", &next->data);
curr->link=next;
curr=next;
}
curr->link=NULL;
}
}
The time complexity of creation of singly linked list of n nodes is O(n). Same is also applicable to the traversal.
head
Is NULL Is not NULL
Iteratively traverse in the list till you reach the end of the list
Print the data of the current node
Move to next node by using address stored in link field of
current node
{
printf("%d\n", curr->data);
curr=curr->link;
}
}
}
The typical run of above program, traverse in the singly linked list of n (=3) is shown below. Traversal start from the first
node, it goes through all the nodes and end after processing the last node. Variable temp keeps the track of node in a
migration process.
head 5 8 2 N
curr
3. Enter in the while loop as temp is not NULL and process the node pointed by temp (i.e. first node)
printf("%d\n", curr ->data);
move to second node by using link field of first node
curr = curr ->link;
head 5 8 2 N
curr
4. While loop continue as temp is not NULL and process the node pointed by temp (i.e. second node)
printf("%d\n", curr ->data);
move to third node by using link field of second node
curr = curr ->link;
head 5 8 2 N
curr
5. While loop continue as temp is not NULL and process the node pointed by temp (i.e. third node)
printf("%d\n", curr ->data);
move to next node by using link field of third node
curr = curr ->link;
head 5 8 2 N
curr NULL
6. Since curr is now NULL hence while loop get terminated after processing all the three nodes in the SLL
Traversal function with Head Pointer (info about first node) as global variable is shown below
void traverse()
{
struct node *curr;
Exercise:
1. Write a function to count number of nodes in a singly linked list.
Solution:
int count()
{
int c=0;
struct node *temp=head;
while(temp != NULL)
{
c=c+1;
temp=temp->link;
}
return(c);
}
2. Write a recursive function to count number of nodes in a singly linked list.
Solution:
int count(struct node *temp)
{
if (temp == NULL)
return(0);
else
return(1+count(temp->link));
}
3. Suppose list is a linked list in memory consisting of numerical values. Write a function find average of the values
in the list.
Solution:
float Average()
{
struct node *temp;
int sum=0, c=0;
temp=head;
while(temp != NULL)
By Dr. M. M. Raghuwanshi, YCCE,Nagpur
Notes On Algorithms and Data Structures
{
c=c+1;
sum=sum + temp->data;
temp=temp->link;
}
return((float)sum/c);
}
a. Finding the product PROD of the element.
Hint: initialize prod=1 and in loop prod = prod * first->data
4. Suppose list is a linked list in memory consisting of numerical values. Write a function to find Maximum value in
the list.
Solution:
int Max()
{
struct node *temp=head;
int big;
big=head->data;
temp=head->link;
while(temp != NULL)
{
if (temp->data > big)
big=temp->data;
temp=temp->link;
}
return(big);
}
if (list == NULL)
return NULL;
else
{
temp=(struct node *)malloc(sizeof(struct node));
temp->data=list->data;
temp->link=copy(list->link);
return temp;
}
}
6. Write a function to invert links of singly linked list.
Solution:
Given SLL with initial position of curr and prev
curr
head 5 8 2 9 N
prev NULL
Enter into while loop and process first node and set link field of first node to NULL to make is last node
head N 5 8 2 9 N
In loop, process second node, let link field of second node takes the address of first node
head N 5 8 2 9 N
In loop, process third node, let link field of third node takes the address of second node
prev curr
head N 5 8 2 9 N
next NULL
In loop, process forth node , let link field of forth node takes the address of third node
prev
head N 5 8 2 9
curr, next NULL
N 5 8 2 9 head
curr=head ;
prev=NULL;
while(curr != NULL)
{
next=curr->link;
curr->link=prev;
prev=curr;
curr=next;
By Dr. M. M. Raghuwanshi, YCCE,Nagpur
Notes On Algorithms and Data Structures
}
head = prev;
}
Now pointer to (m-1)th node is curr and newly created node temp will be inserted after curr so that it becomes a mth node
in the list. The link field of temp will take address of the mth node (available in link field of curr) of the original list
temp->link=curr->link;
and link field of (m-1)th node (i.e. curr) will take address of new node temp.
curr->link=temp;
Figure shows typical run of, Insert node at 3rd position in a link list of 3.
temp 4
Traverse up to 2nd node, starting from head node
head 5 8 2 N
curr
temp 4
Insert node temp in between 2nd and 3rd node
head 5 8 2 N
curr
temp 4
Figure. Typical run of, Insert node at 3rd position in a link list of 3
Figure shows typical run of, Insert node at the end of a link list of 3 nodes.
Insert node at end of the a list
head
5 8 2 N
temp 4
Traverse up to last node, starting from head
head 5 8 2 N
curr temp 4
Mark temp as the last node and connect it to last node of original list
head 5 8 2 N
curr
temp 4 N
Figure. Typical run of, Insert node at the end of a link list of 3 nodes
In the following program cases for insert node in the middle and at the end of the list are combined together. Also if value
of pos is greater than the actual number of nodes in the list (i.e. m > n) then new node temp is inserted at the end of the
list.
Since insertion of a node in SLL does not require any movement (or shifting) of nodes. It only does traversing up to the
appropriate position or node in a list. The best case is, insert node in an empty list or insert node at first position in a list
that takes O(1) time. The worst case is, insert node at the end of a list that needs traversal from the first node upto the last
node, hence worst case time complexity for insertion operation on SLL is O(n).
Exercise:
1. Singly linked list of n nodes is given. Write a procedure to move first node to end of the list.
Solution:
void Firsttolast()
{
struct node *temp, *fnode;
fnode= head;
temp=fnode->link;
head=temp;
while (temp->link !=NULL)
temp=temp->link;
temp->link=fnode;
fnode->link=NULL;
}
2. A singly linked list stores integer data in ascending order. P is a pointer to node, which stores data 20. Insert a
node contain data 18 into singly linked list such that it will be sorted after insertion.
p
15 20
Code:
temp=(struct node *) malloc(sizeof(struct node));
temp->data = p->data;
temp->link = p->link;
p->data = 18;
p->link = temp;
3. Create linked list of n node such that the elements in list are arranged in ascending order.
Solution:
void InsSorted( int val)
{
struct node *curr, *temp, *prev;
{
prev->link=temp;
temp->link=NULL;
}
else /* insert in a middle */
{
prev->link=temp;
temp->link=curr;
}
}
}
4. Let x is a pointer to some arbitrary node in the singly linked list. Write a function to insert node after x in the list
head 5 8 2 N
Case 3: Delete some node in the middle or at the end of a linked list
In order to delete node at mth position in a link list of n nodes (n ≥ m), starting from first node traverse up to (m-1)th node
in the list.
curr=head;
c=1;
th
/* traverse up to the (m-1) node */
while (c < pos-1)
{
c++;
curr=curr->link;
}
Now pointer to (m-1)th node is curr. Let the link field of (m-1)th node will take address of (m+1)th node, which stored in
link field of mth node (i.e in the link field of temp).
temp=curr->link;
curr->link=temp->link;
free (temp);
If temp is a last node in the list then, then link field of curr is set to NULL and curr becomes the last node. Figure 3.6
shows typical run for deletion of 3rd node in a link list of 4 nodes.
head
5 8 2 4 N
curr temp
Figure 3.6. Typical run for deletion of 3rd node in a link list of 4 nodes
In the following program if value of pos is greater than the actual number of nodes in the list (i.e. m > n) then program
simply prints a message "ERROR: No node on this position\n".
Code: To delete node from any position in a singly linked list
void del(unsigned int pos)
{
struct node *temp, *curr;
int c=0;
c=1;
curr=head;
while (c < pos-1 && curr->link !=NULL)
{
c++;
curr=curr->link;
}
if (curr->link == NULL)
printf("ERROR: No node on this position\n");
else /* --delete node in between or last node-- */
{
temp=curr->link;
curr->link=temp->link;
free (temp);
}
}
}
}
Since deletion of a node from SLL does not require any movement (or shifting) of nodes. It only does traversing up to the
appropriate position or node in a list. The best case is, delete node from an empty list or delete node at first position in a
list that takes O(1) time. The worst case is, delete last node of a list that needs traversal from first node upto last node,
hence worst-case time complexity for deletion operation on SLL is O(n).
The worst-case time complexity of insertion or deletion operation on singly linked list or array is O(n). The most
important advantage of linked list over array is these operations do not require any movement of data in a list.
Exercise:
1. Write a program to delete the node with the largest data value from a link list.
Solution:
void DelBig()
{
struct node *big, *bprev, *curr, *prev,*temp;
head=temp->link;
free(big);
}
else /* --delete node in between-- */
{
bprev->link=big->link;
free(big);
}
}
}
2. Write a function to delete the node N from a singly linked list. This delete function should call another function
that finds the location of node N and its preceding node.
3. Write an algorithm to implement a linked list and perform insertion and deletion in following way:
i. Insert element at the beginning of a list
ii. Delete last element from the list
4. Write a function which will delete and display the biggest and smallest from the given linked list.
5. Let p be a pointer to the first node in a singly linked list and x an arbitrary node in the list. Write a function to
delete a node x from the list.
6. Delete the node pointed by curr without using any extra pointer variable and provided the address of first node is
not given.
curr
5 8
Code:
while(curr-link!=null)
{
curr->data=curr->link->data;
curr=curr-link;
}
free(curr)
In order to merge them first traverse in the first list and reach to the last node
curr
head
3 5 7 9 N
1
head2
4 6 8 N
Now set link field of last node of first list to the first node of second list
curr
head
3 5 7 9
1
head2
4 6 8 N
if (head == NULL)
head = head2;
else
{
if (head2 != NULL)
{
curr = head;
while(curr->link != NULL)
curr = curr->link;
curr->link = head2;
}
}
}
Concatenation of two lists needs\only traversing in the first list. If first list has n nodes then time complexity of
concatenation operation on SLL is O(n). Unlike array there is no movement of data in SLL for concatenation operation.
Any merge operation on SLL does not require any movement of data that is the major advantage of SLL over array.
Exercise:
1. Let list1 & list2 are two singly linked lists having data in ascending order. Write a function to merge them such
that resultant list will contain data in ascending order.
Solution:
struct node * mergeSortL(struct node *list1, struct node *list2)
{
struct node *p1, *p2, *mlist,*pm;
if (list1 == NULL)
return(list2);
else
{
if (list2 == NULL)
return(list1);
else
{
p1=list1;
p2=list2;
/* --create head node-- */
mlist=(struct node*)malloc(sizeof(struct node));
pm=mlist;
while(p1 != NULL && p2 != NULL)
By Dr. M. M. Raghuwanshi, YCCE,Nagpur
Notes On Algorithms and Data Structures
{
if(p1->data < p2->data)
{
pm->link=p1;
pm=p1;
p1=p1->link;
}
else
{
if(p1->data == p2->data)
p1=p1->link;
pm->link=p2;
pm=p2;
p2=p2->link;
}
}
if(p1 == NULL)
pm->link=p2;
else
pm->link=p1;
Note: In above function merged list (mlist) contains nodes from list1 and list2 that results in disturbing the sequence of
nodes in both the lists. Following function merge the two sorted lists without disturbing the original lists. It creates
sequence of nodes and copy data in them either from list1 or list2.
if (list1 == NULL)
return(list2);
else
{
if (list2 == NULL)
return(list1);
else
{
p1=list1; /* --pointer moving in list1-- */
p2=list2; /* --pointer moving in list2-- */
/* --create head node-- */
mlist=(struct node*)malloc(sizeof(struct node));
pm=mlist; /* --pointer moving in merged list-- */
while(p1 != NULL && p2 != NULL)
{
if(p1->data < p2->data)
By Dr. M. M. Raghuwanshi, YCCE,Nagpur
Notes On Algorithms and Data Structures
{
temp=(struct node *)malloc(sizeof(struct node));
temp->data=p1->data;
pm->link=temp;
pm=temp;
p1=p1->link;
}
else
{
if(p1->data == p2->data)
p1=p1->link;
temp=(struct node *)malloc(sizeof(struct node));
temp->data=p2->data;
pm->link=temp;
pm=temp;
p2=p2->link;
}
}
while(p2 != NULL)
{
temp=(struct node *)malloc(sizeof(struct node));
temp->data=p2->data;
pm->link=temp;
pm=temp;
p2=p2->link;
}
while(p1 != NULL)
{
temp=(struct node *)malloc(sizeof(struct node));
temp->data=p1->data;
pm->link=temp;
pm=temp;
p1=p1->link;
}
pm->link=NULL; /* --mark it as a last node-- */
/* --delete head node-- */
pm=mlist;
mlist=mlist->link;
free(pm);
return(mlist);
}
}
}
5. Let list1 & list2 are two singly linked lists. Write function to create a third linked list which contains elements not
common in both the lists.
head2
4 6 N
Code: To split a singly linked list into two list each containing n/2 nodes
struct node * split()
{
int n,c;
struct node *curr, *prev;
n=count(head);
if(n < 2)
return NULL;
else
{
curr=head;
c=1;
while( c < (n/2+n%2)) /* (n+1)/2 */
{
prev=curr;
curr=curr->link;
c++;
}
prev->link=NULL;
return(curr);
}
}
Split operation on SLL needs traversal in the list of n nodes. The time complexity of split operation is O(n). Again split
operation does not require any movement of data elements in a list.
Exercise:
1. Write a function to split a given linked list of integers into two lists l 1 & l2 where l1 contain nodes having odd
values and l2 contain nodes having even values.
Solution:
void splitEO(struct node *orglist, struct node **list1,
struct node **list2)
{
struct node *temp, *p1=NULL, *p2=NULL;
*list1=NULL;
*list2=NULL;
while(orglist != NULL)
{
temp=(struct node *)malloc(sizeof(struct node));
temp->data=orglist->data;
if((orglist->data % 2) == 0)
{
if(*list1 == NULL)
{ /* -- node is first node in list1-- */
*list1=temp;
p1=temp;
}
else
{
p1->link=temp;
p1=temp;
}
}
else
{ /* -- node is first node in list2-- */
if(*list2 == NULL)
{
*list2=temp;
p2=temp;
}
else
{
p2->link=temp;
p2=temp;
}
}
orglist=orglist->link;
}
if(p1 != NULL)
p1->link=NULL;
if(p2 != NULL)
p2->link=NULL;
}
head 5 8 2
With a circular list, a pointer to the last node gives easy access also to the first node, by following one link. Thus, in
applications that require access to both ends of a list (e.g., in the implementation of a queue), a circular structure allows
one to handle the structure by a single pointer, instead of two. Circular linked list offer benefit from the ability to traverse
the full list by starting from any given node. Where as in SLL, traversal of full list is only possible if traversal starts from
first node only.
Figure shows flow chart depicts the creation of circular singly linked list.
n
== 0 >0
Figure. Flow chart depicts the creation of circular singly linked list.
void createCLL(int n)
{
struct node *curr, *next, *temp;
int i;
if(n<=0)
head=NULL;
else
{ /* --create first (head) node-- */
head=(struct node*)malloc(sizeof(struct node));
printf("Enter data for 1 node:");
scanf("%d",&head->data);
curr=head;
for(i=1; i<n; i++)
{ /* --Create rest of the n-1 nodes-- */
next=(struct node*)malloc(sizeof(struct node));
printf("enter data for %d node:",i+1);
scanf("%d", &next->data);
curr->link=next;
curr=next;
}
curr->link=head;
}
}
Create a second node, put data into it and let link field of first node takes the address of second node
head next
5 8
curr
Create a third node, put data into it and let link field of second node takes the address of third node
head next
5 8 2
curr
In order to make SLL circular SLL, let the link field of last node takes the address of first node
head next
5 8 2
curr
void traverseCLL()
{
struct node *temp;
{
temp=head;
do
{
printf("%d\n", temp->data);
temp=temp->link;
} while(temp != head)
}
}
void main()
{
int n,ch;
clrscr();
while(1)
{
printf("CIRCULAR SINGLY LINLKED LIST\n");
printf("1.Create\n2.Traverse\n3.Quit\n");
printf("Enter your choice:");
scanf("%d",&ch);
switch(ch)
{
case 1:
printf("Enter No of nodes:");
scanf("%d",&n);
createCLL(n);
break;
case 2:
if (head == NULL)
printf("List is EMPTY\n");
else
{
printf("Traversing in The List:\n");
traverseCLL();
}
getch();
break;
case 3:
return;
default:printf("Wrong choice:re-enter\n");
}
}
}
The time complexity of operations on circular linked list is same as SLL. The only advantage is visit to previous node
from current node is possible in Circular singly linked list
Exercise:
1. Write a function to concatenate two Circular singly linked lists.
Solution:
struct node * concatCLL(struct node *list1, struct node *list2)
{
struct node *temp;
By Dr. M. M. Raghuwanshi, YCCE,Nagpur
Notes On Algorithms and Data Structures
if (list1 == NULL)
return(list2);
else
{
if (list2 != NULL)
{
temp=list1;
while(temp->link != list1)
temp=temp->link;
temp->link=list2;
temp=list2;
while(temp->link !=list2)
temp=temp->link;
temp->link=list1;
}
return(list1);
}
}
2. Let p is a pointer to some arbitrary node in Circular singly linked list. Write a code to reach its previous node.
Code:
temp=p;
while (temp->link != p)
temp=temp->link;
3. There are two circular singly linked list available A and B. Write a function to generate third circular linked list
called as C which is nothing but addition of nodes A and B. if one of A and B get exhausted the remaining
elements of other are to copied.
4. Write a function to reverse the direction of links in a circular singly linked list.
Solution:
void invertCLL()
{
struct node * curr, * prev, * next ;
if (head != NULL)
{
curr=head ;
prev=NULL;
do
{
next=curr->link;
curr->link=prev;
prev=curr;
curr=next;
}while(curr != head);
head->link=prev;
head = prev;
}
}
5. Write a function to search a “Key” in a circular linked list. If key is found the function should return a pointer
node when match is found else should return null pointer.
5 8 2 head
Ans: Insertion takes place at head whereas deletion takes place from headlink
5. Linked Stack
A stack is an ordered list in which all insertions and deletions are made at one end,
called the top. This makes stack a single ended data structure where element inserted
last will be deleted first i.e. LIFO (Last In First Out). LIFO makes it is possible to
top remove items from a stack in reverse order of their insertion.
A stack is characterized by two fundamental operations, called push and pop. The
push operation adds a new item at the top of a stack. The pop operation removes an
item from the top of a stack.
Linked stack is an implementation stack using a linked list. In linked stack an
element is a node that contains information about element and the link field to
connect nodes in a stack to form a linked list. Top is a pointer that always points to
the node recently added to a stack (last node added). If a stack is empty then top is NULL.
struct node
{
int data;
struct node *link;
};
struct node *top=NULL;
Initially, stack is empty hence top is NULL.
Note: The stack was first proposed in 1946, in the computer design of Alan M. Turing (who used the terms "bury" and
"unbury") as a means of calling and returning from subroutines.
top 9
top 8 top 8
8
topNULL top 5 N 5 N 5 N 5 N
1. Initial
Stack 2. push (5) 3. push (8) 4. push (9) 5. pop
push operation: it adds a new node in a stack. The link field of this new node takes address of the node at the top and
then set top to this newly added node. If this new node is the first node to be added in a stack then set its link field to
NULL to mark the bottom of a stack (i.e. last node in linked list).
void push(int val)
{
struct node *temp;
Re-usability of code: push operation on Linked stack is a very special case of insertion operation in singly linked list.
Push operation in linked stack always insert a node at first position so as to comply the property LIFO. Hence push is
equivalent to the case insert node at first position in singly linked list.
pop operation: it removes a node from a stack. The node pointed by top is deleted from stack by making its previous
node to become the node on top of a stack. If there is single node in a stack, then deletion of this node makes stack empty
by setting top to NULL.
void pop()
{
struct node *temp;
if(top == NULL)
printf("STACK is EMPTY\n");
else
{
temp=top;
top=top->link;
printf("Poped Value is:%d\n", temp->data);
free(temp);
}
}
Re-usability of code: Pop operation on Linked stack is a very special case of deletion operation in a singly linked list.
Pop operation on linked stack always delete node at first position (if stack is not empty) so as to comply the property
LIFO. Hence pop is equivalent to the case delete node from first position in the singly linked list.
Note: The result of an illegal attempt to pop an element from an empty stack is called underflow.
Traversal in linked stack: it is same as traversal in singly liked list. Traversal begins from the node at the top and goes
through all nodes and reaches to the bottom of a stack. Null in the link field of a node of a stack indicates the bottom of a
stack. If top is NULL then stack is empty.
void traverse()
{
struct node *temp;
As discussed above, push operation is a very special case of insertion operation (always insert node at first position) on
SLL while pop operation is a very special case of deletion operation (always delete node at first position) on SLL.
Insertion or deletion at first position in SLL does not need any traversal. Hence time complexity of push and pop
operation is O(1).
void main()
{
int ch,val;
clrscr();
while(1)
{
printf("Implementation of Linked Stack\n");
printf("1.Push\n2.Pop\n3.Traverse\n4.Quit\n");
printf("Enter your choice:");
scanf("%d",&ch);
switch(ch)
{
case 1:
printf("Enter data to be pushed:");
scanf("%d", &val);
push(val);
break;
case 2:
pop();
break;
case 3:
traverse();
break;
case 4: return;
default:printf("Wrong choice:re-enter\n");
}
}
}
Exercise:
1. Write a function that uses stack to determine if an input character string is of the form xCy, where x is a string
consisting of the letters ‘A’ and ‘B’ and where y is the reverse of x.
2. Consider a language that does not have arrays but does have stack as data type. That is one can declare
stack s;
and the push, pop, popandtest, and stacktop(return element at top but does not remove) are defined. Show how a
one-dimensional array can be implemented by using these operations on two stacks.
Note: First-in-first-out appears to be fairer than last-in-first-out. Queue is more difficult to implement than stack as
actions happen at both the ends.
6. Linked Queue
A queue is an ordered list in which all insertions take place at one end, the rear, while
all deletions take place at the other end, the front. This makes the queue a First-In-First-
Out (FIFO) data structure. In a FIFO data structure, the first item added to the queue
rear will be the first one to be removed
front A queue is characterized by two fundamental operations, called insertQ and deleteQ.
The insertQ operation adds a new item from the rear end while deleteQ operation
removes an item from the front end of a queue.
Linked queue is an implementation of queue using a linked list. The item of a linked
queue is a node that contains information about item and the link field is used to
connect nodes in a queue. front and rear are pointers. rear always points to the node recently added to a queue (last node
added) while front always points to the oldest node in a queue. In linked queue front always points to the first node in
linked list while rear points to the last node in the list if queue is not empty. If a queue is empty then rear and front are
NULL.
struct node
{
int data;
struct node *link;
};
struct node *front=NULL, *rear=NULL;
insertQ operation: it add a new node in a queue. Insertion takes place from the rear end. The link field of this new node
takes address of the node pointed by rear and then set rear to this newly added node. If this new node is the first node
added in a queue then rear and front both point to this node.
void insertQ(int val)
By Dr. M. M. Raghuwanshi, YCCE,Nagpur
Notes On Algorithms and Data Structures
{
struct node *temp;
Re-usability of code: insert operation on Linked queue is a very special case of insertion operation in a singly linked list.
Insert operation on linked queue always insert a node at the end of a queue so as to comply the property FIFO. Hence
insert in linked queue is equivalent to the case insert node at end in the singly linked list.
deleteQ operation: it removes a node from a queue. Deletion takes place from the front end. The node pointed by front is
deleted from a queue by making its next node to become the first node of a queue. If there is single node in a queue, then
deletion of this node makes queue empty by setting both rear and front to NULL. The result of an illegal attempt to
remove an element from an empty queue is called underflow. It occurs when front (as well as rear) becomes NULL.
void deleteQ()
{
struct node *temp;
if (front == NULL)
printf("Queue is Empty\n");
else
{
temp=front;
if(front == rear) /* -- only one node in Queue -- */
front=rear=NULL;
else
front=front->link;
printf("Value deleted:%d\n", temp->data);
free(temp);
}
}
Re-usability of code: delete operation on a Linked queue is a very special case of the deletion operation in a singly linked
list. DeleteQ operation on linked queue always delete node at first position (if queue is not empty) so as to comply the
property FIFO. Hence deleteQ is equivalent to the case delete node from first position in a singly linked list.
Traversal in linked queue: In non-empty queue fronts always points to first node where as rear points to the last node in
a linked queue. Hence in non-empty linked queue traversal begins from the node pointed by front and goes through all
nodes and reaches to the node pointed by rear.
front 5 9 6 8 rear
void traverseQ()
{
if (front == NULL)
By Dr. M. M. Raghuwanshi, YCCE,Nagpur
Notes On Algorithms and Data Structures
As discussed above, insert operation is a very special case of insertion operation (always insert node at the end) on SLL
while delete operation is a very special case of deletion operation (always delete node at first position) on SLL. If instead
of two pointers (front & rear) only single pointer is used to implement a linked queue then insertion operation has time
complexity O(n) and deletion operation takes O(1) time. Use of two pointers (front & rear) makes time complexity of both
the operations O(1).
void main()
{
int ch,val;
clrscr();
while(1)
{
printf("Implementation of Linked Queue\n");
printf("1.Insert\n2.Delete\n3.Traverse\n4.Quit\n");
printf("Enter your choice:");
scanf("%d",&ch);
switch(ch)
{
case 1:
printf("Enter data to be Inserted in Queue:");
scanf("%d", &val);
insertQ(val);
break;
case 2:
deleteQ();
break;
case 3:
traverseQ();
By Dr. M. M. Raghuwanshi, YCCE,Nagpur
Notes On Algorithms and Data Structures
break;
case 4: return;
default:printf("Wrong choice:re-enter\n");
}
}
}
Exercise:
1. What is circular queue? Implement it using circular linked list.
2. Write a function to delete an element from linked queue and insert it into linked stack.
3. Devise a representation for a list where insertions and deletion can be made at either end such a data structure is
called deque. Write a function for insertion and deletion in deque.
4. If p is a pointer to circularly linked list. Show how this list may be used as a queue. Write function to add and
delete elements in queue using p taking into consideration boundary condition when queue is empty.
5. Consider hypothetical data object x2, is a linear list with restriction that while addition to list may be at either end
but deletions can be made from one end only. Design a linked list representation for x 2. Write addition and
deletion functions for x2 specifying initial and boundary conditions for your representation.
6. Implement queue using stacks
7. How would you implement a queue of stacks? A stack of queues? A queue of queues? Write functions to
implement the appropriate operations for each of these data structures.
Let P(x) = 6.0x6 -7.5x4+8.0x+9.7 is a polynomial in variable x with degree 6 with 4 non-zero terms. P(x) is represented
using singly linked list as
poly 6.0 6 -7.5 4 8.0 1 9.7 0 N
if(nterm <= 0)
head=NULL;
else
By Dr. M. M. Raghuwanshi, YCCE,Nagpur
Notes On Algorithms and Data Structures
polyC pc
2. Exponent of term pointed by pa is greater than exponent of term pointed by pb hence add term pointed by
pa to resultant polynomial polyC. Move pointer pa to next term in polyA and let pc points to the last term
added to polyC.
polyC 6.0 6 pc
3. Exponent of term pointed by pb is greater than exponent of term pointed by pa hence add term pointed by
pb to resultant polynomial polyC. Move pointer pb to next term in polyB and let pc points to the last term
added to polyC.
4. Exponent of terms pointed by pa & pb are same hence also sum of their coefficients is non-zero. Add new
node in polyC that contains addition of coefficients and exponent. Move pointers pa & pb to next term in
polyA & polyB respectively and let pc points to last term added to polyC.
5. Exponent of term pointed by pb is greater than exponent of term pointed by pa hence add term pointed by
pb to resultant polynomial polyC. Move pointer pb to next term in polyB and let pc points to the last term
added to polyC.
2.3 2 pc
6. Now pb is NULL but pa is not NULL, it means there are un-processed terms in polyA where as polyB is
processed completely. Hence copy remaining terms of polyA to polyC.
pa pb NULL
7. Remove the extra head node from the resultant polynomial polyC.
if (polyA == NULL)
return(polyB);
else
{
if (polyB == NULL)
return(polyA);
else
{
pa=polyA;
pb=polyB;
/* --create head node-- */
polyC=(struct term*)malloc(sizeof(struct term));
pc=polyC;
while(pa != NULL && pb != NULL)
{
if(pa->expo > pb->expo)
{
temp=(struct term *)malloc(sizeof(struct term));
temp->coef=pa->coef;
temp->expo=pa->expo;
pc->link=temp;
pc=temp;
pa=pa->link;
}
else
{
if(pa->expo < pb->expo)
{
temp=(struct term *)malloc(sizeof(struct term));
temp->coef=pa->coef;
temp->expo=pa->expo;
pc->link=temp;
pc=temp;
pb=pb->link;
}
else
{
c=pa->coef+pb->coef;
if(c != 0)
{
temp=(struct term *)malloc(sizeof(struct term));
temp->coef=c;
temp->expo=pa->expo;
pc->link=temp;
pc=temp;
}
pa=pa->link;
pb=pb->link;
}
}
}
while(pa != NULL)
{
temp=(struct term *)malloc(sizeof(struct term));
temp->coef=pa->coef;
temp->expo=pa->expo;
pc->link=temp;
pc=temp;
pa=pa->link;
}
By Dr. M. M. Raghuwanshi, YCCE,Nagpur
Notes On Algorithms and Data Structures
while(pb != NULL)
{
temp=(struct term *)malloc(sizeof(struct term));
temp->coef=pb->coef;
temp->expo=pb->expo;
pc->link=temp;
pc=temp;
pb=pb->link;
}
pc->link=NULL; /* --mark it as a last node-- */
/* --delete head node-- */
pc=polyC;
polyC=polyC->link;
free(pc);
return(polyC);
}
}
}
void main()
{
struct term *polyA, *polyB, *polyC;
int n;
ployC=polyAdd(polyA, polyB);
printf("Polynomial A:\n");
prnPoly(polyA);
printf("Polynomial B:\n");
prnPoly(polyB);
printf("Polynomial C:\n");
prnPoly(polyC);
}
Exercise:
1. Given a polynomial of a single variable represented as a linked list. Write function to differentiate the polynomial. Do not
create another list.
2. Write function to subtract a polynomial from another polynomial.
3. Write a function to evaluate polynomial at x=x0.
double evalPoly(struct term *poly, float x0)
{
double res=0;
while(poly != NULL)
{
Res=res + poly->coef * pow (x0, poly->expo);
poly=poly->link;
}
return(res);
}
head N 6 7 8 9 N
n
== 0 >0
void createDLL(int n)
{
struct dnode *curr, *next;
int i;
if(n<=0)
head=NULL;
else
{ /* --create first (head) node-- */
head=(struct dnode*)malloc(sizeof(struct dnode));
printf("Enter data for 1 node:");
scanf("%d",&head->data);
head->llink=NULL;
curr=head;
for(i=1; i<n; i++)
{ /* --Create rest of the n-1 nodes-- */
next=(struct dnode*)malloc(sizeof(struct dnode));
printf("enter data for %d node:",i+1);
scanf("%d", &next->data);
curr->rlink=next;
next->llink=curr;
curr=next;
}
curr->rlink=NULL;
}
}
void traverseDLL()
{
temp 5
head N 6 7 8 N
temp N 5
6 7 8 N
head
head
temp 5
head N 6 7 8 9 N
prev curr
temp 5
head N 6 7 8 9 N
prev curr
temp 5
head N 6 7 8 N
prev
temp 5 N
head N 6 7 8
prev
temp->rlink=NULL;
head=temp;
}
else
{
if (pos == 1) /* --insert at first position-- */
{
temp->rlink=head;
temp->llink=NULL;
head->llink=temp;
head = temp;
}
else
{
c=1;
curr=head;
while (c < pos && curr != NULL)
{
c++;
prev=curr;
curr=curr->rlink;
}
if (curr == NULL) /* --insert node at the end-- */
{
prev->rlink=temp;
temp->llink=prev;
temp->rlink=NULL;
}
else /* --insert node in between-- */
{
prev->rlink=temp;
temp->llink=prev;
curr->llink=temp;
temp->rlink=curr;
}
}
}
}
head N 6 7 8 9 N
head
curr
head N 6 N 7 8 9 N
head N 6 7 8 9 N
prev curr
head N 6 7 8 9 N
{
c++;
prev=curr;
curr=curr->rlink;
}
if (curr == NULL)
printf("ERROR: No node on this position\n");
else /* --delete node in between-- */
{
next=curr->rlink;
prev->rlink=next;
if (next != NULL) /* --node is not a last node-- */
next->llink=prev;
free(curr);
}
}
}
}
void main()
{
int n,ch,pos;
clrscr();
while(1)
{
printf("DOUBLY LINLKED LIST\n");
printf("1.Create\n2.Traverse\n3.Insert\n4.Delete\n5.Quit\n");
printf("Enter your choice:");
scanf("%d",&ch);
switch(ch)
{
case 1:
printf("Enter No of nodes:");
scanf("%d",&n);
createDLL(n);
break;
case 2:
if (head == NULL)
printf("List is EMPTY\n");
else
traverseDLL();
getch();
break;
case 3:
printf("Enter position:");
scanf("%d", &pos);
insDLL(, pos);
break;
case 4:
printf("Enter position:");
scanf("%d", &pos);
delDLL( pos);
break;
case 5:
return;
default:printf("Wrong choice:re-enter\n");
}
}
}
Exercise:
1. The concatenation of two link lists is to be performed in O(1) time. Which of the following implementations of a list shall be
used?
(a) Single link list (b) doubly link list
(c) Circular link list (d) array implementation of lists
Code:
end1=list1->llink;
end2=list2->llink;
list2->llink=end1;
end1->rlink=list2;
list1->llink=end2;
end2->rlink=list1;
2. Write a function to generate a doubly linked list from a given singly linked list.
3. Write a function to remove all occurrences of value m from a doubly linked list
head 6 7 8 9
Creation and
traversal in Circular Doubly Linked List
Figure shows flow chart of creation on doubly linked list of n nodes.
n
== 0 >0
void createDLL(int n)
{
struct dnode *curr, *next;
int i;
if(n<=0)
head=NULL;
else
{ /* --create first (head) node-- */
head=(struct dnode*)malloc(sizeof(struct dnode));
printf("Enter data for 1 node:");
scanf("%d",&head->data);
curr=head;
for(i=1; i<n; i++)
{ /* --Create rest of the n-1 nodes-- */
next=(struct dnode*)malloc(sizeof(struct dnode));
printf("enter data for %d node:",i+1);
scanf("%d", &next->data);
curr->rlink=next;
next->llink=curr;
curr=next;
}
curr->rlink=head;
head->llink=curr;
}
}
void traverseDLL()
{
struct dnode *temp;
9. Generalized List
A linear list was defined to be a finite sequence of n≥0 elements a 1, a2, …..an, which we write as A=( a1, a2, …..an). the elements of a
linear list are restricted to be atoms and thus the only structural property a linear list has is the one of position, i.e. a i precedes ai+1, 1≤ i
≤n. it is sometimes useful to relax this restriction on the elements of a list, permitting them to have a structure of their own.
A generalized list, A is a finite sequence if n≥0 elements, a1, a2, …..an, where ai are either atoms or lists. The elements ai, 1≤ i ≤n
which are not atoms are said to be the sublists of A.
A list A itself is written as A= ( a1, a2, …..an). A is the name of the list ( a1, a2, …..an) and n its length. If n ≥ 1, then a1 is head of A
while (a2, …..an) is the tail of A. this definition of generalized list is recursive one. Some examples of generalized lists are
(i) D=() the null or empty list; its length is zero
(ii) A = (a, (b, c)) a list with length two; its first element is atom ‘a’ and second element is a linear list
(iii) B = (A, A, ( )) a list of length three; whose first two elements are the list A and the third element the null list
(iv) C = (a, C) a recursive list of length two; C corresponds to infinite list C = (a, (a, (a, (……..)))
Two important consequences of definition are:
1. Lists may be shared by other lists (in example iii)
2. Lists may be recursive ( in example iv)
Tag is 0 if element is an atom and tag is 1 if element is a list. The representation of generalized list (i) to (iv) are:
D NULL
A 0 a 1
B 1 1 1 N N B = (A, A, ( ))
C a C = (a, C)
0 1 N
struct gnode
{
struct gnode * link ;
int tag ;
union
{
int data ;
struct gnode * dlink ;
}
};
Before writing function to create generalized linked list lets us analyze the function to create singly linked list in which nodes are
added at run time. In fact it a linked list of n nodes but the value of n is decided by the number of nodes created at run time (value of n
is not predefined).
void createSLL()
{
struct node *curr, *temp;
char ch;
while (1)
{
printf("wants to add node in the list:");
ch=getch();
if (ch == 'n' || ch == 'N')
break;
else
{
temp=(struct node*)malloc(sizeof(struct node));
printf("Enter data:");
scanf("%d",&temp->data);
temp->link=NULL;
if (head == NULL)
{
head = temp;
curr = temp;
}
else
{
curr->link=temp;
By Dr. M. M. Raghuwanshi, YCCE,Nagpur
Notes On Algorithms and Data Structures
curr=temp;
}
}
}
}
struct gnode
{
int tag;
union
{
int data;
struct gnode *dlink;
};
struct gnode *link;
};
head = NULL;
while (1)
{
printf("wants to add element in the list:");
ch=getch();
By Dr. M. M. Raghuwanshi, YCCE,Nagpur
Notes On Algorithms and Data Structures
if(h != NULL);
{
temp=h;
printf("( ");
while(temp != NULL)
{
if(temp->tag == 0)
printf("%d\t", temp->data);
else
traverseGLL(temp->dlink);
temp=temp->link;
}
printf(")");
By Dr. M. M. Raghuwanshi, YCCE,Nagpur
Notes On Algorithms and Data Structures
}
}
void main()
{
int n,ch,pos;
struct gnode *head;
while(1)
{
printf("GENERALIZED LINLKED LIST\n");
printf("1.Create\n2.Traverse\n3.Quit\n");
printf("Enter your choice:");
scanf("%d",&ch);
switch(ch)
{
case 1:
head = createGLL();
break;
case 2:
printf("Traversing in the generalised Singly linked list:\n");
traverseGLL(head);
printf("\n");
getch();
break;
case 3:
return;
default:printf("Wrong choice:reenter\n");
}
}
}
Exercise:
1. Write a function to create exact copy of a given generalized linked list.
Solution:
struct gnode * copyGLL (struct gnode * curr)
{
struct gnode * temp ;
if (curr != NULL)
{
temp = ( struct gnode *) malloc (sizeof (struct gnode));
temp->tag= curr->tag;
if (curr->tag == 1)
temp->dlink = copyGLL(curr->dlink);
else
temp->data= curr->data;
temp->link=copyGLL(curr->link);
return(temp);
}
else
return (NULL);
}
By Dr. M. M. Raghuwanshi, YCCE,Nagpur
Notes On Algorithms and Data Structures
2. Write a function to check whether given two generalized lists are equal or not?
Solution:
check (struct gnode *f, struct gnode *s)
{
int result = 0 ;
if (curr== NULL)
return (0);
else
{
if (curr->tag == 1)
clink=countGLL(curr->dlink);
else
catom=countGLL(curr->link);
}
return (1+catom+clink);
}
5. Write a function to count number of atoms and lists in a given generalized list
6. Write a function that takes an arbitrary list l with no shared sub-lists and invert it and all of its sub-lists. For example if l= (a,
(b, c)) then invert (l) = ((c, b), a).
One can easily think of sequential representation for P(x,y,z) using nodes with fields coef, expx, expy, and expz. But this would means
that polynomial in different number of variables would need a different number of fields that add another complexity to
representation.
The idea of using a generalized list structure with fixed size nodes arises naturally. Let us re-write P(x,y,z) as
Continuing in this way one can see that every polynomial consists of a variable plus coefficient-exponent pairs. Each coefficient is
itself a polynomial (in one less variable) if a single numerical coefficient is regarded as a polynomial in zero variables. One can see
from discussion that every polynomial, regardless of the number of variables in it, can be represented using nodes of the type defined
below
struct pgnode
By Dr. M. M. Raghuwanshi, YCCE,Nagpur
Notes On Algorithms and Data Structures
{
int tag ;
union
{
struct pgnode * dlink ;
char var ;
float coeff ;
};
int expo ;
struct pgnode *link ;
}
1 y 0 0 3 0 2 N
1 y 0 0 4 2 2 1 N
1 x 0 2 1 9 2 2 8 N
1 x 0 2 1 4 2 6 3 N
1 x 0 2 3 8 N
Exercise:
1. Represent following polynomial using generalized list
P(x,y,z) = 4x7 y3 z3 + 2y z + 3x8 z3 + 6x5 y4 z + 9x6+8y5 - x9 y3 z3