Every time I add comments inside the definitions of the operators, it starts giving me errors, but removing the comments immediately gets rid of the errors. I don't see why comments would have any effect at all on the code. Also just general advice on the overloading of operators in general would be appreciated.
Heres my class template:
template<class THING>
struct LLNode
{
THING data;
LLNode<THING> *next;
LLNode<THING> *prev;
};
template<class THING>
class LinkedList
{
private:
//use a doubly linked-list based implementation
//keep a head and tail pointer for efficiency
LLNode<THING> *Head;
LLNode<THING> *Tail;
int count;
public:
//setup initial conditions
LinkedList();
//delete all dynamic memory, etc.
~LinkedList();
//constant bracket operator to access specific element
const THING& operator[](int);
//Bracket operator to access specific element
THING& operator[](int);
//Equality operator to check if two lists are equal
bool operator==(const LinkedList<THING>&);
//Inequality operator to check if two lists are equal
bool operator!=(const LinkedList<THING>&);
//add x to front of list
void addFront(THING);
//add x to back of list
void addBack(THING);
//add x as the ith thing in the list
//if there are less than i things, add it to the back
void add(THING, int);
//remove and return front item from list
THING removeFront();
//remove and return back item from list
THING removeBack();
//return value of back item (but don't remove it)
THING getBack();
//return value of front item (but don't remove it)
THING getFront();
//return how many items are in the list
int length();
//print all elements in the linked list
void print();
};
And the operators I'm currently working on:
template<class THING>
THING& LinkedList<THING>::operator[](int index)
{
}
template<class THING>
bool LinkedList<THING>::operator==(const LinkedList<THING>& list_one, const LinkedList<THING>& list_two)
{
//checking for same size on both lists
//if both are same size, move on to checking for same data
if(list_one.count != list_two.count)
{
return false;
}
else
{
//boolean flag to hold truth of sameness
bool flag = true;
//two pointers to go through
LLNode<THING> *temp_one = list_one.Head;
LLNode<THING> *temp_two = list_two.Head;
while(temp_one != NULL && temp_two != NULL)
{
if(temp_one->data != temp_two->data)
{
flag = false;
break;
}
else
{
temp_one = temp_one->next;
temp_two = temp_two->next;
}
}
return flag;
}
}
These, as you've said, aren't compilation errors: they are Intellisense errors. These errors take a while to refresh in the extension and therefore aren't very indicative most of the time, and it's a known issue that Intellisense isn't great with adding comments, and is even worse when colliding with other extensions.
One way to get rid of the errors is to cut-paste all of the code (just go ctrl+a, ctrl+x, ctrl+v). This forces Intellisense to refresh.
Another way which is a personal favorite of mine is to shut down Intellisense :) you can see how to do that in here.
Related
Class:
template <class T>
class vectorADT
{
public:
//default constructor
vectorADT();
//destructor
~vectorADT();
//push data to the front of the vector
void push_front(T data);
//push data to the rear of the vector
void push_back(T value);
void insert(int position, T value);
//remove data from the front of the vector
void remove_front();
//remove data from the rear of the vector
void remove_rear();
//return the front of the vector
T getFront();
//return the rear of the vector
T getRear();
//check if vector is full
bool isFull();
//create a new vector with more space
T *resize(T *prevSizePtr);
//return the size of the vector
int size();
//check if the vector is empty
bool isEmpty();
//print the vectors data
void print();
private:
T *vectPtr;
T array[4] = {};
int front;
int rear;
int vectSize;
};
constructor:
template <class T>
vectorADT<T>::vectorADT()
{
front = 0;
rear = -1;
vectSize = 4;
vectPtr = array;
}
Class Method:
template <class T>
void vectorADT<T>::push_front(T data)
{
if (vectPtr[0] == nullptr)
{
vectPtr[front] = data;
}
front++;
}
I asked a question earlier but I am still really confused on how this works. I want to be able to check if my array has nullptr as a value, that way I know whether that index is empty, and if it is, I can assign that index some data. Whenever I try to make the comparison to nullptr, I get a host of errors about operator==. I thought that when I do T array[4] = {} it would initialize all the index to nullptr or zero, thus making it valid to compare that index with nullptr, however that obviously is not the case. If anyone could point me in the right direction on how I would go about doing something like that I would really appreciate it. Thank you.
Re: I want to be able to check if my array has nullptr as a value, that way I know whether that index is empty - You really don't need to know that. You should maintain a size of your vector that would tell you if there are available slots and where they are. What you call vectSize is in fact its capacity.
My program requires me to create a binary search tree that is also a set. I've got up to inserting items into it and having that work correctly, but my issue comes when I'm attempting to get recursively get the size of the tree, aka how many nodes there are. Below is all the code that matters I believe.
struct SetNode
{
T data;
SetNode<T>* left;
SetNode<T>* right;
SetNode(const T& value);
};
//Set based on a BST
template <class T>
class MySet
{
private:
SetNode<T>* root;
public:
//constructor, insert function, "contains" function declared here
//get number of items contained
int size() const;
int sizeHelper(SetNode<T>* curNode) const;
}
template<typename T>
int MySet<T>::size() const {
if (root == nullptr)
return 0;
else
return this->sizeHelper(root);
}
template<typename T>
int MySet<T>::sizeHelper(SetNode<T>* curNode) const {
return 1 + sizeHelper(curNode->left) + sizeHelper(curNode->right);
}
The issue arises in main after I declare Set<string> setA and attempt to call size with setA.size(). From the debugger, I've seen that this causes the aforementioned SIGSEGV error. I can change the declaration of sizeHelper and even remove it if need be, but other than the code within it, size must remain as it is. Should sizeHelper be a non-member function? Removing the const doesn't work.
Your sizeHelper is a recursive function with no exit condition, you just keep reading the left and right fields from the node you're given, but you never check if they are nullptr. If you do pass nullptr, you have UB and possibly a segfault.
To avoid it you need to add an exit condition like so.
template<typename T>
int MySet<T>::sizeHelper(SetNode<T>* curNode) const {
if (curNode == nullptr) {
return 0;
}
return 1 + sizeHelper(curNode->left) + sizeHelper(curNode->right);
}
I have an iterator class nested in a LinkedList class. My question is how do I make the insert_after function using iterators. The rest of the code is given for information purposes, but the function I'm trying to get working is at the end.
Insert_After takes a position and inserts a value after it.
template <typename T>
class LinkedList : public LinkedListInterface<T> {
private:
struct Node {
T data; // data can be any type
Node* next; // points to the next Node in the list
Node(const T& d, Node* n) : data(d), next(n) {}
};
Node* head; // Is a pointer
class Iterator
{
private:
Node* iNode;
public:
Iterator(Node* head) : iNode(head){ }
~Iterator() {}
bool operator!=(const Iterator& rhs) const { return iNode != rhs.iNode; }
Iterator& operator++() { iNode = iNode->next; return *this; }
T& operator*() const { return iNode->data; }
};
/** Return iterator pointing to the first value in linked list */
Iterator begin(void) {
return LinkedList<T>::Iterator(head);
}
/** Return iterator pointing to something not in linked list */
Iterator end(void) {
return LinkedList<T>::Iterator(NULL);
}
/** Return iterator pointing found value in linked list */
Iterator find(Iterator first, Iterator last, const T& value) {
Iterator current = first;
bool found = false;
while (current != last) {
if (*current == value) {
return current;
}
++current;
}
return last;
}
Iterator insert_after(Iterator position, const T& value)
{
// Need help here
}
What I've tried so far resulted in a few errors.
Iterator insert_after(Iterator position, const T& value)
{
// Need to insert after position
Iterator previous = position;
++position;
Node* newNode = new Node(value, position);
previous->next = newNode;
}
The error I got was Error C2664 'function' : cannot convert argument n from 'type1' to 'type2' for the line
Node* newNode = new Node(value, position);
Compiler Error C2819 type 'type' does not have an overloaded member 'operator ->' for line
previous->next = newNode;
I understand the errors but I'm not sure how to work around them.
I think the short answer to your compiler errors is that you are likely supposed to pass a Node or Node* as your second argument and not an iterator. previous is also an iterator, and therefore does not have a next call.
Long answer below about generally fixing the function in question:
There's a lot [not] going on in that function, which gets me wondering about the rest of the linked list class as well. I've only looked at this function, as it's the one you claim is causing you trouble.
SUBJECTIVE THOUGHT I generally hate working with iterators in my class functions. Deal with the Nodes directly as much as possible. The iterator pattern exists for universal traversal of containers no matter how they're laid out, and that abstraction makes it a pain to deal with inside your class.
Iterator insert_after(Iterator position, const T& value)
{
// Need to insert after position
Iterator previous = position;
++position;
Node* newNode = new Node(value, position);
previous->next = newNode;
}
As it currently stands, if position is anywhere but the last element, you will break your list and leak memory. This is because you never check what is after position. That first mistake leads into the second. newNode->next never gets set. Maybe it's default constructed to nullptr, that's fine. But if I'm inserting into the middle of my list, I need to connect newNode to whatever came after position originally.
Another question that you need to consider is "what if this is called on an empty list?" Does your begin() function handle that? Is it supposed to throw?
Iterator insert_after(Iterator position, const T& value)
{
Node* pos = position.iNode;
if (!pos) { // assumes an empty list if this is true
// Correctly build first Node of your list and get everything assigned
// that you can
// return the new iterator;
// or just throw
}
if (!pos->next) { // position at end of list if true
pos->next = new Node(value, position); // Is that second argument
// supposed to be an iterator?
return Iterator(pos->next);
} else {
// Some of this is probably redundant depending on how you are actually
// building Nodes, but the gist is it's important to ensure the list is
// not broken; connecting tmp before changing existing nodes helps the
// list stay intact for as long as possible
Node* tmp = new Node(value, position);
tmp->next = pos->next;
pos->next = tmp;
return Iterator(tmp);
}
A doubly linked list never seems attractive at first blush to a student, but it makes certain operations like erasing from the middle of the list so much easier. Yes, you have one extra pointer to deal with, but it makes it harder to lose Nodes as well. Along with bi-directional iteration.
I had an assignment today and I'm really struggling trying to find a solution.
"Using a Binary-Search-Tree based priority queue, implement Huffman Coding [...]".
So, basically, I have to write my own priority queue based on a Binary Search Tree.
I managed to get a working BST and so on, but I've been really smashing my head against every wall In my room for the last two-tree days for the second part.
And that's Huffman's fault (Just kidding, I know I'm kinda stupid).
In Huffman Algorithm, we create a priority queue, fill it with our N starting elements, then we pop() the 2 nodes with minimum frequences, create a new node whose frequence is the sum of the previously popped elements and push() that node into the priority queue and reiterate[...].
To make my BST into a priority queue, I added one member and two methods: min,getMin() and extractMin().
min is a pointer to the node whose value is the lowest in the tree.
getMin() is a method that starts from a given node, and looks for the minimum value in its left subtree.
Please, note that everytime a node gets removed or a new node inserted, it calls an update of the min variable of the tree (a new inserted node could have a lower value than the previous min, so mingets updated, and the node pointer by min could be removed, somin gets updated).
extractMin() is basically a wrapper for pQueue.remove(pQueue.getMin()).
The thing is this: after popping the two elements with lowest frequency, and creating the new node, inserting it in the tree causes a min update. Since the left and right members of the new inserted node have a lower frequence than the inserted note itself, the min variable is set to one of those two members. I am struggling to find a solution to this. I don't want code or lines, I just want some ideas because I really ran out of patience and intelligence.
Following, my BST class and a snippet of the Huffman code I wrote. Please, be kind, I'm new to coding.
template <class T>
class BST
{
private:
void setRoot(bstNode<T>* nd){this->root=nd;}
bool isEmpty()const{if (this->getRoot()==nullptr) return true; else return false;}
protected:
bstNode<T>* root;
bstNode<T>* min;
public:
BST(void){this->root=nullptr;this->min=nullptr;}
BST(bstNode<T>* rt){this->root=rt;}
~BST(void){this->root=nullptr;};
void inorder(bstNode<T>*) const;
void insert(bstNode<T>*);
bool remove(bstNode<T>*);
void extractMin();
bstNode<T>* getRoot()const {return this->root;}
bstNode<T>* getMin(bstNode<T>*)const;
bstNode<T>* getMin()const {return this->min;} //simply returns a pointer to the minimum
void setMin(bstNode<T>* nd){this->min=nd;}
};
template <class T>
void BST<T>::extractMin()
{
if (this->getMin()!=nullptr)
this->remove(this->getMin());
else return;
}
template <class T>
void BST<T>::insert(bstNode<T>* nd)
{
if (this->isEmpty()==true)
{
this->setRoot(nd);
this->setMin(nd);
return;
}
else
{
bstNode<T>* up=nullptr;
bstNode<T>* actual=this->getRoot();
while (actual!=nullptr)
{
up=actual;
if(nd->getValue()<=actual->getValue())
actual=actual->getLeft();
else actual=actual->getRight();
}
nd->setParent(up);
if (nd->getValue()<=up->getValue())
up->setLeft(nd);
else up->setRight(nd);
}
if (nd->getValue()<=this->getMin()->getValue())
this->setMin(nd);
}
template <class T>
bool BST<T>::remove(bstNode<T>* nd)
{
if (nd==this->getMin())
this->setMin(nullptr);
if (nd==this->getRoot() && nd->getRight()==nullptr && nd->getLeft()==nullptr)
{
this->setRoot(nullptr);
return true;
}
if (nd==this->getRoot() && nd->getRight()!=nullptr)
this->setRoot(nd->getRight());
else if( nd==this->getRoot() && nd->getLeft()!=nullptr)
this->setRoot(nd->getLeft());
bstNode<T>* Root=this->getRoot();
bstNode<T>* temp, *temp2;;
if (nd->getLeft()==nullptr)
this->swapTree(Root,nd,nd->getRight());
else if (nd->getRight()==nullptr)
this->swapTree(Root,nd,nd->getLeft());
else
{
temp=this->getMin(nd->getRight());
if (temp->getParent()!=nd)
{
this->swapTree(Root,temp,temp->getRight());
temp->setRight(nd->getRight());
temp2=temp->getRight();
temp2->setParent(temp);
}
this->swapTree(Root,nd,temp);
temp->setLeft(nd->getLeft());
temp2=temp->getLeft();
temp2->setParent(temp);
}
this->setMin(this->getMin(this->getRoot()));
return true;
}
template <class T>
bstNode<T>* BST<T>::getMin(bstNode<T>* nd)const //find and return the minimum of the tree whose root is nd
{
while (nd->getLeft()!=nullptr)
nd=nd->getLeft();
return nd;
}
and here's the Huffman part:
template <class T>
class Encoder
{
private:
std::vector <myTuple> *alphabet; //vector of tuples <fequency,character, isInternal>
void createPqueue();
void createAlphabet();
void encode();
void showHuff(bstNode<T>*, string);
BST<T> *hTree;
public:
Encoder(){createAlphabet();createPqueue();};
~Encoder(){};
std::vector <myTuple> * getAlphabet()const{return this- >alphabet;}
BST<T> *getPqueue()const{return this->hTree;}
void askWhat();
};
template <class T>
void Encoder<T>::createPqueue()
{
this->hTree=new BST<myTuple>();
if (this->hTree==nullptr)
{
cout<<"Error allocating Red-Black Tree, now exiting..."<<endl;
exit(-1);
}
}
for (unsigned int i = 0; i < this->getAlphabet()->size(); ++i)
{
bstNode<myTuple>* temp;
temp=new bstNode<myTuple>(this->getAlphabet()->at(i));
if (temp!=nullptr)
this->getPqueue()->insert(temp); //fill the priority Queue with <int frequency, char character, bool is_internal> Nodes. I still have to remove tuples since they are not necessary anymore.
else
exit(-1);
}
bstNode<myTuple> *left, *right, *top;
for (unsigned int i = 0; i< u_int(this->getAlphabet()->size())-2;i++)
{
left=this->getPqueue()->getMin();
this->getPqueue()->extractMin();
right=this->getPqueue()->getMin();
this->getPqueue()->extractMin();
myTuple temp ((get<0>( left->getValue() ) + get<0>( right->getValue() )),'\0',true);
top=new bstNode<myTuple>(temp);
if (top==nullptr)
{
cout <<"Can't allocate top, now exiting..."<<endl;
exit(-1);
}
top->setLeft(left);
top->setRight(right);
this->getPqueue()->insert(top);
}
I've been using the bool value in tuples to distinguish between internal and external nodes, but with no success.
Thank you in advance and I'm really sorry if I've been messy, my clearness equals my state of mind as of now. Thank you.
Since most of the ppl like puzzles I,ll start this question with a (bad spelling :))gotw like introduction, note that if you dont care about it you can skip the warmup(JG question) and read the G question since that is my "real SO question".
During review of the code samples provided by potential new employees
you stumbled upon a linked list whose implementation uses modern C++11
feature, an std::unique_ptr<>.
template <typename T>
struct Node {
T data;
std::unique_ptr<Node<T>> next;
Node () {}
Node(const T& data_): data(data_) {}
Node(Node& other) { std::static_assert(false,"OH NOES"); }
Node& operator= (const Node& other) {
std::static_assert(false,"OH NOES");
return *new Node();
}
public:
void addNext(const T& t) {
next.reset(new Node<T>(t));
}
};
template<typename T>
class FwdList
{
std::unique_ptr<Node<T>> head;
public:
void add(const T& t)
{
if (head == nullptr)
head.reset( new Node<T>(t));
else {
Node<T>* curr_node = head.get();
while (curr_node->next!=nullptr) {
curr_node = curr_node->next.get();
}
curr_node->addNext(t);
}
}
void clear() {
head.reset();
}
};
JG question:
Determine(ignoring the missing functionality) problem(s) with this
code.
G question: (added 2. based on answers)
1.
Is there a way to fix the problem(s) detected in JG part of the
question without the use of raw pointers?
2.
Does the fix work for the containers where node contain more than one pointer(for example binary tree has pointers to left and right child)
Answers:
JG :
stackoverflow :). Reason:recursion of the unique_ptr<> destructors
triggered by .clear() function.
G:
(???) I have no idea, my gut feeling is no, but I would like to check with
the experts.
So long story short: is there a way to use smart pointers in node based structures and not end up with SO problems? Please don't say that trees probably wont get too deep, or something like that, im looking for general solution.
You can clear it iteratively, making sure that each node's next pointer is empty before destroying the node:
while (head) {
head = std::move(head->next);
}
A binary tree is trickier; but you can flatten it into a list by iteratively cutting off right-hand branches and adding them to the bottom left, something like this:
node * find_bottom_left(node * head) {
while (head && head->left) {
head = head->left.get();
}
return head;
}
node * bottom = find_bottom_left(head.get());
while (head) {
bottom->left = std::move(head->right);
bottom = find_bottom_left(bottom);
head = std::move(head->left);
}