Monday, December 30, 2013

Linked Lists Notes

Linked Lists
*Sequential method of allocation is suitable for certain applications only.
*Other applications where the sequential allocation method is unacceptable usually has the following characteristics.
1. unpredictable storage requirements:- The exact amount of data storage required by program in these areas often depends on the particular data being processed and consequently ,this requirement cannot be easily determined at the time the program is written.
2. Extensive manipulation of the stored data:- programs in these areas typically require that operations such as insertions and deletions be performed frequently on the data.
The linked-allocation method of storage can be result in both the efficient use of computer storage and computer time.
The use of pointers or links to refer to elements of a data structure (which is linearly ordered) implies that elements which are logically adjacent need not be physically adjacent in memory. This type of allocation is called Linked Allocation.
A list has been defined to consist of an ordered set of elements which may vary in number. A simple way to represent a linear list is to expand each node to contain a link or pointer to the next node. This representation is called a one-way chain or singly linked linear list.
Representation:
*List with array implementation requires O(n) time for insertion and deletion operations.
*Linked list implementation of list requires O(1) time for insert/delete operations.
Disadv:
If the position of an element is given in the list it requires O(n) time to find in linked list.
Single Linked List:
*If we want to delete an element from a single linked list we need the address of its previous node.
*We can only insert the new element after a given node.
Insertion into single linked list:
Deletion from a linked list
A special node (dummy node) called as header node is used in the beginning of the list, which is used to maintain the information about the list like, no elements, type of the
elements, owner of the list etc.
Header node facilitates us to insert in the front of the list, as eliminating the special case of deleting first node.
Single Linked list :Implementation
typedef struct node *nptr;
struct node
{
int data;
Data next
nptr next;
};
*Creating the list
nptr Createhead(void)
{ /*Creating the header node */
nptr L;
L = (nptr)malloc (sizeof(struct node));
if (L = = NULL)
printf(“out of space”);
else
L ->next = NULL
return(L);
}
*Counting the no of nodes of the list
int countnodes(nptr L)
{ /*Counting the no of nodes */
int k =0;
nptr p;
p = L -> next
while(p! = NULL)
{
k++;
p = p-> next;
}
return(k);
}
*printing the list
void printlist(nptr L)
{ /*Printing the list */
nptr p;
p = L ->next;
while (p!=NULL)
{
printf(“%d”, p->data);
p = p-> next;
}
}
*Finding previous of the given element(delete)
nptr findprev(nptr L, int x)
{/*Finding the previous of given node */
nptr p;
p = L;
while ((p->next!=NULL) && (p->next ->data!= x)
{
p = p->next;
}
return(p);
}
The above function returns last node address when x does not exist.
X =25
*Finding the address of a node after which the new element is to be inserted.
nptr findpos (nptr L ,int x)
{/*Finding the position of the given node */
nptr p;
p = L;
while ((p->next!= NULL) &&(p->next ->data < x))
p = p-> next;
return(p);
}
*Finding the address of the last node
nptr findlast (nptr L)
{/*Finding the address of last node */
nptr p;
p = L;
while(p->next != NULL)
p = p->next;
return(p);
}
*Inserting an element into an ordered list
void ordinsert(nptr L,int x)
{/*Inserting the element into a ordered list */
nptr temp p;
p = findpos(L,x)
temp = (nptr) malloc (sizeof(struct node));
if (temp = = NULL)
printf(“out of space”);
else
{
temp ->data = x;
temp ->.next = p->next;
p->next = temp;
}
}
*Inserting an element in the beginning of the list
void beginsert (nptr L,int x)
{/*Inserting the element at the beginning */
nptr temp;
temp = (nptr) malloc (sizeof (struct node));
if(temp!= NULL)
{
temp ->data = x;
temp -> next = L -> next;
L-> next = temp;
}
else
printf(“out of space”);
}
*Inserting an element at the end of the list
void endinsert (nptr L,int x)
{ /*Inserting the element at the end */
nptr temp,last;
last = findlast(L);
temp = (nptr)malloc(sizeof(struct node));
if(temp = = =NULL)
printf(“out of space”);
else
{
temp ->data = x;
temp ->next = last->next;
last-> next = temp;
}
}
*Creating an ordered list
nptr Createlist(void)
{/*Creating an ordered list*/
nptr L;
int x;
L = Createhead();
while(1)
{
printf(“Enter the element –999 at the end”);
scanf(“%d”, &x);
if(x = = - 999)
break;
else
ordinsert(L,x);
}
return(L);
}
*Deleting an element x from the given list
void delete (nptr L,int x)
{/*Deleting an element x from the given list */
nptr temp,prev;
prev = findprev(L,x);
if (prev-> next ! = NULL)
{
temp = prev -> next;
prev->next = temp-> next;
free(temp);
}
else
printf(“Element is not existing”);
}
*updating an element of a given SLL
void update(nptr L,int x,int y)
{
nptr p;
p = find(L,x);
if(p = = NULL)
printf (“Element is not existing”);
else
p->data = y;
}
*Appending two lists
nptr append(nptr L1,nptr L2)
{
nptr last;
if(L1 -> next = = NULL)
return(L2);
else if(L2 ->next = = NULL)
return(L1)
else
{
last = findlast(L1)
last->next =L2->next;
free(L2);
return(L1)
}
*splitting a given list into two lists based on the given value of ‘x’.
nptr split(nptr L1,int x)
{
nptr p,L2;
L2 =createhead();
p = find(L1,x);
L2 -> next = p ->next;
p->next = NULL;
return(L2);
}
*Merging two linked lists
nptr merge (nptr L1,nptr L2)
{
nptr L3, t1,t2,t3,temp;
L3 =createhead();
t1 = L1 -> next;
t2 = L2-> next;
t3 = L3;
while((t1! = NULL) && (t2! = NULL))
{
temp = (nptr)malloc(sizeof(struct node));
t3->next = temp;
t3 =temp;
if( t1 ->data <= t2->data)
{
temp -> data = t1->data;
t1 = t1->next;
}
else
{
temp->data = t2->data;
t2 = t2->next;
}
}
while (t1!= NULL)
{
temp = (nptr) malloc (sizeof(struct node ));
t3->next = temp;
t3 =temp;
temp->data = t1->data;
t1 = t1->next;
}
while (t2!= NULL)
{
temp = (nptr)malloc(sizeof(struct node ));
temp->data = t2->data;
t2 =t2->next;
t3->next = temp;
t3 = temp;
}
t3->next = NULL;
return (L3);
}
*Merging two lists without using any extra memory
nptr merge (nptr L1,nptr L2)
{
nptr t1,t2,t3;
t1 = L1->next;
t2 =L2 -> next;
while ((t1!= NULL) && (t2!=NULL)
{
if (t1->data <= t2->data)
{
t3 ->next = t1;
t1 = t1->next;
}
else
. {
t3-> next = t2;
t2 = t2 -> next;
}
t3 = t3->next;
}
if (t1= = NULL)
t3->next = t2;
else
t3->next = t1;
free(L2);
return(L1);
}
*Reversing a given SLL
L P q r
void reverse(nptr L)
{
nptr p,q,r;
p = NULL;
q = L -> next;
while (q!= NULL)
{
r = q ->next;
q->next = p;
p = q;
q = r;
}
L->next = p;
}
Polynomial Implementation:
One variable polynomials can be implemented using arrays
ex : 8x6 + 5x 4 + 3x 3 + 6x + 5
Each term of the polynomial consists of two values size: Coef. and xpower. In the array they can be represented using the value and position.
9 8 7 6 5 4 3 2 1 0
0
0
0
8
0
5
2
0
6
5
*Functions for polynomial Addition
A function which can read the polynomial and return the highest degree (user enters c,e; 0, 0 at the end)
int readpoly(int p [])
{
int hd.,c,e,i;
for (i = 0;i< size;i++)
p[i] = 0;
while (1)
{
printf(“Enter coef & xpower”);
scanf(“%d %d” ,&c ,&e);
if(c= = 0)
return(hd);
else
{
p[e] = c;
if(hd < e)
hd = e;
}
}
}
*printing a polynomial when the highest degree is given
void printpoly(int p[], int hd)
{
int i;
for(i = hd;i>0 ; i++)
{
if(p[i] ! = 0)
{
printf(“+(%d) x ^ %d” ,p [i] , i): } } printf(“+(%d)”,p[i]);
}
*Adding two polynomials is adding two arrays
*Disadvantage with array representation is wastage of memory.
Polynomials can be implemented using an array of structures.
ex: 10 x7 + 5x 5 + 3x 4 + 4x
0 1 2 3 4 5 6
10
5
3
4
7
5
4
1
Implementation
struct term
{
int coef;
int exp;
};
typedef struct term sterm;
*Function to read the polynomial & returns no of terms.
int readpoly(sterm p[])
{
int i;
i = 0;
do
{
printf(“Enter the coef & xpower”);
scanf(“%d %d”, & p[i].coef , &p[i].xp);
i++;
}
while(p[i-1].coef != 0);
return(i-1);
}
*printing a polynomial when the no of terms is known
void printpoly(stem p[] ,int n)
{
int i;
for( i = n-1 ; i>= 0;i--)
{
if(p[i].xp = = 0)
break;
else
printf(“+(%d) x^%d”, p[i].coef,p[i] .xp);
}
if(i > = 0)
printf(“ + (%d)”, p[i].coef );
}
Adding two polynomials
m-1
P1
10
8
3
4
2 6 5 2 1 0
n-1
P2 2 4 4 1 4
4
4
3
2
0
10
6
P3
int polynomialadd( sterm p1[ ] , sterm p2[ ], sterm p3[] ,int m,int n)
{
int i,j ,k;
i = j= k =0
while( ( i< m) &&( j < n))
{
if( p1[i] .xp = = p2[j].xp)
{
p3[k].coef = p1[i] .coef + p2[j].coef;
p3[k].xp = p1[i] .xp;
k++;i++;j++;
}
else if(p1[i].xp > p2[j].xp)
{
p3[k].coef = p1[i].coef;
p3[k].xp = p1[i].xp;
i++;k++;
}
else
{
p3[k].coef = p2[1].coef;
p3[k].xp = p2[j].xp;
j++; k++;
}
}
while(i < m)
{
P3[k] = p2[j];
k++;j++;
}
while(j<n)
{
P3[k] = p2[j];
k++;j++;
}
return(k);
}
Linked list Implementation of polynomials
typedef struct tnode * tnptr;;
Struct tnode
{
int coef; coef xp
next
int xp; term
tnptr next;
};
*Function to find the address of the term with the power e.
tnptr findterm(tnptr p, int e)
{
tnptr t;
t = p -> next;
while(( t! = NULL) && ( t ->xp ! = e))
t = t->next;
return(t);
}
*Function to find the address of a node after which the new term is to be inserted.
tnptr findtpos(tnptr p ,int e)
{
tnptr t;
t =p;
while((t->next ! = NULL) &&(t->next ->xp >e))
t = t->next;
return(t);
}
*Function to insert a term into the polynomial void terminsert (tnptr p,int c,int e)
{
tnptr pos temp;
pos = findterm(p,e);
if (pos ! = NULL)
pos ->coef + = c;
else
{
pos = findtpos(p,e);
temp = (tnptr)malloc(sizeof(struct tnode));
temp ->coef = c;
temp ->xp = e;
temp ->next = pos->next;
pos->next = temp;
}
}
*Multiplying two polynomials
tnptr polyprod(tnptr p1, tnptr p2)
{
tnptr t1,t2,p3;
int c,e;
p3 = createhead();
for( t1 = p1->next ;t1! = NULL;t1 = t1->next)
for(t2 = p2->next;t2!= NULL;t2 = t2->next)
{
c = t1->coef * t2 ->coef;
e = t1->xp + t2->xp;
terminsert(p3,c,e);
}
return(p3);
}
*Function to add two polynomials
tnptr polyadd(tnptr p1,tnptr p2)
{
tnptr t1, t2,t3,p3,temp;
p3 = createhead();
t1 = p1->next;
t2 = p2->next;
t3 = p3;
while((t1! = NULL) && (t2 != NULL)
{
temp = (tnptr)malloc (sizeof(struct tnode));
t3 ->next = temp;
t3 = temp;
if(t1 ->xp > t2 ->xp)
{
t3 ->coef = t1 ->coef;
t3 -> xp = t1->xp;
t1 = t1->next;
}
else if(t1->xp < t2->xp)
{
t3 ->coef = t2->coef;
t3 ->xp = t2 ->xp;
t2 = t2->next;
}
else
{
t3 ->coef = t1->coef + t2->coef;
t3 ->xp = t1->xp;
t1 = t1->next;
t2 = t2 ->next;
}
}
while(t1!= NULL)
{
temp = (tnptr)malloc(sizeof(struct tnode));
temp -> coef = t1 ->coef;
temp-> xp = t1->xp;
t1 = t1->next;
t3 ->next = temp;
t3 = temp;
}
while (t2 != NULL)
{
temp =(tnptr) malloc (sizeof(struct tnode));
temp ->coef =t2->coef;
temp-> xp = t2 ->xp;
t2 = t2->next;
t3 -> next = temp;
t3 = temp ;
}
t3 -> next = NULL;
return(p3);
}
Circular Linked List(CLL)
Last node next field will give the address of the first node/header node
*If the address of any node is given we can access all the nodes, which is not possible in SLL.
*Function to reverse the elements/nodes of CLL.
void reversecll(nptr L)
{
nptr p,q,r;
p =L;
q= L->next;
while(q! = L)
{
r = q->next;
q->next = p;
p->q;
q-> r;
}
L->next = p;
}
*Function to concatenate two CLLs
nptr concat(nptr L1,nptr L2)
{
nptr p;
p = L1->next->next;
L1->next ->next = L2->next->next;
L2->next ->next = p;
free(L1);
return(L2);
}
Double Linked List
Each node gives the addresses of its previous node and its next node-two links are maintained.
If the address of a node is given we can delete it which is not the case with SLL.
If the address of a node is given we can insert a new element before it or after it.
If one link is lost, we can restore it using the other link.
We can traverse list in both the directions.
dnode
prev
data
next
typedef struct dnode* dnptr;
struct dnode
{
dnptr prev;
int data;
dnptr next;
};
Representation :
*Function to delete a given element from DLL
void delete(dnptr H, int x)
{
dnptr p;
p=find(H,x);
if (p = = NULL)
printf(“Element is not existing”);
else
{
if(H->prev = = H->next)
{
H->prev = H->next = NULL;
}
else if(p = = H->prev)
{
H->prev = p->next;
p->next ->prev = NULL;
}
else if(p = = H->next)
{
H->next = p->prev;
p->prev ->next = NULL;
}
else
{
p->next ->prev = p->prev;
p->prev ->next = p->next;
}
free(p);
}
}
* Function to insert an element into DLL before given node ‘p’.
void dllinsertbp(dnptr H,dnptr p,int x)
{
dnptr temp;
temp = (dnptr)malloc(sizeof(struct dnode));
temp ->data = x;
if(p->NULL)
{
temp ->prev = temp ->next = NULL;
H->prev = H->next = temp;
}
else
if (p = =H->prev)
{
temp ->next = p;
temp->prev = NULL;
p->next = temp;
H->prev = temp;
}
else
{
temp ->next = p;
temp ->prev = p->prev;
p->prev ->next = temp;
p->prev = temp;
}
}
Radix Sort:- Function ‘m’ –is the no of digits.
void radixsort(nptr L,int m)
{
nptr B[10],T[10],p,q,prev;
int i,j ,k d;
for(i =0; i<=m;i++)
{
/* intializing the buckets*/
for(j=0;j<= 9;j++)
B[j ] = T[j ] = NULL;
p = L->next;
/* Distributing the elements into buckets based on a digit*/
while(p!=NULL)
{
q = p->next
d= p->data/pow(10,j)%10;
if(T[d] = = NULL)
T[d] = B[d] = p;
else
{
T[d] ->next = p;
T[d] =p;
}
T[d] ->next = NULL;
p = q;
}
/* Combining all the buckets.*/
k = 0;
while(B[k ] = = NULL)
k++;
L->next = B[k] ;
for(j = k+1; j<= 9; j++)
{
prev = T[j-1];
if(B[j]!=NULL)
prev -> next = B[j];
else
T[j] = prev;
}
}
}
Time Complexity : T(n) = O(m * n).