How to add a Node pointer to a Vector pointer? - c++

I am trying to create a maze that consists of Nodes objects. Each Node object has a member variable Node *attachedNodes[4] that essentially contains all of the attached Nodes that will later tell the program the options it has when it is doing a breadth first search. Every time I think that I understand pointers, another issue like this comes up, and I feel lost all over again. Especially since it was working fine (as far as I knew) until I changed something that I thought was unrelated. Anyways, here is where the issues are:
My Node object looks like this
class Node {
public:
...
void attachNewNode(Node *newNode, int index);
...
private:
...
Node *attachedNodes[4];
...
};
My function to attach the Nodes looks like this:
void Node::attachNewNode(Node *newNode, int index) {
*attachedNodes[index] = *newNode;
}
And then lastly, the part of the other function that is calling the attachNewNode function looks like this:
int mazeIndex = 0;
while (inStream.peek() != EOF) {
int count = 0;
Node n;
Node m;
...
if (System::isNode(name2)) {
m = System::findNode(name2);
}
else {
m = Node(name2);
maze[mazeIndex] = m;
mazeIndex++;
}
Node *temp;
*temp = m;
n.attachNewNode(temp, count); //The error usually happens here, but I added the rest of the code because through debugging it is only consistently in this whole area.
count++;
}
n.setNumberUsed(count);
}
Sorry that this got a little lengthy, but I've been searching all over this portion that I have provided trying to figure out what is wrong, but it would be nice to have someone that knows a little more about pointers give their input on the matter. The Node class was given to me, but everything else I made, so basically any of that could be changed. Thanks in advance for the help.

Your class contains a property:
Node *attachedNodes[4];
The above says that attachedNodes is an array that contains 4 pointers to Nodes. In your attachNewNode function, you do:
*attachedNodes[index] = *newNode;
This means that you are trying to assign value of newNode (as * dereferences the pointer) to the value of the element under attachedNodes[index]. What you probably want is:
attachedNodes[index] = newNode;
This means that you just want to store the address (as pointer is just an address to some place in memory) in the array of addresses.
There is also another error here:
Node *temp;
*temp = m;
n.attachNewNode(temp, count);
Again, you are interested in storing the address of node m. In order to do that, you need to get the said address:
Node *temp;
temp = &m;
n.attachNewNode(temp, count);
These are the most obvious problems with the above code, but there might be more.

Related

Tree traversal falls into infinite loop (with huffman algorithm implementation)

