Recursion to add struct in linked list c++ - c++

I'm having trouble inserting a struct into a linked list in numerical order. Each struct has a "number" as indicated in the code below. I'm trying to have the struct with the lowest number be the head of the list (ie: be the struct pointed to by "people"). I've been staring at this code on and off all day and I can't figure out what's wrong with it. Any help is much appreciated. Thanks
Person *addPerson(Person *people, Person *addition, int &numList)
{
if (people == NULL && numList == 0)
{
people = addition;
numList++;
return people;
}
if (people->number >= addition->number)
{
addition->nextPerson = people;
people = addition;
return people;
}
else if (people->number < addition->number && people->nextPerson != NULL)
{
addPerson(people->nextPerson, addition, numList);
}
else if (people->number < addition->number && people->nextPerson == NULL)
{
people->nextPerson = addition;
numList++;
return people;
}
}
EDIT**
int main()
{
Person *blake = new Person;
Person *kyra = new Person;
Person *elon = new Person;
Person *bill = new Person;
Person *people = NULL;
blake->number = 1;
blake->name = "blake";
blake->lastName = "madden";
blake->nextPerson = NULL;
kyra->number = 2;
kyra->name = "kyra";
kyra->lastName = "madden";
kyra->nextPerson = NULL;
elon->number = 3;
elon->name = "elon";
elon->lastName = "musk";
elon->nextPerson = NULL;
bill->number = 4;
bill->name = "bill";
bill->lastName = "gates";
bill->nextPerson = NULL;
int num = 0;
int &numList = num;
people = addPerson(people, blake, numList);
people = addPerson(people, kyra, numList);
people = addPerson(people, elon, numList);
people = addPerson(people, bill, numList);
cout << people->name << '\n' << people->lastName;
}

You are not using the return value from addPerson() in the third if block. Try:
people->nextPerson = addPerson(people->nextPerson, addition, numList);
return people;
You also need the return people; in there otherwise you'll run off the end of your function and not return anything sensible (my compiler warned me about that, you should change your warning settings so yours does too).
With the above change, your code appears to run correctly.

You aren't ever assigning the returned head. It should be
people->nextPerson = addPerson(people->nextPerson, addition, numList);

You're problem is the arguments to the function. You're desiring to modify the pointer in the node in the previous caller in the recursive call-order, but you are simply passing the pointer value of the next node. That doesn't allow you to actually modify the pointer-member of the previous node.
Change your function so that it looks like this:
void addPerson(Person** people, Person *addition, int &numList)
Then when you call addPerson in the third block, do it like so:
addPerson(&(*(people)->nextPerson), addition, numList);
And finally when you access the people argument, make sure to-do an extra dereference, for instance:
*people = addition;
or
if ((*people)->number >= addition->number)

Related

Print a string from a pointer to its member class

