OOP, Linked list using classes - c++

I have a class of events.
Now All I have to do is to create events and store them in a linked list. but I don't know how to fix the head position. I mean if i define head to be NULL in a constructor then for every new event it would re-defined to be NULL. Thus I will have only one event in my linked list.
My code is something like this:
// event.h
class event{
private:
Event *head;
Event *nxt;
int date;
string name;
public:
event();
event(int d, string n);
Add_item();
}
//event.cpp
event::event(){}
event::event(int date, string name): date(date), name(name){
head=NULL;
// Now each time I call a constructor, head would be re-defined as NULL.
What should I do???

First off, the code shows that class Event is self-contained. Which is to say that head and nxt are part of the object itself. If you wish to use a Linked List of objects linking to each other but not maintaining the head outside then I would do the following...
// event.cpp
event::event() {
head = NULL;
}
event::event(int date, string name): date(date), name(name) {
head = NULL;
}
event::event(event *prev, int date, string name): date(date), name(name) {
if (prev->head != NULL) {
this->head = prev->head;
} else {
prev->head = this->head = prev;
}
prev->nxt = this;
this->nxt = NULL;
}
An example of using this would be as follows:
event *tailEvent = new event(1, 'first');
event *nextEvent = new event(tailEvent, 2, 'second');
event *thirdEvent = new event(nextEvent, 3, 'third');
...
tailEvent = lastEvent;
and so on and so forth. So, tailEvent->head will always point to the first created event and the tailEvent->nxt will follow in the list.
BUT... This is highly prone to errors, so I would recommend keeping the list itself outside, if possible using STL. See Learning C++: A sample linked list for an example.
EDIT:
Better approach:-
class Event {
private:
Event *next;
int date;
string name;
public:
Event() {};
Event(int date, string name) : date(date), name(name) {};
setNext(Event *next) { this->next = next; };
int date() { return date; };
string name() { return name; };
Event *next() { return next; };
};
class EventList {
private:
Event *head;
public:
EventList() { head = NULL };
void add(int date, string name);
Event *head() { return head; }
}
void EventList::add(int date, string name) {
Event *newEvent = new Event(date, name);
newEvent->setNext(NULL);
Event *tmp = head;
if (tmp != NULL) {
while (tmp->next() != NULL) tmp = tmp->next();
tmp->setNext(newEvent);
} else {
head = newEvent;
}
}

You need some controlling code for your list. List items cannot control themself.
I would recommend you use a container std::list which implements all list operations.
If you want to implement your list, you should create controlling class, eg EventContainer and implement insert/delete and search operations.

A better approach is to have two classes here: One to store each event and another to manage and store information about the list.
There will be many event classes in your list. There will only be one list class.
Now, your event class will in fact need some helper methods such as next and previous pointers. You can implement them directly or create a third class that is either inherited from or have it contain the event class.
But either way, the class that manages the list should only require one instance. And in that instance the head can be initialized to null, and it will be updated as needed.

Related

Modifying private pointer of object within same type (but different object) public method

I've been attempting to create a node class which mimics a node on a graph. Currently, storage of the predecessor and successor nodes are stored via a node pointer vector: std::vector<Node*> previous. The vectors for the predecessor/successor nodes are private variables and are accessible via setters/getters.
Currently, I am dealing with updating the pointer values when adding a new node. My current method to update the predecessor/successor nodes is through this method (the method is the same for successor/previous nodes, just name changes):
void set_next(std::vector<Node*> new_next) {
this->next.clear();
for (Node* node : new_next) {
this->next.push_back(node);
}
}
This works for the current node but I was wondering the best way to update the new_next nodes that are passed in, especially the most 'C++'-esque way to accomplish this. I have previously written a method which adds individual nodes to the successor/predecessor vector:
void add_next(Node* new_node, bool one_way = false) {
this->next.pushback(new_node);
if (!one_way) {
new_node->add_prev(this, one_way = true);
}
}
The one_way variable was used to determine the depth(?) of the add_next() call. If it is true, it will add to the successor set and then add to the predecessor set of new_node. Since the boolean value is set to false when the new_node->add_next() method call occurs, it will only add to the predecessor set and not attempt to call add_next()/add_prev() again. This solution does work, but I'd rather not have the one_way variable and would prefer that the method would be private.
Here is the structure of the class currently:
class Node {
private:
std::vector<Node*> previous;
std::vector<Node*> next;
boost::any data;
public:
std::vector<Node*> get_previous()
void set_previous(std::vector<Node*> new_previous)
std::vector<Node*> get_next()
void set_next(std::vector<Node*> new_next)
void add_prev(Node* new_node, bool one_way = false)
void add_next(Node* new_node, bool one_way = false)
}
Avoiding the one_way parameter, it seems my best solution would be to just create an add_next/add_prev method that only updates the current node, not the passed node, unlike the solution above. With this solution, when adding new nodes, I could call the inverse of the add_next/add_prev on the new node. However, I have an inkling there may be a better solution for this.
Thank you!
I think this should get you going (edge-cases left to you to figure out, if any):
template<typename T>
class Node {
// Everything made public for debugging purposes, change this to fit your needs
public:
std::vector<Node<T>*> previous;
std::vector<Node<T>*> next;
T data;
Node(T val) {
data = val;
}
void set_next(std::vector<Node<T>*>& new_next);
};
template<typename T>
void Node<T>::set_next(std::vector<Node<T>*>& new_next) {
next = new_next;
for (Node<T>* node : new_next)
node->previous.push_back(this);
}
int main() {
// Little proof of concept where 0 is parent to 1, 2, 3
Node<int> one = 1;
Node<int> two = 2;
Node<int> three = 3;
Node<int> zero = 0;
std::vector<Node<int>*> new_next = { &one , &two, &three };
zero.set_next(new_next);
return 0;
}
To sum up the differences:
Use templates, boost::any is non standard and is all around terrible for this task.
Leverage operators (= makes a copy of std::vectors).
Leverage reference types (this way you can modify the argument passed to your function).

understanding enqueue in a linked list

hey i am trying to add to my queue but I have a problem, and I need some help
i used a linked list for my queue and the problem is when I add a 3rd item to my list I overwrite the second
this is the code
void addnode(node* data)
{
if (begin == NULL)
{
data->next = begin;
begin = data;
}
else
{
end = data; //this is where the problem when i add a 3rd data i dont save anywhere my end so its gone
begin->next = end;
end->next = NULL;
}
}
in my code i have begin for the start of the queue, and end for the end of it
the linked list i built is with classes in c++,
but whenever i add a 3rd data the second gets overwriten so i always have two..
I need some help with how to fix it, thanks :)
edit this is more of the code: this is my class for the queue
#include"node.h"
class queue
{
public:
queue();
~queue();
void addNode(node*);
private:
node* begin;
node* end;
};
this is the class that i get the data from
using namespace std;
class node
{
friend void printclient(node &);
public:
node();
~node();
void setstr(string);
void setmoney(int);
node* next;
private:
string name;
double money;
int id;
};
The function can look the following way. I suppose that the data member next of the node pointed to by the pointer data is already set to nullptr.
void addnode(node* data)
{
if (begin == nullptr)
{
begin = end = data;
}
else
{
end = end->next = data;
}
}
That is if the queue is empty (the pointers begin and end are equal to nullptr) then begin and end are set to the added pointer.
Otherwise the new node is appended to the end of the queue. In this case the data member next of the node pointed to by the pointer end is set to the new pointer and this pointer becomes the end pointer.
Pay attention to that the user of the queue should know nothing about the class node. The class should be declared as a private or protected member of the class queue. And the method addNode should be substitute for the method push declaration of which should look like
void push( const std::string &name, int id, double money );