I am trying implementing the huffman algorithm following the steps described in this tutorial: https://www.programiz.com/dsa/huffman-coding, and so far I got this code:
void encode(string filename) {
List<HuffmanNode> priorityQueue;
List<Node<HuffmanNode>> encodeList;
BinaryTree<HuffmanNode> toEncode;
//Map<char, string> encodeTable;
fstream input;
input.open(filename, ios_base::in);
if (input.is_open()) {
char c;
while (!input.eof()) {
input.get(c);
HuffmanNode node;
node.data = c;
node.frequency = 1;
int pos = priorityQueue.find(node);
if(pos) {
HuffmanNode value = priorityQueue.get(pos)->getData();
value++;
priorityQueue.update(pos, value);
} else {
priorityQueue.insert(node);
}
}
}
input.close();
priorityQueue.sort();
for(int i=1; i<=priorityQueue.size(); i++)
encodeList.insert( priorityQueue.get(i) );
while(encodeList.size() > 1) {
Node<HuffmanNode> * left = new Node<HuffmanNode>(encodeList.get(1)->getData());
Node<HuffmanNode> * right = new Node<HuffmanNode>(encodeList.get(2)->getData());
HuffmanNode z;
z.data = 0;
z.frequency = left->getData().frequency + right->getData().frequency;
Node<HuffmanNode> z_node;
z_node.setData(z);
z_node.setPrevious(left);
z_node.setNext(right);
encodeList.remove(1);
encodeList.remove(1);
encodeList.insert(z_node);
}
Node<HuffmanNode> node_root = encodeList.get(1)->getData();
toEncode.setRoot(&node_root);
}
full code for the main.cpp here: https://pastebin.com/Uw5g9s7j.
When I try run this, the program read the bytes from the file, group each character by frequency and order the list, but when I try generate the huffman tree, I am unable to traverse this tree, always falling into a infinte loop (the method get stuck in the nodes containing the 2 first items from the priorityQueue above).
I tried the tree class with BinaryTree<int>, and everything works fine in this case, but with the code above the issue happens. The code for the tree is this (in the code, previous == left and next == right - I am using here the same Node class already implemented for my List class): https://pastebin.com/ZKLjuBc8.
The code for the List used in this example is: https://pastebin.com/Dprh1Pfa. And the code for the Node class used for both the List and the BinaryTree classes is: https://pastebin.com/ATLvYyft. Anyone can tell me what I am missing here? What I am getting wrong here?
UPDATE
I have tried a version using only c++ stl (with no custom List or BinaryTree implementations),but the same problem happened. The code is that: https://pastebin.com/q0wrVYBB.
Too many things to mention as comments so I'm using an answer, sorry:
So going top to bottom through the code:
Why are you defining all methods outside the class? That just makes the code so much harder to read and is much more work to type.
Node::Node()
NULL is C code, use nullptr. And why not use member initialization in the class?
class Node {
private:
T data{};
Node * previous{nullptr};
Node * next{nullptr};
...
Node::Node(Node * node) {
What is that supposed to be? You create a new node, copy the value and attach it to the existing list of Nodes like a Remora.
Is this supposed to replace the old Node? Be a move constructor?
Node::Node(T data)
Write
Node<T>::Node(T data_ = T{}) : data{data_} { }
and remove the default constructor. The member initialization from (1) initializes the remaining members.
Node::Node(T data, Node * previous, Node * next)
Again creating a Remora. This is not inserting into an existing list.
T Node::getData(), void Node::setData(T value)
If everyone can get and set data then just make it public. That will also mean it will work with cons Node<T>. Your functions are not const correct because you lack all the const versions.
Same for previous and next. But those should actually do something when you set the member. The node you point to should point back to you or made to do so:
void Node::setPrevious(Node * previous) {
// don't break an existing list
assert(this->previous == nullptr);
assert(previous->next == nullptr);
this->previous = previous;
previous->next = this;
}
Think about the copy and move constructors and assignment.
Follow the rule of 0/3/5: https://en.cppreference.com/w/cpp/language/rule_of_three . This goes for Node, List, ... all the classes.
List::List()
Simpler to use
Node<T> * first{nullptr};
List::~List()
You are deleting the elements of the list front to back, each time traversing the list from front till you find index number i. While horrible inefficient the front nodes have also already been deleted. This is "use after free".
void List::insert(T data)
this->first = new Node<T>();
this->first->setData(data);
just write
first = new Node<T>(data);
And if insert will append to the tail of the list then why not keep track of the tail so the insert runs in O(1)?
void List::update(int index, T data)
If you need access to a list by index that is a clear sign that you are using the wrong data structure. Use a vector, not a list, if you need this.
void List::remove(int index)
As mentioned in comments there are 2 memory leaks here. Also aux->next->previous still points at the deleted aux likely causing "use after free" later on.
int List::size()
Nothing wrong here, that's a first. But if you need this frequently you could keep track of the size of the list in the List class.
Node * List::get(int index)
Nothing wrong except the place where you use this has already freed the nodes so this blows up. Missing the const counterpart. And again a strong indication you should be using a vector.
void List::set(int index, Node * value)
What's this supposed to do? Replace the n-th node in a list with a new node? Insert the node at a specific position? What it actually does it follow the list for index steps and then assign the local variable aux the value of value. Meaning it does absolutely nothing, slowly.
int List::find(T data)
Why return an index? Why not return a reference to the node? Also const and non-const version.
void List::sort()
This code looks like a bubblesort. Assuming it wasn't totaly broken by all the previous issues, would be O(n^4). I'm assuming the if(jMin != i) is supposed to swap the two elements in the list. Well, it's not.
I'm giving up now. This is all just the support classes to implement the BinaryTree, which itself is just support. 565 lines of code before you even start with your actual problem and it seems a lot of it broken one way or another. None of it can work with the state Node and List are in. Especially with copy construction / copy assignment of lists.

Geting Data from a Tree Structure

I have a tree structure that i am creating the following way. The tree is created correctly as far as i know. But when i want to get the data from a node, i get some weird acsii symbols.
How I set the data.Lets say its empty. Doesn't matter at the moment. I have a value in my program. The function feeds itself until i get to the end of the data.
struct Node {
char Data;
Node* Left;
Node* Right;
};
Node maketree(0,s,split)
{
Node node;
node.Data=' ';
Node n1=subsplit(0,s,splitingat);
Node n2= subsplit(1,splitingat+1,e);
node.Left=&n1;
node.Right=&n2;
return node;
}
This is how i get data from the tree.
char decode(Node node,string text)
{
int currentindex=0;
Node sub=node;
{
}
if(text[currentindex]=='0')
{
sub=*sub.Left;
cout<<" x "<<sub.Data<<endl;
}
else if(text[currentindex]=='1')
{
sub=*sub.Right;
cout<<" x "<<sub.Data<<endl;
}
// cout<<sub.Data<<endl;
}
I think that the mistake is that I am printing out the pointer and not the node. But I don't know where I went wrong.
The source of your problem appears to be here:
Node node;
node.Data=' ';
Node n1=subsplit(0,s,splitingat);
Node n2= subsplit(1,splitingat+1,e);
node.Left=&n1; // danger Will Robinson!
node.Right=&n2;
return node;
You're taking the addresses of local, temporary, automatic variables and storing them in pointers that you return through node. As soon as that return executes, n1 and n2 are destroyed and node.Left and node.Right are left pointing to garbage. You may be able to fix this like so:
Node* n1=new Node(subsplit(0,s,splitingat));
Node* n2=new Node(subsplit(1,splitingat+1,e));
// side note: probably better to have subsplit() return dynamically-allocated Node*s to avoid the copy
node.Left=n1;
node.Right=n2;
but you may still have issues crop up if similar things are being done elsewhere.
Kind of along the same lines, in your second block of code, you are making a copy of each node you examine and storing it into sub. It would probably make more sense to have sub be a Node*.
And finally, to avoid memory management issues (almost) altogether, use shared_ptr<Node> instead of Node* in all of the above. :)

Linked ArrayList Implementation

I am trying to implement a Linked ArrayList in C++ for instruction purposes, I've hit a snag though and I'm unsure how to unsnag it. My pointer array doesn't seem to be composed of pointers, but of actual objects.
Keeping my code as brief as possible.
//arraylist.h//
class classArrayList {
private:
class Node {
Node();
//accessors
};
Node* classArray;
public:
classArrayList();
};
//arraylist.cpp//
classArrayList::classArrayList() {
Node* node = new Node();
this->setHead(node);
this->setMaxSize(5);
classArray = new Node[5];
this->classArray[0] = *node;
this->setSize(1);
}
void classArrayList::deleteNode( int index ) {
Node* my_current = &this->classArray[index];
//blahblah
}
But when I go to delete a node, "my_current" doesn't link to whatever would be next or prev in this list. Trying to delete at position zero, no next.
So there's definately a node with data but it doesn't have its links, but checking the debugger my linked list is fine and works, so its whatever the array is pointing to that's screwing up.
So instead of pointing to the list, its pointing to unique instances, how can I fix this?
My code to add something new to the array is: this->classArray[some_index] = *new_node;
To clarify, I wanna be able to have an array that points sequencially to each object in my linked list. And then when I ask for one at any n in my arraylist, reference it to a pointer and then do thins to the object in my list through its position in the array, rather than increment through the list until I find the nth one I want.
Make your classArray a double pointer and create a Node pointer array. Node* classArray; Copy the address of head of your list to each array.
classArray = new Node*[5];
In your code by your statement this->classArray[0] = *node; you are not storing the address of the newly created, instead content of newly created node. And by deleting you are not removing the dynamically created list head.
For copying the address of newly created list you should use
this->classArray[0] = node;
The code works as it should. When you delete a node from your linked list, you delete the data under the pointer. As you set my_current to the address of the deleted node, you actually don't point to anything. The problem doesn't lie in the code, but in your understanding of the subject.
In order to really make a working linked list, every node should consist of a pointer to the next node. That way, when you delete a node, you'll first be able to retrieve the next node from the pointer, and set your my_current to a valid address.
In order to solve your problem, you should actually read a bit about the subject.
If you want to access the elements in "array style", overload the operator [].
Node& classArrayList::operator [](unsigned int index)
{
Node *node = head;
for(unsigned int i=0;i<index;i++)
if(node->next()) node = node->next();
else break;
return *node;
}

Unable to compile C++ code: invalid conversion from 'Node*' to 'int'

I have this C++ class with an array of Node objects called adj (I guess you don't need to see the implementation of my Node class)
class Graph {
public:
Node *adj;
bool *marked;
int nVertex, p;
int *distance;
void graph(int quantity);
bool is_marked();
void cleaner();
void newVertex(int value);
};
And I have this method which creates a node nod and tries to store it in the p-th position in adj:
void Graph::newVertex(int value)
{
Node *nod = new Node(value);
adj[p++] = nod;
}
When I try to compile this code I get the following error message:
invalid conversion from 'Node*' to 'int'
I can't see what I have done wrong in my code. The array initialization looks right to me and the object assignment too. Please help me answer this question.
UPDATE: the code for the Node class:
class Node {
public:
int value, cost;
Node *next;
Node() {}
Node(int val) {
value = val;
next = NULL;
cost = 0;
}
};
UPDATE: I can't use C++ vector here. I'd love to but it's for a homework thing. Before anyone thinks I am cheating or something, please note that I'm not asking for a solution to my specific assigned problem, but instead to a problem that I am having for compiling the code.
The type of adj[p++] is clearly Node& and you try to assign a Node* to it. I guess, your Node type has a constructor taking an int and the compiler tries but fails to convert the Node* to an int.
You probably meant to declare adj as
std::vector<Node*> adj;
... and then add new nodes using, e.g.:
adj.push_back(nod);
(note, that you still need to make sure the allocated objects get released at the appropriate point in time).
adj is of type Node*. adj[someIndex] is then of type Node. You are trying to assign Node* to Node. My educated guess is, you have Node::operator=(int), so the compiler tries to interpret your code that way - but that doesn't work out either, producing the error message you observe.
After you have created your new Node:
Node *nod = new Node(value);
you need to hook it up to your linked list. A linked list looks like:
[HEAD] => [value|next] => [value|next] => NULL
where HEAD in your case would be adj.
Therefore, you need to update the next of your new node to point to the current head node, then update the head node to point to the new node.
That is, you should end up with something like:
adj => [value|next] => [value|next] => ... => NULL
^ ^
nod adj'
where adj' is the old value of adj.
It helps to create diagrams of what the data structure looks like and how the values are being updated.
You then need to work out how to traverse the nodes in the list.
Also, don't forget to clean up the nodes in the Graph destructor (and be careful how you do that).
OK, with the definition of the Node class in hand I think I can see what you're trying to do. If I'm correct, you want to have Graph::adj point to a linked list of Node elements, with each Node then pointing to the next Node in the list. If that's correct the implementation of new_vertex needs to look something like:
void Graph::newVertex(int value)
{
Node *nod = new Node(value);
nod->next = adj;
adj = nod;
}
No need to have an index (p) - you'd just walk the linked list of Node elements with code similar to
Node *n = adj;
while(n != NULL)
{
// do something useful with n
n = n->next;
}
If you really insist upon using array syntax to access elements of the linked list (bad idea in my mind, as it just adds to the potential confusion, but YMMV) you could add something like
Node *operator[](int n); // 0-based index into Node list
to Graph with an implementation similar to
Node *operator[](int ndx)
{
Node *n = adj;
for( ; n != NULL, ndx > 0 ; ndx--)
n = n->next;
return n;
}
Share and enjoy,.

Basic C++ programming question

I am in process of learning c++. I am working on creating a linkedlist data structure. One of the functions that displays the values of nodes in the structure does not work. For some reason the while loop that traverses through nodes doesn't work in the display function, hence I can't see the values in those nodes. Does anyone see what the problem is? I've been staring at the code for a while and not sure what is wrong here.
Thanks for your help in advance.
Header:
// linklist.h
// class definitions
#ifndef LINKLIST_H
#define LINKLIST_H
class linklist
{
private:
// structure containing a data part and link part
struct node
{
int data;
node *link;
}*p;
public:
linklist();
void append(int num);
void addatbeg(int num);
void addafter(int loc, int num);
void display();
int count();
void del(int num);
~linklist();
};
#endif
.cpp file
// LinkedListLecture.cpp
// Class LinkedList implementation
#include"linklist.h"
#include<iostream>
using namespace std;
// initializes data member
linklist::linklist()
{
p =NULL;
}
// adds a node at the end of a linked list
void linklist::append(int num)
{
node *temp, *r;
// if the list is empty, create first node
if(p==NULL)
{
temp = new node;
temp->data = num;
temp->link = NULL;
}
else
{
// go to last node
temp = p;
while(temp->link!=NULL)
temp = temp->link;
// add node at the end
r = new node;
r->data=num;
r->link=NULL;
temp->link=r;
}
}
// displays the contents of the linked list
void linklist::display()
{
node *temp = p;
cout<< endl;
// traverse the entire linked list
while(temp!=NULL) // DEBUG: the loop doesn't work
{
cout<<temp->data<<" ";
temp = temp->link;
}
void main()
{
linklist l;
l.append(14);
l.append(30);
l.append(25);
l.append(42);
l.append(17);
cout<<"Elements in the linked list:";
l.display(); // this function doesn't work
system("PAUSE");
}
You never set p to a non NULL value.
if(p==NULL)
{
p = new node;
p->data = num;
p->link = NULL;
}
I think GWW has highlighted the issue, but part of learning to program it to learn how to identify the mistakes.
If you do something and don't get the expected result you could:
Use the visual c++ debugger to step through and see the values of your variables.
Put in log lines to report information you think is important
inspect the code - if you think something is right but it doesn't work, then go to an earlier step and check it does the right thing.
Add unit tests, or follow design by contract adding pre/post conditions and class invariants.
Learning to program C++ by writing a linked list is like learning math by adding 1 + 1. It is old fashioned thinking, slow and mostly boring without having any context.
Math isn't calculating, like C++ programming isn't pointer manipulation. At some stage you might need to know about it, but your better off learning other important things like stl and boost.
If it was understood that append() ment create something, find the end of the list, add it. you could then see that in you append function you have create something mixed uyp with move to the end of the list, but you never add it.