"Cannot find symbol - method add" error with LinkedList - singly-linked-list

I'm trying to use the add method to add elements to a LinkedList. This is what the code looks like:
/**
* A singly linked list.
*
* #author
* #version
*/
public class LinkedList<T> {
private ListElement<T> first; // First element in list.
private ListElement<T> last; // Last element in list.
public LinkedList<T> asd;
private int size; // Number of elements in list.
/**
* A list element.
*/
private static class ListElement<T> {
public T data;
public ListElement<T> next;
public ListElement(T data) {
this.data = data;
this.next = null;
}
}
/**
* This TEST METHOD returns true if the following invariants hold:
* <ul>
* <li> size equals the number of list elements, </li>
* <li> if size == 0, first == null and last == null, </li>
* <li> if size > 0, first != null and last != null, </li>
* <li> if size == 1, first == last, </li>
* <li> last.next == null. </li>
* </ul>
*/
public boolean isHealthy() {
return false;
}
/**
* Creates an empty list.
*/
public LinkedList() {
asd = new LinkedList<T>();
}
/**
* Inserts the given element at the beginning of this list.
*/
public void addFirst(T element) {
asd.add(element);
}
/**
* Inserts the given element at the end of this list.
*/
public void addLast(T element) {
}
/**
* Returns the first element of this list.
* Returns <code>null</code> if the list is empty.
*/
public T getFirst() {
// TODO
return null;
}
/**
* Returns the last element of this list.
* Returns <code>null</code> if the list is empty.
*/
public T getLast() {
return null;
}
/**
* Returns the element at the specified position in this list.
* Returns <code>null</code> if <code>index</code> is out of bounds.
*/
public T get(int index) {
return null;
}
/**
* Removes and returns the first element from this list.
* Returns <code>null</code> if the list is empty.
*/
public T removeFirst() {
return null;
}
/**
* Removes all of the elements from this list.
*/
public void clear() {
}
/**
* Returns the number of elements in this list.
*/
public int size() {
return 0;
}
/**
* Returns <code>true</code> if this list contains no elements.
*/
public boolean isEmpty() {
return false;
}
/**
* Returns a string representation of this list. The string
* representation consists of a list of the elements enclosed in
* square brackets ("[]"). Adjacent elements are separated by the
* characters ", " (comma and space). Elements are converted to
* strings by the method toString() inherited from Object.
*/
public String toString() {
return null;
}
}
The problem is that when I try to compile, it generates a "cannot find symbol - method add(T)" error message. I can't see why it wouldn't work, but I'm new to Java so I'd like some help on this.

Yes, LinkedList has add method but the problem is you are not importing java.util.LinkedList. You are implementing your own LinkedList. So either implement a add method for your class, or you can easily use import java.util.LinkedList without implementation.

Related

How to iterate over a template class?