Linked list overwrites the previous value

I want to create a linked list with classes. I have two classes, one LinkedList and another LinkedNode. My problem is that my function InsertAtEnd always delete the current node. So when I want to print my linked list, I can't see anything.
I know thanks to debugger that in the function InsertAtEnd, we don't enter in the while loop, this is the problem. But after several attemps I can't resolve my problem.
This is my code:
void LinkedList::InsertAtend(int data)
{
LinkedNode* node = new LinkedNode();
node->setData(data); node->setNext(nullptr);
LinkedNode* tmp = _header;
if (tmp != NULL)
{
while (tmp->getNext() != nullptr)
{
tmp = tmp->getNext();
}
tmp->setData(data);
tmp->setNext(nullptr);
}
else
{
_header = node;
}
}
My class LinkedNode:
class LinkedNode
{
public:
LinkedNode();
~LinkedNode();
void setData(int data);
void setNext(LinkedNode* next);
int getData() const;
LinkedNode* getNext() const;
private:
int _data;
LinkedNode* _next;
};
My class LinkedList:
#pragma once
#include
#include "LinkedNode.h"
using namespace std;
class LinkedList
{
public:
LinkedList();
~LinkedList();
void PrintList();
void InsertAtend(int data);
void PrintList() const;
private:
LinkedNode* _header;
};
Thanks for your help !
tmp->setData(data);
Your tmp is not the node that you're trying to add, but the last in your list.
tmp is the last Node, so if you don't want to delete it you shouldn't write value data in it. You should link it with the new Node, which you named node.
Instead of
tmp->setData(data);
tmp->setNext(nullptr);
You should write
tmp->setNext(node)
At the end of the loop, the tmp is the last node in the current list. As you want to add the new node after the last node, you need to
tmp->setNext(node);
to append it (and not set the data as the data are already set to the new node).
Also note that you actually do not need to iterate through the entire list at all, if you keep another member variable to the current end of the list (_tail). Then you can access it directly and simply append and update.

Issues loading data from a struct into a vector of that struct