So I'm trying to print a string, but I get no output. However the other values in the class prints just fine.
In main I have a for loop that prints the the values for the Skill class. In Skill I have a pointer to the Ability class.
class Skill {
private:
Ability* ability;
public:
Ability* GetAbility() {
return ability;
};
}
It gets assigned in the constructor like this:
Skill::Skill(Ability* ability){
this->ability = ability;
}
The Ability class contains just a Name and a score.
class Ability {
private:
string name;
float score;
public:
Ability(string name, float score) {
this->name = name;
this->score = score;
};
string Name() { return name; }
float GetScore() { return score; }
};
Now in main I create a few skills and assign an ability to it. as is a container class that initializes a few ablities in a vector and I can get an ability based on its name.
Skill s* = new Skill[2]
s[0] = Skill(&as.GetAbility("Strength"));
s[1] = Skill(&as.GetAbility("Charisma"));
And then we print
cout << s[i].GetAbility()->Name() << " " << s[i].GetAbility()->GetScore();
However the only output I get is the score. No name what so ever and I can't figure it out. I've tried a few things, but still noting is printing. I'm sure I'm missing something simple that will make me facepalm, but in my defense I haven't written C++ in over 10 years. Thanks in advance.
EDIT: as.GetAbility looks like this:
Ability AbilityScores::GetAbility(string abilityName) {
for (int i = 0; i < abilityScores.size(); i++) {
if (abilityScores[i].Name() == abilityName) {
return abilityScores[i];
}
}
return Ability();
}
abilityScores is a vector
Your AbilityScores::GetAbility() method is returning an Ability object by value, which means it returns a copy of the source Ability, and so your Skill objects will end up holding dangling pointers to temporary Ability objects that have been destroyed immediately after the Skill constructor exits. So your code has undefined behavior.
AbilityScores::GetAbility() needs to return the Ability object by reference instead:
Ability& AbilityScores::GetAbility(string abilityName) {
for (int i = 0; i < abilityScores.size(); i++) {
if (abilityScores[i].Name() == abilityName) {
return abilityScores[i];
}
}
throw ...; // there is nothing to return!
}
...
Skill s* = new Skill[2];
s[0] = Skill(&as.GetAbility("Strength"));
s[1] = Skill(&as.GetAbility("Charisma"));
...
If you want to return a default Ability when the abilityName is not found, consider using std::map instead of std::vector:
private:
std::map<std::string, Ability> abilityScores;
AbilityScores::AbilityScores() {
abilityScores["Strength"] = Ability("Strength", ...);
abilityScores["Charisma"] = Ability("Charisma", ...);
...
}
Ability& AbilityScores::GetAbility(string abilityName) {
// if you don't mind Name() returning "" for unknown abilities...
return abilityScores[abilityName];
// otherwise...
auto iter = abilityScores.find(abilityName);
if (iter == abilityScores.end()) {
iter = abilityScores.emplace(abilityName, 0.0f).first;
}
return iter->second;
}
...
Skill s* = new Skill[2];
s[0] = Skill(&as.GetAbility("Strength"));
s[1] = Skill(&as.GetAbility("Charisma"));
...
Otherwise, return the Ability object by pointer instead:
Ability* AbilityScores::GetAbility(string abilityName) {
for (int i = 0; i < abilityScores.size(); i++) {
if (abilityScores[i].Name() == abilityName) {
return &abilityScores[i];
}
}
return nullptr;
// or:
abilityScores.emplace_back(abilityName, 0.0f);
return &(abilityScores.back());
}
...
Skill s* = new Skill[2];
s[0] = Skill(as.GetAbility("Strength"));
s[1] = Skill(as.GetAbility("Charisma"));
...

how to insert linked list nodes in multiple functions without using global variables in c++?

struct MonthReservationsAverage
{
string monthName;
int averageOfReservations;
MonthReservationsAverage *link;
};
void getMonthReferenceAndCalculateAverage()
{
const string monthsReferencesFile = "months_files_names.txt";
ifstream inputFile(monthsReferencesFile);
string monthReference;
MonthReservationsAverage *firstMonthAverage,
*lastMonthAverage, *newMonthAverage;
firstMonthAverage = NULL;
lastMonthAverage = NULL;
while (getline(inputFile, monthReference))
{
newMonthAverage = new MonthReservationsAverage;
ifstream monthInputFile(monthReference);
int reservationsAveragForMonth;
int totalReservationsOfmonthCounter = 0;
int dailyReservations;
int daysOfMonthCounter = 0;
while (!monthInputFile.eof())
{
monthInputFile >> dailyReservations;
totalReservationsOfmonthCounter += dailyReservations;
daysOfMonthCounter++;
}
monthInputFile.close();
reservationsAveragForMonth = totalReservationsOfmonthCounter / daysOfMonthCounter;
newMonthAverage->monthName = monthReference.substr(0, 3);
newMonthAverage->averageOfReservations = reservationsAveragForMonth;
newMonthAverage->link = NULL;
if (firstMonthAverage == NULL)
{
firstMonthAverage = newMonthAverage;
lastMonthAverage = newMonthAverage;
}
else
{
lastMonthAverage->link = newMonthAverage;
lastMonthAverage = newMonthAverage;
}
}
inputFile.close();
writeInfoInTextMode(firstMonthAverage);
}
hello everyone, I'm working with linked lists, I wrote this piece of logic, it works OK, but the problem is that the getMonthReferenceAndCalculateAverage is responsible of doing more than one thing, and that's not too good, so can anyone help me to divide this logic into more than one function without using global variables ?
I'm thinking of inserting nodes in different function, but the problem is how shall the linked list append the new node?

