How to pass pointers correctly for custom class - c++

The backPtr_ of last node is pointing to itself at the time of generating trajectory.
This is mostly happening due to the backptr__ is pointing at the back of openNodes and while exploring a node it is last element due to pop_heap.
Any work around for this?
I have already tried to keep the openNodes as vector of Node objects rather than of pointers.
init_node.calculateF();
vector<Node*> openNodes;
openNodes.push_back(&init_node);
vector<vector<coord_t>> traj;
while(!openNodes.empty()){
pop_heap(openNodes.begin(), openNodes.end(), NodePtrCompareGtr());
Node* newNodePtr = openNodes.back();
Node newNode = *newNodePtr;
openNodes.pop_back();
traj = newNode.exploreNodes(openNodes, openSet, closedNodes, &newNode);
}
class Node
{
Node *backPtr_ = NULL;
public:
void setBackPtr(Node* nodeptr){
backPtr_ = nodeptr;
}
vector<vector<coord_t>> exploreNodes(vector<Node*> &openNodes){
newCoordList = generateCoords();
vector<Node*> newNodeList;
if(goal_reached(this)){
return generate_traj(this);
}
for(auto const& newCoords : newCoordsList){
Node *newNode = new Node(...);
newNodeList.push_back(newNode);
}
for(auto & i : newNodeList){
...
i->setBackPtr(this);
openNodes.push_back(i);
make_heap(openNodes.begin(), openNodes.end(), NodePtrCompareGtr());
...
}
}
I want to store the backPtr_ correctly to store the correct previous node.

Related

Adding a node to the beginning of a double-linked list

I am trying to create a function that adds a node to the beginning of a double-linked list in C++, and I'm getting this error in Xcode. I know it must be because I lost the address of one of my temp nodes, but I cannot figure out how to fix it.
template<typename Item>
void DLList<Item>::push_front(const Item &item) {
/* Adds item to a new Node at the front of the list. Updates head,
tail, and size accordingly. Must appropriately handle cases in which the list is empty */
Node*p = new Node;
p -> item = item;
Node*oldHead = head;
p -> next = oldHead;
oldHead -> prev = p; /*error message: Thread 1: EXC_BAD_ACCESS (code=1, address=0x10)*/
head = p;
size ++;
}
The error will happen when oldHead is nullptr, and then oldHead->prev is an invalid access. This happens when the list is empty (head is nullptr).
It is easy to fix: just make sure you only execute that statement when the list is not empty. NB: you don't actually need oldHead. Just keep working with head.
And as the comment in your code seems to suggest your list has a tail member, you should set it when the first node is added to the list:
Node* p = new Node;
p -> item = item;
p -> next = head;
if (head != nullptr) {
head -> prev = p;
} else {
tail = p;
}
head = p;
size ++;

Selection sort in single linked list without using swap

I have been trying to solve the selection sort in single linked list without using swap nodes. Using a temp list to store nodes and assign the current list with a new one
//my addlastnode function
void AddLastNODE(LIST &mylist, NODE *p)
{
//Check the list is empty or not
if(isEmpty(mylist))
mylist.pHead = mylist.pTail = p;
else
mylist.pTail->pNext = p;
mylist.pTail = p;
}
void selectionSort(LIST &mylist)
{
//Initialize a temp list to store nodes
LIST mylisttemp;
IntList(mylisttemp);
//Create node
NODE *p;
NODE *i;
//Create min node
NODE *min;
//Check if list is empty or has one node
if(mylist.pHead == mylist.pTail)
return;
//Traverse the list till the last node
for(p=mylist.pHead; p->pNext!=NULL && p!=NULL; p = p->pNext)
{
min=p;
for(i=p->pNext; i!=NULL;i=i->pNext)
{
////Find the smallest data in list
if(i->data < min->data)
min=i;
}
////Add the smallest to a new list
AddLastNODE(mylisttemp, min);
}
//Fill the current list to the new list
if(!isEmpty(mylisttemp))
mylist = mylisttemp;
}
Your code does not reduce the list you are selecting nodes from: the selected node should be removed from it. To make that happen, you need a reference to the node before the selected node, so that you can rewire the list to exclude that selected node.
There is also a small issue in your AddLastNODE function: it does not force the tail node to have a null as pNext pointer. This may be a cause of errors when the function is called with a node that still has a non-null pNext pointer. Secondly, the indentation is off around the else block. It does not lead to a bug in this case, but still it is better to avoid the confusion:
void AddLastNODE(LIST &mylist, NODE *p)
{
if(isEmpty(mylist))
mylist.pHead = p;
else
mylist.pTail->pNext = p;
mylist.pTail = p; // indentation!
p->pNext = nullptr; // <--- better safe than sorry!
}
Then to the main algorithm. It is quite tedious to work with a previous node reference when looking for the node with the minimum value. It helps a bit when you temporarily make the input list cyclic:
void selectionSort(LIST &mylist) {
if (mylist.pHead == mylist.pTail) return;
// Make list temporarily cyclic
mylist.pTail->pNext = mylist.pHead;
LIST mytemplist;
IntList(mytemplist);
while (mylist.pHead != mylist.pTail) {
// Select node:
NODE * beforemin = mylist.pTail;
for (NODE * prev = mylist.pHead; prev != mylist.pTail; prev = prev->pNext) {
if (prev->pNext->data < beforemin->pNext->data) {
beforemin = prev;
}
}
NODE * min = beforemin->pNext;
// Extract selected node:
if (min == mylist.pTail) mylist.pTail = beforemin;
if (min == mylist.pHead) mylist.pHead = min->pNext;
beforemin->pNext = min->pNext;
// And insert it:
AddLastNODE(mytemplist, min);
}
// Move last remaining node
AddLastNODE(mytemplist, mylist.pHead);
// Copy back
mylist = mytemplist;
}
As a side note: You might even want to always keep your list cyclic. This will mean some changes in other functions you may have, as there will be no pNext pointers that are null then.

C++: Append node to Linked List

This what I need to do:
append_data adds a node onto the end of the list pointed to by top. the resulting list is one element longer, and the newly appended node has the given data value. consider using the 'append' function to help.
void AppendData(int data);
append is the same as append_data, except we're adding a node, rather than a value.
void Append(shared_ptr new_node);
I was able to AppendData using this code, but in an ideal world I could pass Append thru AppendData and get the same result. I'm struggling with Append right now even though the answer is in the AppendData code
'''
void LinkedList::AppendData(int data){
shared_ptr<node> temp(new node);
temp->data = data;
temp->next = shared_ptr<node>(NULL);
shared_ptr<node> end_node(top_ptr_);
if(end_node == NULL) {
end_node=temp;
} else {
while(end_node->next!=NULL) {
end_node=end_node->next;
}
end_node->next=temp;
}
}
void LinkedList::Append(shared_ptr<node> new_node){}
'''
in an ideal world I could pass Append thru AppendData and get the same result.
Actually, Append has less information than AppendData, in particular, the data itself. It would make more sense to refactor it in a way that AppendData creates a node, and then calls Append to append that node to the list:
void LinkedList::AppendData(int data){
// construct node
shared_ptr<node> temp(new node);
temp->data = data;
temp->next = shared_ptr<node>(NULL);
// append it
Append(temp);
}
void LinkedList::Append(shared_ptr<node> new_node){
shared_ptr<node> end_node(top_ptr_);
if(end_node == NULL) {
end_node = new_node; // new_node instead of temp
} else {
while(end_node->next!=NULL) {
end_node=end_node->next;
}
end_node->next = new_node; // ditto
}
}
Also, this line end_node = new_node; is incorrect. If the list is empty, you need to update top_ptr_ like this:
top_ptr_ = new_node;

Interview Coding - Take a pointer to a Node structure as a parameter and return a complete copy of the passed-in data structure

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);
}