The structure is only in one function of my class. I have been debugging and trying everything I can think of. This is for a graph and the function is for a Dijkstra formula. The main issue I get is that my data never gets into my vector (vector open).
Not sure if all the code is need since all the problems happen in this function. Code not currently used (trying to get data into the vector first) has been commented out.
void Graph::Dijkstra(string start, string end, vector<string> &path)
{
struct node
{
string name;
vector<string> connection;
int costSoFar;
node() {name = " "; costSoFar = 0;}
node(node& other)
{
name = other.name;
connection = other.connection;
costSoFar = other.costSoFar;
}
};
vector<string> adjacent;
node startNode;
node current;
node endNode;
vector<node> open;
node closed[MAX_VERTICES];
int small, temp;
bool found = false;
bool inClosed = false;
bool inOpen = false;
string tempVertex;
// starting node is added open list
// startNode = node();
startNode.name = start;
startNode.costSoFar = 0;
//adjacent.push_back(startNode.name);
open.push_back(startNode);
temp = 0; // used a place holder for debugging
//open[0].name = startNode.name;
//open[0].costSoFar = startNode.costSoFar;
}
Any help would be greatly appreciated. I have looked at similar post and attempted their suggestions not sure why my vector will not take input even if I try to directly apply it (see commented code above).
I believe std containers require a copy constructor of the form:
node(const node& other);
That's the form of the default copy constructor if you don't provide one. If do provide a copy constructor then this default one will not be provided for you, so you must define one of that form.
OK I found my own solution. It appears if the structure is created inside the function it cannot access variables the way it needs to. All I did was move the node struct to the outside of the function.
struct node
{
string name;
vector<string> connection;
int costSoFar;
node() {name = " "; costSoFar = 0;}
node(const node& other)
{
name = other.name;
connection = other.connection;
costSoFar = other.costSoFar;
}
};
void Graph::Dijkstra(string start, string end, vector<string> &path)
{ // the other code needed }

Mixing abstract classes and templates, a recipe for disaster?

I'm having problems with the following situation. I have three classes that are involved in this mixup. List, ListNode, City. I have a List<City *>, where the list will be made up of a set of ListNode<City *> (standard wrapper around the list nodes).
City is an abstract class, so there are several classes that inherit from it that could be placed in this list and accessed polymorphically. The List class has a getHead() method which returns a pointer to a ListNode that is the head.
Any city has a population, so to access the populations, I'd expect the following to work. It's not, thus my question. I broke it down into pieces to make it simpler along the way:
ListNode<City *> *head= country->city_list->getHead();
City *headnode = *head->getNode();
cout << "Test: " << headnode->getPopulation() << endl;
getPopulation() returns an integer. country is defined as List<City*> *city; Any help on how I could figure out my problem would be greatly appreciated.
edit adding more code for better idea of what I'm working with. First, ListNode:
template <class T>
class ListNode
{
public:
ListNode() {next = 0;node = 0;};
ListNode(T *t) {node = t; next = 0;};
ListNode(const ListNode &l)
{
//long copy constructor. snip.
};
T *getNode() const { return node; }
ListNode *getNext() const { return next; };
private:
T *node;
ListNode *next;
};
Now, here is what might relevant in the List class..
template <class T>
class List
{
public:
List()
{
head = 0;
size = 0;
};
List(ListNode<T> *t)
{
head = t;
size = 1;
};
List(T *t)
{
head = new ListNode<T>(t);
size = 1;
};
List(const List<T> &t)
{
// long copy constructor. snip.
};
//bunch of irrelevent methods.
ListNode<T> *getHead() const {return head;};
List &operator+=(T &t)
{
this->insert(&t);
size++;
return (*this);
};
private:
List &insert(T *t)
{
ListNode<T> *current = head;
if (current == 0)
{
head = new ListNode<T>(t);
}
else
{
while (current->getNext() != 0)
{
current = current->getNext();
}
current->setNext(new ListNode<T>(t));
}
return (*this);
};
ListNode<T> *head;
int size;
};
I have a hunch that the process of inserting might be the problem. I insert with the List class's += operator, shown in the List implementation above. It calls the private insert method shown above, as well. It looks like this:
City *somecity = new City(x,y,z); //some parameters. integers.
*city_list += somecity; // where city_list is a List.
I think you've got a variable scoping problem.
Your ListNode class contains a pointer to the node value. Your ListNode constructor takes in a pointer to the node value and saves it.
The problem is if that pointer is to a local variable that then goes out of scope. Your ListNode's node pointer is now pointing to an object that doesn't exist. e.g. in this example
addToList(List<int>& myList)
{
int x = 3;
myList += x; // pointer to x is in the list
}
// Out of scope; x no longer exists, but myList has a pointer to it.
// Accessing this node will result in an error.
There are a couple possible remedies:
Have your ListNode contain values rather than pointers. The drawback here is that you will be making copies of the values
Implement ListNode using a reference counted smart pointer which will manager the lifetime of the object.
Well, what you could do is:
ListNode<City *>* head = new ListNode<City*>(country->city_list->getHead());
City* headnode = head->getNode();
cout << "Test: " << headnode->getPopulation() << endl;
It will take the existing City (on the memory) and put it at the head of the List node, and so on.
and if you want to copy them, maybe you could just make this:
ListNode<City *>* head = new ListNode<City*>*(new City(country->city_list->getHead()));
City* headnode = new City(head->getNode());
cout << "Test: " << headnode->getPopulation() << endl;
Hope it will help you.