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?
Related
I'm writing a function which iterates a Queue from within a queue class which operates off of a LinkedList/Node data structure.
I've been able to make the function work but only by getting a pointer to the head node directly from the LinkedList class which, as I understand it, is considered poor encapsulation.
This is my code:
main():
int main()
{
Queue list;
int nums[] = {60, 50, 40};
for (int i=0; i<(int)sizeof(nums)/(int)sizeof(nums[0]); i++) {list.enqueue(nums[i]);}
list.iterate();
}
Queue:
.h
#include "LinkedList.h"
class Queue
{
public:
typedef int value_type;
Queue();
void enqueue(value_type& obj);
int size() const;
void iterate();
int min();
private:
LinkedList data;
int used;
};
#include "Queue.hpp"
.hpp
Queue::Queue()
{ data = LinkedList(); used = 0; }
void Queue::enqueue(value_type& obj)
{ ++used; data.addToTail(obj); }
int Queue::size() const
{ return used; }
void Queue::iterate()
{
node * temp = data.get_head();
for (int i = 0; i < size(); i++)
{ cout << temp->get_data() << endl; temp = temp->get_next(); }
delete temp;
}
LinkedList
.h
#include "Node.h"
class LinkedList
{
public:
typedef int value_type;
LinkedList();
void addToHead(typename node::value_type& entry);
void addToTail(typename node::value_type& entry);
node * get_head();
int front();
private:
node* head;
node* tail;
node* current;
};
#include "LinkedList.hpp"
.hpp
LinkedList::LinkedList()
{ head = NULL; tail = NULL; current = NULL; }
void LinkedList::addToTail(value_type& entry)
{
if (get_head() == NULL)
{ addToHead(entry); }
else {
node* add_ptr = new node;
add_ptr->set_data(entry);
add_ptr->set_next(current->get_next());
add_ptr->set_previous(current);
current->set_next(add_ptr);
if (current == tail) {tail = current->get_next();}
current = current->get_next();
}
}
void LinkedList::addToHead(value_type& entry)
{ head = new node(entry, head); if (tail == NULL) {tail = head;} current = head; }
node * LinkedList::get_head()
{ return head; }
int LinkedList::front()
{ int rval = head->get_data();return rval; }
Node
.h
class node
{
public:
typedef int value_type;
node();
node(const value_type& data, node* link);
void set_data(const value_type& new_data);
void set_next(node* next_ptr);
void set_previous(node* last_ptr);
int get_data() const;
node* get_next() const;
node* get_previous() const;
private:
value_type data;
node* next;
node* previous;
};
#include "Node.hpp"
.hpp
node::node()
{ data = 0; next = 0; previous = 0; }
node::node(const value_type& data, node* link)
{ this->data = data; this->next = link; this->previous = NULL; }
void node::set_data(const value_type& new_data) {data = new_data;}
void node::set_next(node* next_ptr) {next = next_ptr;}
void node::set_previous(node* last_ptr) {previous = last_ptr;}
int node::get_data() const {return data;}
node* node::get_next() const {return next;}
node* node::get_previous() const {return previous;}
Is it possible to iterate the LinkedList without directly retrieving a pointer node? And is this bad practice?
You do not expose the (internal) data structures of the linked list within the interface of the Queue-class (i.e. in the header file). You're just using these data structures in the implementation. Hence, I'd say that you do not "violate encapsulation".
But of course, you may adapt the interface of your LinkedList, such that it does not make use of the internal data structures directly. The standard library with its iterators shows how such a concept is realized. An iterator is an object that represents the position of an element in the container, (and it offers access to the respective element).
The encapsulation in Queue isn't violated but in LinkedList it is, you shouldn't have get_head() function that returns a private pointer member (what if someone does something like this: list.get_head()->set_next(NULL)). You need to create an iterate function in LinkedList and than Queue::iterate would just call this function.
Linked List Class
class LinkedList
{
protected:
class Element
{
private:
Element *next;
int data;
public:
~Element() {};
Element() {};
Element(int value): next(NULL), data(value) {};
Element(Element *elem, int value): next(elem), data(value) {};
void setNext(Element *elem) {next = elem;}
void setValue(int value) {data = value;}
Element *getNext() const {return next;}
int getValue() const {return data;}
};
Element *head;
Element *tail;
public:
LinkedList(): head(NULL), tail(NULL) {};
~LinkedList() {};
Element* returnHead() {return head;};
Element* returnTail() {return tail;};
void setTail(Element *elem) {tail = elem;};
void setHead(Element *elem) {head = elem;};
// Basic functions
void print();
void printEnds();
void insertFront(int value);
void insertAfter(int afterValue, int value);
void deleteAt(int value);
void reverse();
// Question functions
void mthElemLast(int m);
void makeConnection();
bool isCyclic();
void weave();
void removeDup();
void deleteMiddle();
void partition(int value);
void palindrome();
void sumList(Element *head1, Element *head2);
void createIntersection(LinkedList *L1, LinkedList *L2, LinkedList *L3);
void getIntersection(LinkedList *L1, LinkedList *L2);
};
Insert Front Function
void LinkedList::insertFront(int value)
{
Element *newElem = new Element(value);
if (head == NULL)
{
head = newElem;
tail = newElem;
}
else
{
newElem->setNext(head);
head = newElem;
}
// delete newElem ------------> Adding this line Breaks the complete Linked List
}
Here above I have displayed my Linked List implementation using raw pointers. The problem I am facing is when I add a new element to the list in the front I create a new Element() add it to the list and make necessary adjustments to the list to make sure head is updated.
But when I delete the temporarily created element, it breaks my complete linked list and I am unable to understand why.
If I choose not to delete the temporary element, it creates memory leaks.
Help would be appreciated.
Thank You.
The is fine just as it is, without the call to delete. You say:
If I choose not to delete the temporary element
however, the object pointed to by newElem is not temporary. It is allocated on the heap and is now part of the linked list.
void LinkedList::insertFront(int value)
{
Element *newElem = new Element(value);
if (head == NULL)
{
head = newElem;
tail = newElem;
}
else
{
newElem->setNext(head);
head = newElem;
}
// No need to delete newElem, it is not a temporary object
}
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;
I'm been having trouble with either my constructor or my insert function, I'm not sure which is the issue, but the real issue is that I get the error code mentioning I'm having an error with things getting de-referenced. All I'm trying to do is insert a node containing an integer value in the correct position.
This is the declaration:
template <class T>
class LinkedList
{
template <class T>
struct Node
{
T mData;
Node<T> *mNext;
/* Pre: None
* Post: This object is initialized using default values
* Purpose: To initialize date object
*************************************************************************/
Node()
{
mData = T();
mNext = NULL;
}
/* Pre: None
* Post: This object is initialized using specified data
* Purpose: To intialize date object
*************************************************************************/
Node(T data, Node<T>* next)
{
mData = data;
mNext = next;
}
};
private:
Node<T> *mHead;
int mCount;
public:
LinkedList();
~LinkedList();
int getCount();
T getData(int index);
void setData(int index, T data);
void clear();
void display();
bool insert(T data);
bool isEmpty();
bool isExist(T searchKey);
bool remove(T searchKey);
T removeAt(int index);
T operator[](int index);
void operator=(LinkedList<T> *list);
};
And this is the insert:
template <class T>
bool LinkedList<T>::insert(T data)
{
Node<T>* current = mHead;
if (!current)
{
if (mCount == 0)
{
current->mData = data;
}
else
{
while (current->mNext != NULL)
{
if (current->mData == data)
return false;
else if (current->mNext->mData < data)
{
Node<T>* newNode = new Node<T>();
newNode->mData = data;
newNode->mNext = current->mNext;
current->mNext = newNode;
}
current = current->mNext;
}
}
}
else
{
Node<T>* node = new Node<T>(data, NULL);
current->mNext = node;
}
mCount++;
return true;
}
Every time my program breaks, it's at this line
current->mData = data;
You shouldn't declare Node class as template, in fact you should get a compile error message like error: declaration of 'T' shadows template parameter.
Remove template<class T> from Node and change Node<T> to Node throughout the code.
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) {
}