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) {
}
Related
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.
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 am implementing a queue data structure, but my app crashes. I know I am doing something wrong with Node pointer front or Front() method of queue class
#include <iostream>
using namespace std;
class Node
{
public:
int get() { return object; };
void set(int object) { this->object = object; };
Node * getNext() { return nextNode; };
void setNext(Node * nextNode) { this->nextNode = nextNode; };
private:
int object;
Node * nextNode;
};
class queue{
private:
Node *rear;
Node *front;
public:
int dequeue()
{
int x = front->get();
Node* p = front;
front = front->getNext();
delete p;
return x;
}
void enqueue(int x)
{
Node* newNode = new Node();
newNode->set(x);
newNode->setNext(NULL);
rear->setNext(newNode);
rear = newNode;
}
int Front()
{
return front->get();
}
int isEmpty()
{
return ( front == NULL );
}
};
main()
{
queue q;
q.enqueue(2);
cout<<q.Front();
system("pause");
}
You're using uninitialized pointers on several occasions.
Enqueue refers to rear->setNext(). If the queue is empty, rear is uninitialized, leading to crashes.
Front returns the node by some Node member-function without checking for a non-null pointer. Why not simply return the *front pointer?
None of your classes have a constructor. Your pointers aren't even NULL-pointers, they're just uninitialized. That's asking for troubles.
My advice:
Give both classes a constructor.
When calling ANY Node member-function, check for valid pointers.
Use less Node member-functions; returns raw pointers when you can.