I'm trying to create a generic menu class that will be used with a 4 line LCD.
I have a specific (non template) version working, but want to extend it to allow the menu to modify a variety of data types (int, float, unsigned...).
Here's the non template version that's working as expected...
/*
* ideally this design allows for defining an arbitrary menu as shown below
* example...
* root1
* sub1-1
* sub1-2
* root 2
* root 3
* sub3-1
* sub3-2
* sub3-2-1
* sub3-2-2
*
* each node in the menu can be executed, and allow for moving to the next/prev sibling or child/parent
* this flexibility requires that each node contains pointers to parent, child, and sibling nodes.
*/
class MenuNode
{
private:
char *prompt;
int value;
public:
MenuNode *parent=NULL;
MenuNode *child=NULL;
MenuNode *prevSibling=NULL;
MenuNode *nextSibling=NULL;
void SetValue(int value)
{
this->value = value;
}
int GetValue()
{
return value;
}
char *Prompt()
{
return prompt;
}
MenuNode(char *prompt, int initialValue, MenuNode *parent, MenuNode *prevSibling)
{
Serial.print(prompt);Serial.println(F(" MenuNode"));
this->prompt = prompt;
if (prevSibling != NULL)
{
this->prevSibling = prevSibling;
prevSibling->SetNextSibling(this);
this->parent = prevSibling->parent;
}
// prevSibling if provided sets the parent
if (prevSibling==NULL && parent != NULL)
{
this->parent = parent;
this->parent->SetChild(this);
}
value = initialValue;
}
void SetChild(MenuNode *child)
{
Serial.print(prompt);Serial.println(F(" SetChild"));
this->child = child;
}
void SetNextSibling(MenuNode *nextSibling)
{
Serial.print(prompt);Serial.println(F(" SetNextSibling"));
this->nextSibling = nextSibling;
}
};
Here's some test code that creates the menu structure...
// Test menu...
MenuNode r1("R1",10,NULL,NULL);
MenuNode r2("R2",20,NULL,&r1);
MenuNode r21("R21",30,&r2,NULL);
MenuNode r22("R22",40,&r2,&r21); // setting parent is optional, the parent will be set by the prev sibling parent
MenuNode r221("R221",50,&r22,NULL);
MenuNode r2211("R2211",60,&r221,NULL);
MenuNode r2212("R2212",70,NULL,&r2211);
MenuNode r3("R3",30,NULL,&r2);
This code iterates over each element printing out the structure
void PrintMenuStructure(MenuNode *node,int offset)
{
while(node != NULL)
{
for (int i=0;i<offset;i++)
Serial.print("-");
Serial.print(node->Prompt());
Serial.print(" = ");
Serial.print(node->Value());
if (node->parent != NULL)
{
Serial.print(" parent=");
Serial.print(node->parent->Prompt());
}
if (node->prevSibling != NULL)
{
Serial.print(" prevSib=");
Serial.print(node->prevSibling->Prompt());
}
if (node->nextSibling != NULL)
{
Serial.print(" nextSib=");
Serial.print(node->nextSibling->Prompt());
}
if (node->child != NULL)
{
Serial.print(" child=");
Serial.print(node->child->Prompt());
}
Serial.println();
if (node->child != NULL)
PrintMenuStructure(node->child,++offset);
node = node->nextSibling;
}
}
This is the output of the previous function demonstrating the structure of the menu...
R1 = 10 nextSib=R2
R2 = 20 prevSib=R1 nextSib=R3 child=R21
-R21 = 30 parent=R2 nextSib=R22
-R22 = 40 parent=R2 prevSib=R21 child=R221
--R221 = 50 parent=R22 child=R2211
---R2211 = 60 parent=R221 nextSib=R2212
---R2212 = 70 parent=R221 prevSib=R2211
-R3 = 30 prevSib=R2
It all works the way I want, but GetValue/SetValue only operate on int data.
I can create a template version of the class, with the data types of GetValue and SetValue defined by the template parameter, but I don't know now to iterate over the nodes once I do that.
Seems like a simple enough task, but I've been beating my head against the wall for a while, and haven't come up with anything that works. Any help pointing me in the right direction would be appreciated.
I'm trying to figure out how to iterate over a linked list of classes, but can't figure out how to get a pointer to start iterating.
Sorry, I couldn't get the code formatting to work... :(
The way I interpret your requirement: it seems your should make your
int value;
a std::variant.
That's the lowest cost path.
If you templatize the MenuNode class with its value type. Then a MenuNode<int>* cannot be the parent of a MenuNode<float*>, etc. Not without some effort. You'd probably better off make it polymorphic by derivate each type of value your want to support from a common abstract virtual base, and depend on how you want to use the value, design your interface.

How do I adjust my code to access the original member and not a copy of it?

