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.
Related
I'm coding red-black tree using C++-smart pointers. I designed left and right child to be owned by its parent, so it is unique_ptr<Node> member variable of its parent node, and 'parent' member variable is set to be Node*, because the children clearly does not have ownership.
My problem is: A function that rotates tree takes argument as unique_ptr<Node>&, because it changes positions of node, but I need to pass a parent node to the function, which is in type of Node* that does not match with function argument type.
The solution I think:
1) Make parent() function that returns unique_ptr<Node>. This would be something that starts from the root of the tree and descend to find the pointer that match with parent's address. CONS: slow as hell
2) for node->parent, return node->parent->parent->left or right after some checks.
CONS: code gets little bit messier
3) Make another unique_ptr<Node> by giving Node* as an argument of constructor, and pass that. CONS: I'm not sure that the newly created unique_ptr object would coincide with already existing unique_ptr<Node> object.
4) Use shared_ptr<Node> for child, weak_ptr<Node> for parent instead. Then I could use node->parent.lock() as function argument.
CONS: child pointers' ownership are not meant to be 'shared'.
5) Discard all smart pointer things. Aww.
struct Node {
T data;
Node* parent = nullptr;
unique_ptr<Node> left, right;
bool color = false;
Node(const T& d) : data(d) {};
Node* grandparent() {
if (parent == nullptr) {
return nullptr;
}
return parent->parent;
}
}
/* SOMETHING... */
void rotate_right(unique_ptr<Node>& pivot) {
if (pivot->left == nullptr) {
return;
}
auto pivot_new = move(pivot->left);
auto pivot_parent = pivot->parent;
pivot->left = move(pivot_new->right);
pivot_new->right = move(pivot);
pivot->parent = pivot_new.get();
if (pivot->left != nullptr) {
pivot->left->parent = pivot.get();
}
if (pivot_parent != nullptr) {
if (pivot == pivot_parent->left) {
pivot_parent->left = move(pivot_new);
} else if (pivot == pivot_parent->right) {
pivot_parent->right = move(pivot_new);
} else {
throw invalid_argument("pivot_parent is actually not parent, why?\n");
}
}
pivot_new->parent = pivot_parent;
}
/* SOME OTHER THINGS */
void insert_repair_tree(Node* node) {
if (node->parent == nullptr) {
// this is root. paint BLACK
node->color = true;
} else if (node->parent->color) {
// parent is BLACK. tree is valid. do nothing
} else if (!get_color(node->uncle())) {
// parent is RED. uncle exists and RED. grandpa exists and BLACK.
// repaint parent and uncle to BLACK, and grandpa to RED.
// recursively repair tree at grandpa
node->parent->color = true;
node->uncle()->color = true;
node->grandparent()->color = false;
insert_repair_tree(node->grandparent());
} else {
// parent is RED. uncle is BLACK (not sure that it exists). grandpa exists and BLACK.
auto grandpa = node->grandparent();
if (node == grandpa->left->right) {
rotate_left(grandpa->left);
node = node->left.get();
} else if (node == grandpa->right->left) {
rotate_right(grandpa->right);
node = node->right.get();
}
grandpa = node->grandparent();
// PROBLEMS HERE
if (node == node->parent->left) {
rotate_right(grandpa);
} else if (node == node->parent->right) {
rotate_left(grandpa);
} else {
throw invalid_argument("");
}
node->parent->color = true;
grandpa->color = false;
}
}
Please consider the below code sample
NodeInterface * pPreNode = NULL;
NodeInterface * pChild = NULL;
for (uint16_t Index = 0; Index < Children.size(); ++Index)
{
pChild = Children[Index];
if (pPreNode == NULL)
{
pChild->SetPrevious(pChild);
pChild->SetNext(pChild);
}
else
{
pChild->SetNext(pPreNode->GetNext());
pChild->SetPrevious(pPreNode);
pPreNode->GetNext()->SetPrevious(pChild);
pPreNode->SetNext(pChild);
}
pPreNode = pChild;
}
To test this lines how to setup the mock exactly?
Children is a vector of Nodes and we are passing Mocked objects.
EXPECT_CALL(Obj, GetNode()).WillOnce(Invoke(this, &GetANewNode));
and the GetANewNode will provide new MockedNode
MockedNode * GetANewNode()
{
MockedNode * pMockedNode = new MockedNode();
return pMockedNode;
}
How to provide exact nodes for each Next(), Previous() calls?
EXPECT_CALL(*pMockedNode, SetNext(_));
EXPECT_CALL(*pMockedNode, SetPrevious(_));
EXPECT_CALL(*pMockedNode, GetNext());
EXPECT_CALL(*pMockedNode, GetPrevious());
Simple solution is to have all mocked nodes predefined before test case. And use Sequence/InSequence to be sure that everything happens in proper order.
class ObjTest : public ::testing::Test
{
protected:
const std::size_t N = ...; // I do not know how many do you need
std::vector<MockedNode> mockedNode;
std::vector<Node*> children;
Sequence s;
.... Obj; // I am not sure what is Obj in your question
ObjTest () : mockedNode(N)
{}
void SetUp() override
{
// initial setup
EXPECT_CALL(Obj, GetNode()).WillOnce(Return(&mockedNode.front())).InSequence(s);
}
};
Having such test class with initial setup - you can create test cases testing various scenarios that happen after initial sequence:
TEST_F(ObjTest, shouldLinkOneNodeToItself)
{
std::vector<Node*> children { &mockedNode[0] };
EXPECT_CALL(mockedNode[0], SetNext(&mockedNode[0])).InSequence(s);
EXPECT_CALL(mockedNode[0], SetPrevious(&mockedNode[0])).InSequence(s);
Obj.testedFunction(children); // you have not provided your tested function name...
}
And very similar test case for two children:
TEST_F(ObjTest, shouldLinkTwoNodesToEachOther)
{
std::vector<Node*> children { &mockedNode[0], &&mockedNode[1] };
// first interation
EXPECT_CALL(mockedNode[0], SetNext(&mockedNode[0])).InSequence(s);
EXPECT_CALL(mockedNode[0], SetPrevious(&mockedNode[0])).InSequence(s);
// second iteration
EXPECT_CALL(mockedNode[0], GetNext()).WillOnce(Return(&mockedNode[0])).InSequence(s);
EXPECT_CALL(mockedNode[1], SetNext(&mockedNode[0])).InSequence(s);
EXPECT_CALL(mockedNode[1], SetPrevious(&mockedNode[0])).InSequence(s);
// etc...
Obj.testedFunction(children);
}
So first I created a struct to contain the following:
template <class T>
struct ListNode
{
unsigned int id;
T data;
ListNode *next_left;
ListNode *next_right;
};
And a class with the following:
template <class T>
class List
{
public:
unsigned int id_count;
ListNode<T> *tail;
List()
{
tail = NULL;
id_count = 0;
}
unsigned int add(T item)
{
id_count += 1;
ListNode<T> *n = new ListNode<T>;
n->id = id_count;
n->data = item;
n->next_left = tail;
n->next_right = NULL;
tail = n;
if (n->next_left != NULL)
n->next_left->next_right = n;
return id_count;
}
ListNode<T> *getNode(unsigned int id)
{
bool found = false;
ListNode<T> *np = tail;
while(np != NULL)
{
if (np->id == id)
{
found = true;
return np;
break;
}
else
{
np = np->next_left;
}
}
return NULL;
}
};
Here is a link to the exact code of main.cpp: http://pastebin.com/fHhsvd9A
So in my main.cpp I create a List instance and a Node pointer:
List<F3D_model> GameEntities;
ListNode<F3D_model> *np;
Then I create two model class instances of the F3D_model Class and add them to the List intsance I created:
F3D_model model;
model.create();
F3D_model model2;
model2.create();
GameEntities.add(model);
GameEntities.add(model2);
Print models' information:
Created with ID: 1
Created with ID: 2
Model 1 Address: 07091F28
Model 2 Address: 070919D0
Model 1 Angle: 0
Model 2 Angle: 0
Tail ID: 2
Tail Data: 0
Tail Address: 070919D0
Code used to print information:
printf("Created with ID: %i\n",GameEntities.add(model));
printf("Created with ID: %i\n",GameEntities.add(model2));
printf("Model 1 Address: %p\n",GameEntities.getNode(1));
printf("Model 2 Address: %p\n",GameEntities.getNode(2));
printf("----------------\n");
printf("Model 1 Data: %i\n",GameEntities.getNode(1)->data.angle);
printf("Model 2 Data: %i\n",GameEntities.getNode(2)->data.angle);
printf("----------------\n");
printf("Tail ID: %i\n",(GameEntities.tail->id));
printf("Tail Data: %i\n",(GameEntities.tail->data.angle));
printf("Tail Address: %p\n",(GameEntities.tail));
printf("----------------\n");
( angle is a public var in F3D_model class )
Everything looks right.
So I have a keypress event where I add a value to the models' angle.
GameEntities.getNode(1)->data.angle += 60;
GameEntities.getNode(2)->data.angle += 60;
and then it prints again the values.
So the problem is that when I press the key it prints the same, as if I hadn't added the values.
BUT when I press the key it does move the model on the screen, so it is actually adding the values. And when I change the type from F3D_model to int and do the same process, it works just fine.
SO my question is why isn't it working when I use the F3D_model, and how can I make it work?
From what you've described, it sounds like the issue is just how you're printing the angle:
printf("Model 1 Data: %i\n",GameEntities.getNode(1)->data.angle);
printf("Model 2 Data: %i\n",GameEntities.getNode(2)->data.angle);
You've used %i which is an integer format specifier. You've said it prints what you expect when you change the definition of angle to be an int. If you change the format string to %f to print a float, or print static_cast<int>( GameEntities.getNode(1)->data.angle ) it should work.
The problem I can think of is that you use model and model2 when printing values, but you should use your nodes instead, because they are copies of the created models.
You can store pointers to models instead of models themselves in your list, to avoid copying models.
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.
This is an interview question that I found interesting.
Write a method that takes a pointer to a Node structure as a parameter and returns a complete copy of the passed-in data structure.
The Node structure contains two pointers to other Node structures.
For example, the method signature could look like so:
Node* Copy(Node* root);
Note - Do not make any assumptions about the data structure – it could be a tree, linked list, graph, etc.
How can this be done for any data structure ?
In the generic graph case, you need a mapping from nodes in the original graph to nodes in the new graph, so that when a cycle is encountered, the proper link gets created. If you happen to have extra temporary space in each node, large enough to hold a pointer, then you can store the mapping directly in the nodes; otherwise, you'll need to use an external map, such as an associative array or hash table.
Then it's just a matter of traversing the graph, copying nodes, and looking up the corresponding edges. Something like this:
struct Node
{
Node(int _data) : data(_data) { memset(links, 0, sizeof(links)); }
int data;
Node *links[2];
}
Node *Copy(Node *root)
{
typedef std::map<Node*, Node*> NodeMap;
NodeMap nodeMap;
std::deque<Node*> nodesToVisit;
// Set up initial new root and mapping for the root
Node *newRoot = new Node(root->data);
nodeMap[root] = newRoot;
// Breadth-first search the graph
nodesToVisit.push_back(root);
while(!nodesToVisit.empty())
{
Node *cur = nodesToVisit.front();
nodesToVisit.pop_front();
Node *newCur = nodeMap[cur];
for(int i = 0; i < 2; i++)
{
Node *link = cur->links[i];
if(link)
{
// If we've already created the corresponding node for this
// link, use that. Otherwise, create it and add it to the map.
NodeMap::iterator mappedLink = nodeMap.find(link);
if(mappedLink != nodeMap.end())
{
newCur->links[i] = mappedLink->second;
}
else
{
Node *newLink = new Node(link->data);
nodeMap[link] = newLink;
newCur->links[i] = newLink;
nodesToVisit.push_back(link);
}
}
}
}
return newRoot;
}
The problem as stated is impossible. You have to assume that the entire data structure is stored entirely within the content of nodes that are accessible from that initial one. But that is not an assumption you are allowed to make. Even your standard basic double linked list might not fit that description.
class Copier {
std::map <Node*, Node*> copies;
Node* Copy(Node* n) {
if (!n) return 0;
Node*& copy = copies[n];
if (!copy) {
copy = new Node();
copy.node1 = Copy(n.node1);
copy.node2 = Copy(n.node2);
}
return copy;
}
}
Node* Copy(Node* root) {
if (root == NULL)
return root;
std::unordered_map<Node*, Node*> completed;
std::deque<Node*> todo;
Node *ret = new Node(*scur);
completed.push_back(std::make_pair(root, ret));
todo.push_pack(root);
//while there's more nodes to duplicate
do {
//duplicate the node
Node* oldNode = todo.back();
Node* newNode = completed[cur];
todo.pop_back();
if(oldNode->left) {
auto iter = completed.find(oldNode->left);
//if it has a left child that needs duplicating, add it to the todo list
if (iter == completed.end()) {
newNode->left = new Node(*(oldNode->left));
completed.push_back(std::make_pair(oldNode->left, newNode->left));
todo.push_back(oldNode->left);
} else {
newNode->left = completed[oldNode->left];
}
}
if(oldNode->right) {
auto iter = completed.find(oldNode->right);
//if it has a right child that needs duplicating, add it to the todo list
if (iter == completed.end()) {
newNode->right = new Node(*(oldNode->right));
completed.push_back(std::make_pair(oldNode->right, newNode->right));
todo.push_back(oldNode->right);
} else {
newNode->right= completed[oldNode->right];
}
}
} while(todo.empty() == false)
//return the translation of the root
return ret;
}
Doesn't have stack overflow, root can be NULL, doesn't fail if left or right are NULL.
[Edit]Adam Rosenfield made me realize this was incorrect if there was loops in the network. Had to rewrite almost from scratch. Due to the large amount of code required, I prefer his code's for loop.
return new Node(*node);
Trick question?
You should write it recursively;
Node * Copy( Node * root )
{
Node * node_copy;
node_copy = new Node; // Assume Node1 and Node2 are initialized to 0
node_copy->content = root->content;
if( root->Node1 ) node_copy->Node1 = Copy( root->Node1 );
if( root->Node2 ) node_copy->Node2 = Copy( root->Node2 );
return node_copy;
}
So, this does not make any assumption on the data type
Given that a copy constructor exists that copies only the contents of a node and not its children:
Node* Copy(Node* root)
{
Node* copy = new Node(*root);
copy->left = Copy(root->left);
copy->right = Copy(root->right);
return copy;
}
In a more general sense, I would use copy-constructors that fully copy the entire data structure:
Node* Copy(Node* root)
{
return new Node(*root);
}