Queue appending more then one entry

I keep getting the first entry appended 4 times instead of one time.. when I append my first entry to the Queue it appends it 4 times..I thought this might be the problem..but it looks like it isn't. I can't find where the problem is..
I also created a print function for the nodes, and it showes that there are 4 of the same entries in the queue, so it is not a printing problem. And it doesn't look like it's in the read function. Maybe it's in the logic of the append function?? Still working on it..
This is the output: 3X^2 + 3X^2 + 3X^2 + 3X^2 + 1 but it should be 3X^2 + 1
This is my append function:
//Append(Add) item to back of queue.
Error_code Extended_queue::append(const Queue_entry &item) {
Node<Queue_entry> *new_rear = new Node<Queue_entry>(item);
if(rear == nullptr){
front = new_rear; // I also tried rear = new_rear; front = rear; rear = new_rear;
}
else {
rear->next = new_rear;
rear = new_rear;
}
return success;
}
And here is the code that prints the output:
This is the node code declaration:
#ifndef NODE_H
#define NODE_H
enum Error_code{success,underflow,overflow}; // Used in node containing classes
template <class Node_entry> // Template to allow for more varience
// Part of a linked structure
struct __declspec(align(1)) Node{
Node_entry entry; // Data contained in the node
Node *next; //Pointer to next node
//constructors
Node(); // Creates empty node
Node(Node_entry item, Node *add_on = nullptr); // Creates node with specified data and pointer to next node
};
/* Post: The Node is initialized to contain nothing, and to have a null pointer.*/
template <class Node_entry>
Node<Node_entry>::Node()
{
entry = nullptr;
next = nullptr;
}
/* Post: The Node is initialized to contain item, and to point to add_on.*/
template <class Node_entry>
Node<Node_entry>::Node(Node_entry item, Node *add_on)
{
entry = item;
next = add_on;
}
#endif
It looks like the copy constructor had bad logic. After I fixed th constructor, the driver only returned the first term as front and rear entry. So I had to fix up the overloaded = operator as well.
New Code(for copy constructor):
Extended_queue::Extended_queue(const Extended_queue &original){
Node<Queue_entry> *temp_node, *original_node = original.front;
if(original.empty()){ //original queue is empty, set new to NULL
front = nullptr;
rear = nullptr;
}
else
{
front = temp_node = new Node<Queue_entry>(original_node->entry,nullptr);
while(original_node->next != nullptr)
{
original_node = original_node->next;
//needed to change next and still incriment
temp_node->next = new Node<Queue_entry>(original_node->entry, nullptr);
temp_node = temp_node->next;
//rear->next = temp_node;
//rear = temp_node;
}
rear = temp_node->next;
}
}