I have a class called Child that holds a name and a list of string items. Different child objects are stored in a separate list, sort of as a nested list. The representation is:
List<"Child"> [Child1(name, List<"string">), Child2(name, List<"string">), etc.]
My objective is to create two functions: insertChild() and insertPresent(). The first one works, where the idea is to insert a child object into List(Child) with a specified name and List<"string">. Where I'm having trouble is with insertPresent(), where it is supposed to search List<"Child"> given a name and, once there's a match, add a present (string) to that Child object's List<"string">.
The problem appears to be I'm accessing a local copy of the List<"string"> when calling getList(), which explains why there appears to be no errors and the original list remains untouched after calling insertPresent(). How do I implement the changes to access the original list and not the copy? Here's the code:
ArrayList.h:
template<class ItemType>
class ArrayList
{
private:
static const int DEFAULT_CAPACITY = 5; // Small capacity to test for a full list
ItemType items[DEFAULT_CAPACITY]; // Array of list items
protected:
int itemCount; // Current count of list items
int maxItems; // Maximum capacity of the list
public:
ArrayList();
// Copy constructor and destructor are supplied by compiler
bool isEmpty() const;
int getLength() const;
bool insert(int newPosition, const ItemType& newEntry);
bool remove(int position);
void clear();
/** #throw PrecondViolatedExcep if position < 1 or
position > getLength(). */
ItemType getEntry(int position) const throw(PrecondViolatedExcep);
/** #throw PrecondViolatedExcep if position < 1 or
position > getLength(). */
void setEntry(int position, const ItemType& newEntry) throw(PrecondViolatedExcep);
}; // end ArrayList
template<class ItemType>
ArrayList<ItemType>::ArrayList() : itemCount(0), maxItems(DEFAULT_CAPACITY)
{
} // end default constructor
template<class ItemType>
bool ArrayList<ItemType>::isEmpty() const
{
return itemCount == 0;
} // end isEmpty
template<class ItemType>
int ArrayList<ItemType>::getLength() const
{
return itemCount;
} // end getLength
template<class ItemType>
bool ArrayList<ItemType>::insert(int newPosition, const ItemType& newEntry)
{
bool ableToInsert = (newPosition >= 1) && (newPosition <= itemCount + 1) &&
(itemCount < maxItems);
if (ableToInsert)
{
// Make room for new entry by shifting all entries at
// positions >= newPosition toward the end of the array
// (no shift if newPosition == itemCount + 1)
for (int pos = itemCount; pos >= newPosition; pos--)
items[pos] = items[pos - 1];
// Insert new entry
items[newPosition - 1] = newEntry;
itemCount++; // Increase count of entries
} // end if
return ableToInsert;
} // end insert
template<class ItemType>
bool ArrayList<ItemType>::remove(int position)
{
bool ableToRemove = (position >= 1) && (position <= itemCount);
if (ableToRemove)
{
// Remove entry by shifting all entries after the one at
// position toward the beginning of the array
// (no shift if position == itemCount)
for (int fromIndex = position, toIndex = fromIndex - 1; fromIndex < itemCount;
fromIndex++, toIndex++)
items[toIndex] = items[fromIndex];
itemCount--; // Decrease count of entries
} // end if
return ableToRemove;
} // end remove
template<class ItemType>
void ArrayList<ItemType>::clear()
{
itemCount = 0;
} // end clear
template<class ItemType>
ItemType ArrayList<ItemType>::getEntry(int position) const throw(PrecondViolatedExcep)
{
// Enforce precondition
bool ableToGet = (position >= 1) && (position <= itemCount);
if (ableToGet)
return items[position - 1];
else
{
string message = "getEntry() called with an empty list or ";
message = message + "invalid position.";
throw(PrecondViolatedExcep(message));
} // end if
} // end getEntry
template<class ItemType>
void ArrayList<ItemType>::setEntry(int position, const ItemType& newEntry) throw(PrecondViolatedExcep)
{
// Enforce precondition
bool ableToSet = (position >= 1) && (position <= itemCount);
if (ableToSet)
items[position - 1] = newEntry;
else
{
string message = "setEntry() called with an empty list or ";
message = message + "invalid position.";
throw(PrecondViolatedExcep(message));
} // end if
} // end setEntry
Child.h:
#include "ArrayList.h"
class Child
{
private:
string name;
ArrayList<string> presents;
public:
string getName() const;
ArrayList<string> getList() const;
void setName(string name);
void setList(ArrayList<string> aList);
};
string Child::getName() const {
return name;
}
ArrayList<string> Child::getList() const {
return presents;
}
void Child::setName(string name) {
this->name = name;
}
void Child::setList(ArrayList<string> aList) {
this->presents = aList;
}
NiceArrayList.h: List<"Child">
#include <string>
#include "Child.h"
using namespace std;
template<class ItemType>
class NiceArrayList : public ArrayList<ItemType>
{
public:
/** Inserts an object containing name and aList into this list at a given position.
#pre None.
#post If 1 <= position <= getLength() + 1 and the insertion is
successful, name and aList is at the given position in the nice list,
other entries are renumbered accordingly, and the returned
value is true.
#param position The list position at which to insert the object.
#param name The string assigned to the object inserted into this list.
#param aList The list assigned to the object inserted into this list.
#return True if insertion is successful, or false if not. */
bool insertChild(int position, string name, const ArrayList<string>& aList);
/** Inserts a new entry to the gift list inside an object from this
list given a name.
#pre The parameter name must be in an object in this list.
#post If 1 <= position <= getLength() + 1 and the insertion is
successful, newEntry is at the given position in the gift list,
other entries are renumbered accordingly, and the returned
value is true.
#param position Theobject list position at which to insert the new entry.
#param name The string used to identify the object in this list.
#param newEntry The entry to insert into the object's list.
#return True if removal is successful, or false if not. */
bool insertPresent(string name, string newEntry);
};
template<class ItemType>
bool NiceArrayList<ItemType>::insertChild(int position, string name, const ArrayList<string>& aList) {
bool ableToInsert = false;
Child aChild;
aChild.setName(name);
aChild.setList(aList);
ableToInsert = this->insert(position, aChild);
return ableToInsert;
}
template<class ItemType>
bool NiceArrayList<ItemType>::insertPresent(string name, string newEntry) {
bool ableToInsert = false;
int length = this->getLength();
int position = 0;
for (int i = 1; i <= length; i++) {
position++;
if (this->getEntry(i).getName() == name) {
break;
}
}
//THE PROBLEM APPEARS TO BE HERE! THE INSERT DOES NOT UPDATE THE LIST!
ableToInsert = this->getEntry(position).getList().insert(1, newEntry);
return ableToInsert;
}
Sample main to test:
#include <iostream>
#include "NiceArrayList.h"
int main() {
ArrayList<string> aList1;
aList1.insert(1, "PS4");
aList1.insert(2, "PS5");
aList1.insert(3, "Toy Car");
NiceArrayList<Child> nice;
nice.insertChild(1, "John", aList1);
nice.insertPresent("John", "Phone");
return 0;
}
Your problem is here
ArrayList<string> Child::getList() const {
return presents;
}
This is returning a copy of presents, So thios line only updates the copy
ableToInsert = this->getEntry(position).getList().insert(1, newEntry);
You need
ArrayList<string> & Child::getList() {
return presents;
}
Note the removal of the const too
and here
ArrayList<string> &getList() ;
same for getEntry on ArrayList, same fix
The API you defined for ArrayList does provide the basic operations of adding items, removing items, and changing items. However, the paradigm you chose for changing items can be awkward to use and – as you discovered – easy to mess up. It is not wrong, per se, since it is a good choice in some situations, but it does not appear to bring any of its benefits to your situation.
Since it is a valid approach, I will go over how to fix the code using the existing paradigm before going over an alternative paradigm.
Your way
Under your approach, changing an element of a list requires calling setEntry(). You are not allowed to directly change an element, but must make a copy (obtained via getEntry()), modify the copy, then update the list with setEntry().
Let us look at the line where you try to make your change.
ableToInsert = this->getEntry(position).getList().insert(1, newEntry);
This follows two of the three steps for making a change. There is a call to this->getEntry(position) to make a copy of the Child object. Then there is a change made to that copy (via .getList().insert(1, newEntry)), but the changed object is never given to the NiceArrayList as an update.
To update an element with your paradigm, you need to add a call to setEntry(). Given how your API is configured, this necessitates defining additional variables to help out. (Note, though, that even if this was not necessary, defining at least one of these variables would probably be a good idea style-wise, since this line is already quite long, and we intend to add code.)
// The first three lines split the existing line into pieces.
ItemType toChange = this->getEntry(position);
auto theList = toChange.getList();
ableToInsert = theList.insert(1, newEntry);
// The next lines update the child and list.
toChange.setList(theList);
this->setEntry(position, toChange);
Inserting an element into the presents list (a.k.a. getList()) is a change to that list, which in turn is a change to the Child object (a.k.a. ItemType). This new call to setEntry() replaces the object in the list with the changed copy.
Alternative way
The line of code you used to try to update the presents list would be correct if you adopt a different paradigm for changing a list. Instead of requiring a get/set pair of function calls, you could allow direct access to the elements of an ArrayList, similar to how [] allows direct access to the elements of an array. Instead of having getEntry() return a copy of an entry, it could return a reference to the entry.
If you adopt this paradigm, you could replace the setEntry() function with a non-const version of getEntry(). This would change code that changes entries in an ArrayList from something like setEntry(i, object); to something like getEntry(i) = object;. In more complex cases, you could modify an entry directly, much like you attempted to do in your version of insertPresent().
The new signature of your "get" function would look like the following.
const ItemType & getEntry(int position) const throw(PrecondViolatedExcep);
// ^^^^^ ^
Other than this change to the return type, the implementation would remain the same. (Well, you might want to get rid of throw(PrecondViolatedExcep), as that syntax was deprecated in C++11 and removed in C++17.)
The non-const version of this function could piggy-back on the const version's functionality.
ItemType & getEntry(int position) {
// Trick to invoke the const version of this function:
auto constThis = const_cast<const ArrayList *>(this);
return const_cast<ItemType &>(constThis->getEntry(position));
}
(Don't forget that you can remove setEntry() once this is defined. This can be a net reduction in lines of code.) This approach tends to be more intuitive to work with and less prone to bugs when used.
A similar change should be made to Child::getList() and Child::setList(). With these changes, your version of insertPresent() should work as-is, and you may find that working with these "get" functions is more intuitive than your original approach.
getList() was returning a copy of the sublist, so I turned the presents attribute into a pointer of the list array and made getList() return a reference to the array. Updated Child class:
Child.h:
#include "ArrayList.h"
class Child
{
private:
string name;
ArrayList<string>* presents;
public:
string getName() const;
ArrayList<string>& getList() const;
void setName(string name);
void setList(ArrayList<string>& aList);
};
string Child::getName() const {
return name;
}
ArrayList<string>& Child::getList() const{
return *presents;
}
void Child::setName(string name) {
this->name = name;
}
void Child::setList(ArrayList<string>& aList) {
this->presents = &aList;
}

underflow + right rotation of a BTree

Was wondering if you guys could provide/assist me with concise solutions to determine whether a BTree underflows, and whether or not you could complete a right rotation on it. Bit confused as to the process of arriving at it. Don think it's as easy as just comparing the two unsigned values (particularly for underflow).
BTreeNode.h:
#ifndef BTREENODE_H
#define BTREENODE_H
#include <string>
#include <vector>
struct BTreeNode {
bool is_leaf_ = true;
std::vector<int> elements_;
std::vector<BTreeNode*> children_;
BTreeNode() {}
BTreeNode(std::vector<int> v) {
this->elements_ = v;
}
/**
* Fix the underflow child node at idx by rotating right
* (borrowing a node from left sibling).
* #param idx The underflow child to be fixed is at children_[idx].
* #return If the rotation can be done.
*/
bool rotateRight(unsigned idx, unsigned order);
};
/**
* Check if the given number of elements in a BTree node underflows.
* #param numElem Number of elements in this node.
* #param order The order of the BTree.
* #return True if it underflows, False otherwise.
*/
bool underflows(unsigned numElem, unsigned order);
/**
* A special case for removing an element from BTree. Assume elem
exists in leaf.
* #param item The element to be removed.
* #param parent The parent node that contains the leaf node as a
child.
* #param leaf_idx The leaf BTreeNode idx that contains the element to
be removed.
* #return If the removal is successful.
*/
bool removeFromLeaf(int item, BTreeNode* parent, unsigned leaf_idx,
unsigned order);
#endif
BTreeNode.cpp:
#include "BTreeNode.h"
#include <assert.h>
#include <algorithm>
#include <iostream>
/**
* Check if the given number of elements in a BTree node underflows.
* #param numElem Number of elements in this node.
* #param order The order of the BTree.
* #return True if it underflows, False otherwise.
*/
bool underflows(unsigned numElem, unsigned order) {
return false;
}
/**
* Fix the underflow child node at idx by rotating right
* (borrowing a node from left sibling).
* #param idx The underflow child to be fixed is at children_[idx].
* #return If the rotation can be done.
*/
bool BTreeNode::rotateRight(unsigned idx, unsigned order) {
/**
* First check if there is a left sibling.
* If there is not, simply return false because rotateRight cannot
be done.
*/
if (idx <= 0) return false;
/**
* Then check if the left sibling leaf contains enough elements
after one being borrowed.
*/
BTreeNode* prev = children_[idx - 1];
if (underflows(prev->elements_.size() - 1, order)) {
/**
* If it's not enough, this case cannot be handled by
rotateRight.
* Simply return false.
*/
return false;
}
/**
* Do the right rotation by stealing one element from left sibling
* and fixing the parent key.
*
* Example: Assume we are doing rotateRight around (40) to fix
right child
* (we are in BTreeNode(40), idx = 1 (the second child)),
* | 40 |
* / \
* | 10 | 20 | 30 | | 60 |
*
* after rotation, the tree should look like
* | 30 |
* / \
* | 10 | 20 | | 40 | 50 |
*
*/
// TODO: do the right rotation here
return true;
}
bool removeFromLeaf(int item, BTreeNode* parent, unsigned leaf_idx,
unsigned order) {
// sanity checks
assert(!parent->is_leaf_);
assert(leaf_idx < parent->children_.size());
BTreeNode* leaf = parent->children_[leaf_idx];
assert(leaf->is_leaf_);
std::vector<int>& elems = leaf->elements_;
std::vector<int>::iterator pos = std::find(elems.begin(),
elems.end(), item);
assert(pos != elems.end());
std::cout << "removing " << item << "..." << std::endl;
// delete item, shift other items, shrink the size
elems.erase(pos);
std::cout << "Does the node underflow? ";
// call rotateRight if current leaf node underflows
if (underflows(elems.size(), order)) {
std::cout << "Yes!" << std::endl;
return parent->rotateRight(leaf_idx, order);
}
std::cout << "No!" << std::endl;
return true;
}

Binary Tree: iterative inorder print

I've written a Red-Black Tree implementation, with built-in in-order traversal (using nested class Iterator).
I am looking for an (iterative, if possible) algorithm that prints the binary tree graphically using in-order traversal.
Printing orientation isn't relevant, i.e. the tree in the command-line output can be oriented (formatted) like this:
2
/ \
1 4
/ \
3 5
or like this:
|1
|
|
2
| |3
| |
|4
|
|5
or even upside-down, but the tree should be printed using in-oder traversal, using methods provided below:
void Iteraor::first(); // Traverses to the first node.
void Iterator::next(); // Traverses to the next node.
void Iterator::last(); // Traverses to the last node.
so it's possible so make something like this:
RBTree tree;
/* Tree init. */
Iterator from(&tree), until(&tree);
from.first();
until.last();
for (Iterator i = from; i != until; i.next()) {
// PRINTING.
}
This is the original code:
/** A program for Red-Black Tree manipulation: insertion and value retrieval.
* All position relations (first, last, previous, next) are in-order.
*/
class RBTree {
struct Node {
enum class Colour : bool { RED, BLACK };
int value;
Node *left, *right, *parent;
Colour colour;
public:
/* ... */
};
class Iterator {
class Stack {
/* ... */
};
Stack stack;
const RBTree* const tree; // Once set, neither the reference nor the referenced object's attributes can be modified.
Node* pointer;
public:
Iterator(const RBTree*);
void first();
void next();
void last();
/* ... */
Node* getNode() const;
bool operator != (const Iterator&) const;
};
Node *root;
Iterator iterator;
public:
RBTree() : root(nullptr), iterator(this) {}
/* ... */
bool printTree() const;
~RBTree() { deleteTree(); }
};
// TREE // public: //
/* ... */
bool RBTree::printTree() const {
if (root != nullptr) {
// print ??
return true;
}
else
return false;
}
// NODE: Ensures the proper connection. //
void RBTree::Node::setLeft(Node *p_left) {
left = p_left;
if (p_left != nullptr)
p_left->parent = this;
}
void RBTree::Node::setRight(Node *p_right) {
right = p_right;
if (p_right != nullptr)
p_right->parent = this;
}
// ITERATOR //
RBTree::Iterator::Iterator(const RBTree* p_tree) : tree(p_tree), pointer(p_tree->root) {}
// Traverses to the first node (leftmost).
void RBTree::Iterator::first() {
if (pointer != nullptr) {
while (true) {
if (pointer != nullptr) {
stack.push(pointer);
pointer = pointer->left;
}
else {
pointer = stack.peek();
break;
}
}
}
}
// Traverses to next node in-order.
void RBTree::Iterator::next() {
if (pointer != nullptr) {
if (!stack.isEmpty()) {
pointer = stack.pop();
if (pointer->right != nullptr) {
pointer = pointer->right;
first();
}
}
}
}
// Traverses to the last node (rightmost).
void RBTree::Iterator::last() {
pointer = tree->root;
if (pointer != nullptr)
while (pointer->right != nullptr)
pointer = pointer->right;
stack.clear();
}
/* ... */
RBTree::Node* RBTree::Iterator::getNode() const {
return pointer;
}
bool RBTree::Iterator::operator != (const Iterator& p_iterator) const {
return pointer != p_iterator.pointer ? true : false;
}
I have studied the responses at a similar question, but none of the algorithms utilizes the in-order traversal (and most of them are recursive).
EDIT:
Folowing #nonsensickle's advice, the code is clipped down to bare minimum.
The canonical method for in-order traversal using an iterative algorithm is to maintain a stack (or LIFO queue) of the nodes you need to print. Each loop iteration does one of two things:
If you aren't at a leaf, push the current node onto the stack and move on to its leftmost child.
If you are at a leaf, print it, pop the top node off of the stack, print that, and move on to its rightmost child.
You continue until your stack is empty and you're at a leaf.
The formatting, and the generation of the graphical representation of the internode branches, are obviously up to you. Keep in mind that it will require some extra state variables.
EDIT
What I mean by "some extra state variables" is this.
To provide for pretty-printing, you need to keep track of three things:
What level of the tree your current node-to-print is on (counting from the bottom). This tells you (part of) how far to indent it (or offset it from the edge of your canvas, if you're using a 2D drawing library).
Whether your current node-to-print is a left- or right-child. This tells you (again) how far to indent it from its sibling, and also the orientation of the branch connecting it with its parent.
How many nodes away from "center" your node is. This will also be useful for proper spacing from its (non-sibling) neighbors.
It may be possible to make do with less iteration-to-iteration state, but this works for me.

C++ vector push_back with class object

I've been using this site for a while and so far never needed to ask a new question (found all answers I've needed until now).
I need to push_back multiple objects into a vector but VS throws an error (This may be due to a corruption of the heap, which indicates a bug in PVSS00DataGate.exe or any of the DLLs it has loaded) that I cannot seem to work out for myself.
Here is what I am trying to do, it works to push_back the first object into the vector but when I try to push_back a second object that is when the error occurs.
class HWObject{}
void DataLogger::WriteNewMessages()
{
unsigned int iBattery = 0;
unsigned int iSignal = 0;
TimeVar tTimeStamp;
// I want to store all HWObjects in a temporary vector (loggerData)
std::vector<HWObject> loggerData;
CharString strElement;
strElement.format( "batteryCondition.value" );
SendOneValuePVSS( (const char *)strElement, iBattery, tTimeStamp );
strElement.format( "signalStrength.value" );
SendOneValuePVSS( (const char *)strElement, iSignal, tTimeStamp );
}
void DataLogger::SendOneValuePVSS(const char *szElementName, double dValue, TimeVar, &tValue)
{
HWObject obj;
obj.setOrgTime(tValue); // Current time
obj.setTimeOfPeriphFlag();
CharString address;
address = strID;
address += ".";
address += szElementName;
obj.setAddress(address);
loggerData.reserve( loggerData.size() + 1 );
loggerData.push_back( obj );
obj.cutData();
}
dataLogger is declared in
class DataLogger
{
public:
std::vector<HWObject> loggerData;
...
}
Here is the class HWObject, I didn't want to overwhelm you with code.
public:
/** Default constructor*/
HWObject();
/** Constructor, which sets the periphAddr and transformationType.
* #param addressString address of the HW object
* #param trans type of transformation
*/
HWObject(const char* addressString, TransformationType trans);
/** Destructor. If the date pointer is not NULL, it is deleted.
*/
virtual ~HWObject();
/** Creates a new HWObject
* This function returns an empty HWObject, no properties are duplicated or copied!
* #classification public use, overload, call base
*/
virtual HWObject * clone() const;
/** Reset all pvss2 relevant parts of the HWObject. when overloading this member
* don't forget to call the basic function!
* #classification public use, overload, call base
*/
virtual void clear();
/** Gets pointer to data
* #return pointer to data
*/
const PVSSchar * getDataPtr() const { return dataPtr; }
/** Gets the data buffer pointer
* #return data buffer pointer
*/
PVSSchar * getData() { return dataPtr; }
/** Cut the data buffer out of the HWObject.
* This function is used to avoid the deletion
* of the data buffer, when a new pointer is set using
* setData() or the HWObject is deleted.
* #return pointer to the data of the HWObject
*/
PVSSchar * cutData();
/** Get the data buffer lenght
* #return length of the data buffer
*/
PVSSushort getDlen() const { return dataLen; }
/** Set ptr to the data buffer, pointer is captured.
* The actual data pointer in the HWObject is deleted,
* if it is not NULL. To avoid the deletion use cutData()
* in order to cut out the pointer.
* #param ptr pointer to new data
*/
void setData(PVSSchar *ptr);
/** Set the data length
* #param len length to be set
*/
void setDlen(const PVSSushort len) { dataLen = len; }
/** Get the periph address
* #return periph address string
*/
const CharString & getAddress() const { return address; }
/** Get the transformation type
* #return type of transformation
*/
TransformationType getType() const { return transType; }
/** Set the transformation type
* #param typ type of transformation for setting
*/
void setType(const TransformationType typ) { transType = typ; }
/** Get the subindex
* #return subindex
*/
PVSSushort getSubindex() const { return subindex; }
/** Set the subindex
* #param sx subindex to be set
*/
void setSubindex( const PVSSushort sx) { subindex = sx; }
/** Get the origin time
* #return origin time
*/
const TimeVar& getOrgTime() const { return originTime; }
/** Get the origin time
* #return oriin time
*/
TimeVar& getOrgTime() { return originTime; }
/** Set the origin time
* #param tm origin time to be set
*/
void setOrgTime(const TimeVar& tm) { originTime = tm; }
/** Get HWObject purpose
* #return objSrcType
*/
ObjectSourceType getObjSrcType() const { return objSrcType; }
/** Set HWObject purpose
* #param tp objSrcType
*/
void setObjSrcType(const ObjectSourceType tp) { objSrcType = tp; }
/** Get number of elements in data buffer
* #return number of elements in data buffer
*/
PVSSushort getNumberOfElements() const { return number_of_elements; }
/** Set number of elements in data buffer
* #param var number of elements in data buffer
*/
void setNumberOfElements(const PVSSushort var) { number_of_elements = var; }
/** Prints the basic HWObject information on stderr.
* in case of overloading don't forget to call the base function!
* #classification public use, overload, call base
*/
virtual void debugPrint() const;
/** Prints th basic HWObject info in one CharString for internal debug DP.
* in case of overloading call base function first, then append specific info
* #classification public use, overload, call base
*/
virtual CharString getInfo() const;
/** Set the periph address
* #param adrStr pointer to address string
*/
virtual void setAddress(const char *adrStr);
/** Set the additional data (flag, orig time, valid user byte,etc)
* #param data aditional flags that be set
* #param subix subindex, use subix 0 for setting values by default
*/
virtual void setAdditionalData(const RecVar &data, PVSSushort subix);
/** Set the 'origin time comes from periph' flag
*/
void setTimeOfPeriphFlag()
{
setSbit(DRV_TIME_OF_PERIPH);
}
/** Check whether time comes from periph
* #return PVSS_TRUE if the time is from perip
*/
PVSSboolean isTimeFromPeriph() const
{
// If isTimeOfPeriph is set, it must be valid
return getSbit(DRV_TIME_OF_PERIPH);
}
/** Set the flag if you want to receive callback if event has answered the value change
*/
void setWantAnswerFlag()
{
setSbit(DRV_WANT_ANSWER);
}
/** Get the status of the 'want answer, flag
*/
PVSSboolean getWantAnswerFlag() const
{
// If isTimeOfPeriph is set, it must be valid
return getSbit(DRV_WANT_ANSWER);
}
/** Set the user bit given by input parameter.
* Status bits defined by the enum DriverBits
* #param bitno bit number
* #return PVSS_TRUE if bit was set
*/
PVSSboolean setSbit(PVSSushort bitno)
{
return (status.set(bitno) && status.set(bitno + (PVSSushort)DRV_VALID_INVALID - (PVSSushort)DRV_INVALID));
}
/** Clear the user bit given by input parameter
* #param bitno bit number
* #return PVSS_TRUE if bit was cleared
*/
PVSSboolean clearSbit(PVSSushort bitno)
{
return (status.clear(bitno) && status.set(bitno + (PVSSushort)DRV_VALID_INVALID - (PVSSushort)DRV_INVALID));
}
PVSSboolean isValidSbit(PVSSushort bitno) const
{
return status.get(bitno + (PVSSushort)DRV_VALID_INVALID - (PVSSushort)DRV_INVALID);
}
/** Check any bit
* #param bitno bit number
* #return status of the bit on bitno position
*/
PVSSboolean getSbit(PVSSushort bitno) const {return status.get(bitno);}
/** Clear all status bits
* return status of clear all
*/
PVSSboolean clearStatus() {return status.clearAll();}
/** Get the status of this object
* #return bit vector status
*/
const BitVec & getStatus() const {return status;}
/** Set status of the bit vector
* #param bv deference to bit vector to be set as status
*/
void setStatus(const BitVec &bv) {status = bv;}
/** Set a user byte in the status.
* #param userByteNo number of user byte range 0..3
* #param val value to set
* #return PVSS_TRUE execution OK
* PVSS_FALSE in case of error
*/
PVSSboolean setUserByte (PVSSushort userByteNo, PVSSuchar val);
/** Reads a user byte from the status.
* #param userByteNo number of user byte range 0..3
* #return the requested user byte
*/
PVSSuchar getUserByte (PVSSushort userByteNo) const;
/** Check validity of user byte.
* #param userByteNo number of user byte range 0..3
* #return PVSS_TRUE user byte is valid
* PVSS_FALSE user byte is not valid
*/
PVSSboolean isValidUserByte(PVSSushort userByteNo) const;
/** Format status bits into a string
* #param str status bits converted to string
*/
void formatStatus (CharString & str) const ;
// ------------------------------------------------------------------
// internal ones
/** Read data from bin file
* #param fp file handle
*/
virtual int inFromBinFile( FILE *fp );
/** Write data to bin file
* #param fp file handle
*/
virtual int outToBinFile( FILE *fp );
/** Set data length
* #param dlen data length
*/
void setDlenLlc (PVSSushort dlen) {dataLenLlc = dlen;}
virtual void updateBufferLlc (HWObject * hwo, int offset1 = 0);
virtual int compareLlc (HWObject * hwo, int offset1 = 0, int offset2 = 0, int len = -1);
/** Get dataLenLlc
* #return dataLenLlc
*/
PVSSushort getDlenLlc () const {return dataLenLlc;}
/** Function to delete the data buffer; overload if special deletion must be done
*/
virtual void deleteData ();
/** Set HW identifier
* #param id hw identifier to be set
*/
void setHwoId(PVSSulong id) {hwoId = id;}
/** Get HW identifier
* #return hw identifier
*/
PVSSulong getHwoId() const {return hwoId;}
protected:
/// the dynamic data buffer
PVSSchar* dataPtr;
/// the data buffer len
PVSSushort dataLen;
/// the pvss2 periph address string
CharString address;
/// the start subix for the data buffer
PVSSushort subindex;
/// the datatype of the data in the buffer (i.e. transformationtype)
TransformationType transType;
/// the time of income, normally set by the constructor
TimeVar originTime;
/// the purpose of this HWObject
ObjectSourceType objSrcType;
/// the number of elements in the data buffer, used for arrays and records
PVSSushort number_of_elements; // fuer array!!!
/// the user bits of the original config
BitVec status;
private:
PVSSushort dataLenLlc;
PVSSulong hwoId;
};
You're not showing the important parts. I'd guess that HWObject has
dynamically allocated memory, and doesn't implement the rule of three
(copy constructor, assignment operator and destructor). But it's only a
guess. (Unless you're using special techniques like reference counting
or smart pointers, copy must do a deep copy, and assignment should
probably use the swap idiom.)
Also, there's no point in reserving size() + 1 just before
push_back.