C++ - Insertion in a Linked List without using a node's constructor. Is it possible?

I'm working on implementing a Templated Linked List in C++ that will be used to simulate a train moving through numerous stops where traincars are both added and removed. Traincar is its own class and each object is supposed to be given a unique ID starting with 1 and incremented when a car is added. However, when running my code, the id is being incremented more than it is supposed to.
After some experimentation and with help from previous answers, I have determined that it is the new node statements within my LinkedList class methods that are causing the id to be incremented more than wanted. However, I do not see a way to implement insertion methods without creating a new node. Is there any way around this?
Here is my TrainCar class:
class TrainCar {
public:
static int nextID;
int id;
char typeOfCar;
int numberOfStops;
node<char>* car;
TrainCar();
};
int TrainCar::nextID = 1;
TrainCar::TrainCar() {
cout << "id++" << endl;
id = nextID++;
int i = (rand() % 3);//gives a random number 0 - 2, used to determine what
//type of car to add
if(i == 0) {
typeOfCar = 'P';
}
else if(i == 1) {
typeOfCar = 'C';
}
else {
typeOfCar = 'M';
}
car = new node<char>(typeOfCar);
numberOfStops = (rand() % 5) + 1;//gives a random number 1 - 5;
}
Here is my main() function
int main() {
LinkedList<TrainCar> train;
int addCargoCar = 0;
for(int i = 0; i < 10; i++) {
TrainCar newCar;
if(newCar.typeOfCar == 'P') {
train.AddToFront(newCar);
addCargoCar++;
}
else if(newCar.typeOfCar == 'C') {
train.AddAtIndex(newCar, addCargoCar);
}
else {
train.AddToEnd(newCar);
}
}
cout <<"Welcome to the Train Station! Here is your train!" << endl;
char type;
int id, numberOfStops, i, j;
for(i = 0; i < train.size; i++) {
type = train.Retrieve(i).typeOfCar;
id = train.Retrieve(i).id;
numberOfStops = train.Retrieve(i).numberOfStops;
cout << "[" << id << ":" << type << ":" << numberOfStops << "] ";
}
}
The output should be something similar to
[5:P:1][6:P:4][8:P:2][3:P:2][10:C:3][2:C:3][4:C:1][1:M:1][7:M:3][9:M:2]
But my output is:
[17:P:2][9:P:2][5:C:2][19:C:1][15:C:2][1:M:5][3:M:4][7:M:1][11:M:3][13:M:1]
Edit: Here is the AddToFront() method: (all other add methods are similar in nature). The issue with the output is the new node<T>(d) statements
template <class T>
void LinkedList<T>::AddToFront(T d) {
node<T>* newNode = new node<T>(d);
if(head == NULL) {
head = newNode;
tail = newNode;
size++;
}
else {
newNode->next = head;
head = newNode;
size++;
}
}
Edit2: Here is my Retrieve function (now fixed, it no longer uses a new node statement):
template <class T>
T LinkedList<T>::Retrieve(int index) {
node<T>* cur = head;
for(int i = 0; i < index; i++) {
cur = cur->next;
}
return(cur->data);
}
You have the right idea to use a static member variable to keep track of identifiers. But you can't use only that.
The static member variable is a member of the class and not any specific object. Therefore all object share the same id.
Use a static member to keep track of the next possible id, and then use a non-static member variable to store the actual id for the object.
Something like
class TrainCar {
public:
static int next_id; // Used to get the id for the next object
int id; // The objects own id
...
};
TrainCar::TrainCar() {
id = next_id++; // Get next id and save it
...
}
You should probably also have a copy-constructor and copy-assignment operator, otherwise you could get two objects with the same id.
Regarding
Why are the id values so high and why are they being incremented by more than one each time?
That's because you probably create more objects than you expect. With the code you show, as well as with the change suggested above, you will create a new id for every object that is default-constructed. And depending on what your LinkedList template class is doing (why don't you use std::vector) there might be new objects created.
An educated guess is that the Retreive function of your list class default constructs the object it contain. That's why you get three objects constructed when printing, as you call Retrieve three times. Probably a similar story about your Add functions.

looking for explanation for a part of a code

