Download as docx, pdf, or txt
Download as docx, pdf, or txt
You are on page 1of 14

DSC SELF-STUDY

Problem Statement:
Implementing a Data Structure for Least Recently Used (LRU) cache which supports the
following operations:
Get_from_cache (Key) : Get the value associated with the key ,if key not found report it
accordingly.
Put_into_cache (Key, Value) : Put (Key, Value) into cache. If cache is full, then use LRU
eviction policy to replace given item in place of Least Recently Used Item.

Introduction to Problem Statement:


In computing, a cache is a hardware or software component that stores data so that future
requests for that data can be served faster; the data stored in a cache might be the result of
an earlier computation or a copy of data stored elsewhere. A cache hit occurs when the
requested data can be found in a cache, while a cache miss occurs when it cannot.
A cache works on the principle of Locality of Reference. In computer science, locality of
reference, also known as the principle of locality, is the tendency of a processor to access
the same set of memory locations repetitively over a short period of time.

Least recently used (LRU) Replacement policy:


Discards the least recently used items first. This algorithm requires keeping track of what
was used when, which is expensive if one wants to make sure the algorithm always discards
the least recently used item. General implementations of this technique require keeping
"age bits" for cache-lines and track the "Least Recently Used" cache-line based on age-bits.
In such an implementation, every time a cache-line is used, the age of all other cache-lines
changes. LRU is actually a family of caching algorithms with members including 2Q by
Theodore Johnson and Dennis Shasha, and LRU/K by Pat O'Neil, Betty O'Neil and Gerhard
Weikum. The access sequence for the below example is A B C D E D F.
Some of the Requirement are

1. Fixed Size: Cache needs to have some bounds to limit memory usages.

2. Fast Access: Cache Insert and lookup operation should be fast, preferably O (1) time.

3. Replacement of Entry in case, Memory Limit is reached: A cache should have efficient
algorithm to evict the entry when memory is full.

In case of LRU cache we evict least recently used entry so we have to keep track of recently
used entries, entries which have not been used from long time and which have been used
recently. plus, lookup and insertion operation should be fast enough.
The Cache implemented here can store 32 key-value pairs.

Data Structures Used:


The Data Structures used for implementing LRU Cache are:
DOUBLY LINKED LIST: It supports deletion and insertion operations used during LRU
replacements at O (1) time. It keeps track of recently used keys. Whenever a key is accessed
it is added to the head of the linked list. Whenever space has to be made for a new key, the
last key in the linked list is deleted and the new key is added to the head of the list. The
previous pointer of head is made to point to the last element in the list to make Deleterear()
operation constant time( O (1) ).
HASH TABLE: It is used for O (1) lookup. The collision Resolution strategy technique used is
Double Hashing. Each hash table entry here stores the address of each of the nodes
in the Doubly Linked list and the key. The size of the hash table is the size of the
cache and is fixed.

Using both these data structures both lookup, addition and replacement of a key can be
done in constant time.
Algorithm :
For Put_into_cache (key, value):

 If entry is not present in the Hash Table then add entry to Hash table and add a node
to the top of doubly linked list.
 Else if entry is already present in the hash table, move the node corresponding to the
key-value pair to the top of the list.
 If table is full, delete last node in the doubly linked list and add new entry to the top
of the list.
For Get_from_cache (Key):

 Search if element is present in the cache.


 If element not present in the cache report accordingly.
 If element is present in the cache print Key-Value pair.
 Move Key to the top of the list.

CODE:
#include<stdio.h>

#include<stdlib.h>

#define size 32

struct dlist{

int key,val;

struct dlist *next,*prev;

};

struct dlist *h=NULL;

struct entry{

int k;

struct dlist *ne;

};

struct dlist *getnode()

struct dlist *nd;

return nd=(struct dlist *)malloc(sizeof(struct dlist));


}

int hash(int key){

int prime=29;

return (prime-key%prime);

struct dlist *addfront(int ke,int value)

struct dlist *temp,*nd;

temp=getnode();

temp->next=temp->prev=NULL;

temp->val=value;

temp->key=ke;

if(h==NULL)

h=temp;

h->prev=h;

return h;}

temp->next=h;

nd=h->prev;

h->prev=temp;

temp->prev=nd;

h=temp;

return h;

struct dlist *deleterear()

struct dlist *temp;

temp=h->prev;
h->prev=temp->prev;

h->prev->next=NULL;

free(temp);

return h;

int search(struct entry a[],int c)

int index, flag=0,i;

