Design and implement a data structure for Least Recently Used (LRU) cache. It should support the following operations: get and set.
get(key) - Get the value (will always be positive) of the key if the key exists in the cache, otherwise return -1.
set(key, value) - Set or insert the value if the key is not already present. When the cache reached its capacity, it should invalidate the least recently used item before inserting a new item.
#include <iostream>
#include <map>
using namespace std;
struct node{
int val;
struct node* next;
struct node* prev;
};
class dlist{
public:
dlist(){}
dlist(int capacity){
cap=capacity;
}
void add(int value){
node* n=new node;
n->val=value;
if (size==0){
size++;
tail=n;
head=tail;
}
else {
if (size==cap){
node* buf=head;
head=head->next;
head->prev=NULL;
delete buf;
size--;
}
tail->next=n;
n->prev=tail;
tail=n;
size++;
}
}
int getVal(){
if (tail==NULL)
return -1;
return tail->val;
}
private:
int cap;
int size;
node* tail;
node* head;
};
class LRUCache{
public:
LRUCache(int capacity) {
cap=capacity;
}
int get(int key) {
if(cap!=0&&cache.find(key)!=cache.end())
return cache[key].getVal();
return -1;
}
void set(int key, int value) {
if (cap==0)
return;
if(cache.find(key)==cache.end()){
dlist d=dlist(cap);
cache.insert(make_pair(key,d));
}
cache[key].add(value);
}
private:
int cap;
map<int,dlist> cache;
};
int main()
{
LRUCache lru(3);
cout<<"asd";
lru.set(1,9);
lru.set(1,8);
lru.set(1,1);
lru.set(1,7);
lru.set(2,9);
cout<<lru.get(1)<<endl;
cout<<lru.get(2)<<endl;
cout<<lru.get(3)<<endl;
return 0;
}
so I used a map and a custom double linked list, it seems to working fine with if I add the cout line right after initializing LRU, but it will have seg fault if I don't, I and not very sure what should I do to manage the memory use of LRU(if this is the problem)
Also if there's any line that could be better written(aside from std namespace) please tell me, I would really appreciate that.
Your program exhibits undefined behavior since the member variables size, tail, and head of dlist are not initialized before being used.
Use
dlist() : dlist(0) {}
dlist(int capacity) : cap(capacity), size(0), tail(nullptr), head(nullptr) {}
That fixes the segmentation violation problem in my testing.
I recommend adding a constructor to node also:
struct node{
node(int v) : val(v), next(nullptr), prev(nullptr) {}
int val;
struct node* next;
struct node* prev;
};
and use
node* n=new node(value);
instead of
node* n=new node;
n->val=value;
Related
I am trying to implement stack using linked list and class, and to the stack class constructor, I am giving reference variables as arguments with default value 0. But it shows an error when I do push operation with an integer literal. How can I implement it by using a default value and reference variable as well?
// ***** Stack using linked list ****
#include <iostream>
using namespace std;
class node{
node* next;
int data;
public:
node(int &d=0,node* n=NULL):data(d),next(n){}
node(){}
~ node(){}
friend class stack0;
};
class stack0{
int size;
node* head;
public:
stack0(){}
stack0():size(-1),head( new node() ){}
void push(int &t){
if (size == -1){
head->data=t;
cout<<"& pushed "<<t<<" at "<<head<<" with size "<<size;
size++;
}
else{
node* temp;temp=head;
head = new node(t,head);
cout<<"& pushed "<<t<<" at "<<head<<" with size "<<size;
head->next=temp;
size++;
}
}
};
int main(){
stack0 s;
s.push(10);
return 0;
}
I have question about insertion and deletion speed of queue in c++ STL.
When i tried to slove algorithm question using Dequeue i made, i face running time out problem.
So i think my Dequeue is so slow, and i want to know what is the difference between my Dequeue and queue in c++ STL.
Here is my queue code.
Please give me some advice.
In this code, i suppose value in Node class can't have negative number.
class Node
{
private:
int value;
Node* prev;
Node* next;
public:
Node();
Node(int value);
Node(int value, Node* next);
~Node();
void setValue(int value);
void setPrev(Node* prev);
void setNext(Node* next);
int getValue();
Node* getPrev();
Node* getNext();
};
Node::Node()
: value(-1), prev(nullptr), next(nullptr)
{
}
Node::Node(int value)
: value(value), prev(nullptr), next(nullptr)
{
}
Node::Node(int value, Node* next)
: value(value), prev(nullptr), next(next)
{
}
Node::~Node()
{
}
void Node::setValue(int value)
{
this->value = value;
}
void Node::setPrev(Node* prev)
{
this->prev = prev;
}
void Node::setNext(Node* next)
{
this->next = next;
}
int Node::getValue()
{
return this->value;
}
Node* Node::getPrev()
{
return this->prev;
}
Node* Node::getNext()
{
return this->next;
}
class Dequeue
{
private:
Node* front;
Node* back;
public:
Dequeue();
~Dequeue();
void pushFront(int value);
void pushBack(int value);
void popFront();
void popBack();
int getFront();
int getBack();
int getSum();
};
Dequeue::Dequeue()
{
this->back = new Node(-1, nullptr);
this->front = new Node(-1, this->back);
this->back->setPrev(front);
}
Dequeue::~Dequeue()
{
}
void Dequeue::pushFront(int value)
{
Node* node = new Node(value, this->front->getNext());
node->setPrev(this->front);
this->front->setNext(node);
node->getNext()->setPrev(node);
}
void Dequeue::pushBack(int value)
{
Node* node = new Node(value, this->back);
node->setPrev(this->back->getPrev());
this->back->setPrev(node);
node->getPrev()->setNext(node);
}
void Dequeue::popFront()
{
if (this->front->getNext() == this->back)
return;
Node* node = this->front->getNext();
this->front->setNext(node->getNext());
node->getNext()->setPrev(this->front);
node->setNext(nullptr);
node->setPrev(nullptr);
delete node;
}
void Dequeue::popBack()
{
if (this->back->getPrev() == this->front)
return;
Node* node = this->back->getPrev();
this->back->setPrev(node->getPrev());
node->getPrev()->setNext(this->back);
node->setNext(nullptr);
node->setPrev(nullptr);
delete node;
}
int Dequeue::getFront()
{
if (this->front->getNext() == this->back)
return -1;
return this->front->getNext()->getValue();
}
int Dequeue::getBack()
{
if (this->back->getPrev() == this->front)
return -1;
return this->back->getPrev()->getValue();
}
You Dequeue is implemented via a linked list, where nodes are allocated/deallocated in each push/pop operation. std::queue is implemented via a std::deque, which is much more efficient (it allocates only once a while).
Linked lists are good if you need to insert in the middle, but this is not your case. std::deque is basically a dynamic sequence of fixed-size arrays.
Relevant questions:
Why does std::queue use std::dequeue as underlying default container?
Which STL container should I use for a FIFO?
I created a private static variable that keeps track of the number of elements in the linked list.
struct node
{
int data;
node *next;
};
class linkedList
{
private:
node *head,*tail;
static int listSize;
public:
linkedList()
{
head=NULL;
tail=NULL;
}
void insert(int n)
{
node *temp=new node;
temp->data=n;
temp->next=NULL;
if(head == NULL)
{
head=temp;
tail=temp;
}
else
{
tail->next=temp;
tail=temp;
}
linkedList::listSize+=1;
}
};
void main()
{
linkedList l;
l.insert(10);
l.insert(20);
}
The compiler throws an error when it reaches the line linkedList::listSize+=1;
error: ‘linkedList’ has not been declared.
Once your typos corrected (inser(20) instead of insert(20) and : instead of ; in linkedList(), your program almost compiles.
There is just one thing missing: you need to implement the listSize variable somewhere for example by putting int linkedList::listSize; before main:
...
int linkedList::listSize; /(/ <<< add this
void main()
{
linkedList l;
l.insert(10);
l.insert(20);
}
But why are you using a static variable for counting the elements of the list? You probably want listSize to be an ordinary (non static) class member, just as head and tail:
class linkedList
{
private:
node * head, *tail;
int listSize; // no static
public:
...
and drop the int linkedList::listSize; suggested before.
i made this linked list class in c++ and it works fine except after i run it the program goes unresponsive. i have located the line that's causing the problem but i have no idea why. Even when i type it differently it still does the same thing.
Here's my list class:
#include <string>
template<class T>
class List : public Object{
private:
Node<T>* first;
Node<T>* last;
int length;
public:
List() : Object(new std::string("List")) {
first = NULL;
last = NULL;
length = 0;
}
~List() {
delete first;
delete last;
}
void Add(T value) {
if(first==NULL)
first = new Node<T>(NULL, value);
else if(last==NULL)
---->last = new Node<T>(first, value);<-----
else
last = new Node<T>(last, value);
length++;
}
T Remove(T value) {
Node<T>* temp = first;
while(temp!=NULL) {
if(temp->GetValue()==value) {
temp->GetPrev()->SetNext(temp->GetNext());
temp->GetNext()->SetPrev(temp->GetPrev());
delete temp;
length--;
return value;
}
temp = temp->GetNext();
}
return 0;
}
T Get(int index) {
Node<T>* temp = first;
int i = 0;
while(temp!=NULL) {
if(i==index)
return temp->GetValue();
i++;
temp = temp->GetNext();
}
return 0;
}
};
when i remove the marked line above the program go unresponsive. This is my Node constructor:
#include <string>
template<class T>
class Node : public Object{
private:
Node* next;
Node* prev;
T value;
public:
Node(Node* prev, T value) : Object(new std::string("Node")){
if(prev!=NULL) {
prev->next = this;
this->prev = next;
}
next = NULL;
this->value = value;
}
~Node() {
delete next;
}
T GetValue() {
return value;
}
Node* GetNext() {
return next;
}
Node* GetPrev() {
return next;
}
};
my object class:
#include <string>
class Object {
private:
std::string* type;
public:
Object() {
type = new std::string("Object");
}
Object(std::string* type) {
this->type = type;
}
~Object() {
delete type;
}
std::string* GetType() {
return type;
}
};
my Test.cpp
#include <iostream>
#include <string>
#include "Object.h"
#include "Node.h"
#include "List.h"
using namespace std;
int main () {
List<int> l;
l.Add(5);
l.Add(93);
l.Add(17);
l.Add(7789);
l.Add(60);
cout << "node 4 is:" << l.Get(3) << endl;
return 0;
}
error image http://i50.tinypic.com/2mw5phi.png
thanks for reading and please help as soon as you can, comment if you need me to supply more info.
Edit: There are many problems with your program, but what might be causing your crash: Your Add-function does not work correctly. It should be something like this:
if(first==NULL) {
first = new Node<T>(NULL, value);
last = first;
} else {
last = new Node<T>(last, value);
}
length++;
Otherwise, it will not correctly insert the second element. Why? With your original code, after the first add, your last is still NULL because of the else. So on the second add, you set last to new Node<T>(NULL, value). Therefore, it will not assign the first element's next pointer. And your list will be inconsistent.
Apart from that, there are double-frees, unnecessary heap-allocation of the string field in your Object class, ownership issues etc. To give you just one more example: Your List destructor will cause a heap corruption due to a double free. Calling delete first will delete all nodes due to the delete next in Node's destructor, as long as the list is consistent. Then you call delete last, but that object was already freed. This will corrupt your program's memory management and can also cause a crash at program exit.
Does this function seem correct to you??
It says GetPrev, but its actually getting next.
Node* GetPrev() {
return next;
}
I found that if I comment out this line in the Node constructor the code compiles:
if (next != NULL) {
// next->next = this;
prev = next;
}
Edit 1:
I also realized that you were doing this in your Node class:
private:
Node* next;
Node* prev;
T value;
Since these objects are declared in the Node class, they are at this time incomplete types. I managed to replicate that problem down to a simple one like this:
template <class T>
struct S {
S* s = new S();
~S() { delete s; }
};
int main() {
S<int> s; // Segmentation fault (core dumped) ./test > .stdout
}
This causes a crash because S is an incomplete type within itself.
I'm getting the same segementation fault as I got in your code. I'm pretty sure it's because the pointers in the Node class are built upon incomplete types; and accessing the data from them is looking into memory that isn't yours, hence the crash.
I'm trying to create a doubly-linked list with the null object model. So far, I've implemented a method to add a node to the beginning of the list and a method to display the node. My problem is that the display function always displays 0. Can anyone point out where I've gone wrong and how to fix it? Also, am I on the right track to correctly implementing the null object model here?
Note: This is a school assignment. Please don't just post a solution without an explanation. I want to learn and understand what's going on here.
Edit: After fixing the display problem, I have another: When calling getHead() or getTail() with a list that is empty or has nodes, it keeps wanting to use self() from the node class, rather than the nullNode class (in the event of an empty list) or elementNode class (in the event of a list with nodes). I'm stuck on how to fix this.
If I print out the addresses of container.getNext() and container (for an empty list), both addresses are the same so shouldn't adding ->self() to the end call the self() method from the nullNode class?
class node {
public:
node(){/* Do nothing */}
node(int e){ element = e; }
int getData(){ return element; }
void setData(int e){ element = e; }
friend class list;
protected:
node* getNext(){ return next; }
void setNext(node* n){ next = n; }
node* getPrev() { return prev; }
void setPrev(node* n){ prev = n; }
node* self();
private:
int element;
node* next;
node* prev;
};
class nullNode : public node{
public:
nullNode(){/* Do nothing */}
int getData(){ return NULL; }
void setData(int e){ /* Do Nothing */ }
node* getNext(){ return head; }
void setNext(node* n){ head = n; }
node* getPrev() { return tail; }
void setPrev(node* n){ tail = n; }
node* self(){ return NULL; }
private:
node* head;
node* tail;
};
class elementNode : public node{
public:
elementNode(){/* Do nothing */}
elementNode(int element){
setData(element);
}
int getData(){ return node::getData(); }
void setData(int e){ node::setData(e); }
node* getNext(){ return node::getNext(); }
void setNext(node* n){ node::setNext(n); }
node* getPrev() { return node::getPrev(); }
void setPrev(node* n){ node::setPrev(n); }
node* self(){ return this; }
};
class list{
public:
list();
node* getHead(){ return (container.getNext())->self(); }
node* getTail(){ return (container.getPrev())->self(); }
node* addHeadNode(int e);
void removeNode(node* n);
void insertBefore(node* n, int e);
void insertAfter(node* n, int e);
void displayNode(node *n);
private:
nullNode container;
};
list::list()
{
container.setNext(&container);
container.setPrev(&container);
}
node* list::addHeadNode(int e)
{
node* foo = new elementNode(e);
foo->setPrev(&container);
foo->setNext(container.getNext());
container.getNext()->setPrev(foo);
container.setNext(foo);
return foo;
}
void list::displayNode(node* n)
{
cout << "Node Data: " << n->getData() << endl;
}
int main()
{
list myList;
node* myNode;
myNode = myList.addHeadNode(5);
myList.displayNode(myNode);
return 0;
}
elementNode(int element)
{
node e;
e.setData(element);
}
What is this code doing? You create node e, but it appears to then be thrown away and not added to any list.
The problem hides in
elementNode(int element){
node e;
e.setData(element);
}
What is going on here? First you create an instance of the node class and then call its setData member function. Sure enough e is modified with the value of element but the very next moment both e and element are vanished out of existence because the scope where they were initialized has ceased to its end (terminated by }) while the information in element hasn't been saved anywhere.
However, if you replace the above code with
elementNode(int element){
setData(element);
}
it calls the inherited setData member function, the value of element is saved, and the program outputs 5 as expected.
Your elementNode constructor is trying to initialize it's node part:
elementNode(int element){
node e;
e.setData(element);
}
You actually just construct an unrelated node then discard it.
What you want is to call your superclass constructor, which can be done in the subclass constructor's initialization list:
elementNode(int element) : node(element) {
}