I have this function a student represented by id going to add a course in a specific semester. this code is correct but i don't understand the section when he did
for (size_t i = 0; i < (*iteratorVectorP).size(); i++) ...
void add_course(map<int, map<int, vector<course *> * > > &DB, int
semester, int id, course c)
{
auto iterator = DB.find(id); //find id as key, set map to value
vector<course*> *pointer = new vector<course*>;
if (iterator != DB.end())
{
auto iterator1 = ((*iterator).second).find(semester); //find
semester as key, set vector to value
if (iterator1 == (*iterator).second.end()) //if semester does not exist
{
pointer->push_back(new course(c));
(iterator->second)[semester] = pointer;
}
else //if semester exist
{
auto iteratorVectorP = (iterator->second)[semester];
// i do not understand what his doing here
for (size_t i = 0; i < (*iteratorVectorP).size(); i++)
{
if (c == *(*iteratorVectorP)[i])
{
return; //exit when class exist
}
else
{
(*iteratorVectorP).push_back(new course(c));
return;
}
}
}
}
}
the defination of iteratorVectorP is vector, so the for loop is iterating the course and try to add it in the vector if non-existed.
It looks like iteratorVectorP is a pointer, so calling (*iteratorVectorP).size() will get the value it is pointing to.

Memory for array property not allocated before Constructor?

When I run the program and new a NetworkEditor, it will corrupt at the constructor because of it reads out of the array's memory.
When I debug it one loop by one loop, it will be ok!?
Why? Didn't it allocate enough memory for the array before it entered the constructor?
In my class, I have two properties:
/*NetworkEditor.h*/
class CNetworkEditor : public CDiagramEditor
{...
VLLink* VL_list[10];
VLLink* temp_VL_list[10];
}
and in the constructor, I initialize the arraies:
/*NetworkEditor.cpp*/
for (int i = 0; i < 10; i++)
{
VLLink* vl_link = NULL;
while(vl_link == NULL)
{
vl_link = new VLLink;
}
vl_link->preLink = NULL;
vl_link->nextLink = NULL;
vl_link->link = NULL;
VLLink* vl_link2 = NULL;
while (vl_link2 == NULL)
{
vl_link2 = new VLLink;
}
vl_link2->preLink = NULL;
vl_link2->nextLink = NULL;
vl_link2->link = NULL;
VL_list[i] = vl_link;
temp_VL_list[i] = vl_link2;
}
and VLLink is defined as:
typedef struct struct_VLLink
{
CPhysicalLink* link;
struct_VLLink* preLink;
struct_VLLink* nextLink;
}VLLink;
If I change it to:
VLLink* VL_list2[10];
VLLink* temp_VL_list2[10];
for (int i = 0; i < MAX_VL_NUM; i++)
{
VLLink* vl_link = NULL;
while(vl_link == NULL)
{
vl_link = new VLLink;
}
vl_link->preLink = NULL;
vl_link->nextLink = NULL;
vl_link->link = NULL;
VLLink* vl_link2 = NULL;
while (vl_link2 == NULL)
{
vl_link2 = new VLLink;
}
vl_link2->preLink = NULL;
vl_link2->nextLink = NULL;
vl_link2->link = NULL;
VL_list2[i] = vl_link;
temp_VL_list2[i] = vl_link2;
}
It will be ok!?
Apart from #PeterHuene's suggestion to replace VL_list and temp_VL_list with something like std::list<CPhysicalLink> or similar, you should move the initialization of VLLink into the constructor, avoiding the code duplication in your loop
struct VLLink {
VLLink() : link(NULL), prelink(NULL), nextlink(NULL) {}
...
};`
then you can reduce your loop as #MikeSeymour said
for (int i = 0; i < MAX_VL_NUM; i++) {
VL_list[i] = new VLLink();
temp_VL_list[i] = new VLLink();
}
A reason for your memory problem might be, that MAX_VL_NUM is larger than 10. So, you should either use MAX_VL_NUM everywhere or use 10 everywhere.
And now to your question ;-)
If I change it to ... It will be ok!?
Nobody can answer this, because nobody knows what you want to achieve. My first reaction would be definitely No!, because moving variables around "just because" is almost always a bad idea. It's better to analyze the problem and fix the cause than to cure some random symptoms.
Your change would also modify the meaning from member of a class to automatic variable on the stack.