for(i=0;i<size ;i++)

index=(c + i*hash(c))%size;

if(a[index].k==c)

flag=1;

return index; }

if(flag==0)

return -1;

struct dlist *put_into_cache(struct entry a[],int ky,int value)

int i, index, flag=0;

struct dlist *temp;

for(i=0;i<size; i++)

index=(ky + i*hash(ky))%size;

if(a[index].k==-1) /* If empty entry for the key insert to top of LIST*/

flag=1;
a[index].k=ky;

h=addfront(ky,value);

a[index].ne=h;

break;

else if(a[index].k==ky) /* If entry entry already present change it's

value and add it top of LIST */

flag=1;

temp=a[index].ne;

if(temp==h)

{ temp->val=value;

break;}

if(temp==h->prev && temp->prev!=h)

struct dlist *f;

f=h->prev;

f=f->prev;

f->next=NULL;

temp->next=h;

h=temp;

temp->val=value;

return h;

if(temp->next==NULL && temp->prev==h)

h->next=NULL;

temp->next=h;

h->prev=temp;

temp->prev=h;

h=temp;
a[i].ne=h;

return h;

struct dlist *pv, *nt, *g;

pv=temp->prev;

nt=temp->next;

pv->next=nt;

nt->prev=pv;

a[index].ne->next=h;

g=h->prev;

h->prev=a[index].ne;

a[index].ne->prev=g;

h=a[index].ne;

if(h->val!=value)

h->val=value;

return h;

if(flag==0) /* If Hash Table is Full Use LRU eviction policy

to make space for new item */

index=search(a, h->prev->key);

h=addfront (ky ,value);

a[index].k=ky;

a[index].ne=h;

h=deleterear ();

return h;

}
struct dlist *Get_from_cache(struct entry a[],int key)

int index=search(a, key); /* Search if element is present int the cache */

if(index==-1)

{ printf("Element not found\n"); /* If element not present report it accordingly */

return h; }

struct dlist *temp=a[index].ne;

printf("KEY = %d VALUE = %d\n", temp->key,temp->val); /* If key is present Print (key,


value) */

if(temp==h)

return h;

if(temp==h->prev && temp->prev!=h) /* Move key to the top of the LIST */

struct dlist *f;

f=h->prev;

a[index].ne->prev->next=NULL;

a[index].ne->next=h;

h->prev=a[index].ne;

a[index].ne->prev=f;

h=a[index].ne;

return h;

if(temp->next==NULL && temp->prev==h)

h->next=NULL;

a[index].ne->next=h;

h->prev=a[index].ne;

a[index].ne->prev=h;

h=a[index].ne;

return h;

}
struct dlist *pv, *nt, *g;

pv=temp->prev;

nt=temp->next;

pv->next=nt;

nt->prev=pv;

a[index].ne->next=h;

g=h->prev;

h->prev=a[index].ne;

a[index].ne->prev=g;

h=a[index].ne;

return h;

void printcache ()

int i=1;

struct dlist *temp;

temp=h;

while(temp!=NULL) /* Traverse the LIST */

printf("%d) KEY = %d \t VALUE = %d\n",i++,temp->key,temp->val);

temp=temp->next; /* Print key and value in each node of LIST*/

int main(){

struct entry a[size];

int i, n1, n2, ke, v, ch;

for (i=0; i<size; i++)

{ a[i].k=-1;

a[i].ne=NULL; }

for (i = 1; i<= size*2; i++)


{ n1 = rand() % 64 + 1;

n2 = rand() % 50 + 1;

h=put_into_cache(a,n1,n2);

printf("\n CURRENT STATE OF CACHE IS :\n");

printcache();

printf("\n");

while(1)

printf("1) PUT A VALUE INTO CACHE\n2) GET A VALUE FROM CACHE\n3) PRINT THE
CURRENT STATE OF CACHE\n4) EXIT\n");

printf("ENTER YOUR CHOICE : ");

scanf("%d",&ch);

switch(ch)

case 1: printf("\nENTER Key and Value to Inserted: ");

scanf("%d%d",&n1,&n2);

h=put_into_cache(a,n1,n2);

break;

case 2: printf("\nENTER key whose value is to be obtained:\n");

scanf("%d",&ke);

h=get_from_cache(a,ke);

break;

case 3: printf("\n CURRENT STATE OF CACHE IS :\n");

printcache();

printf("\n");

break;

case 4: exit(0);

default:exit(0); } }

return 0;

}
OUTPUT:

You might also like