I have a Town class which represents the nodes in my graph like this:
class Town
{
public:
Town();
public:
Town* _parent;
int _name;
int _row;
int _column;
State _state;
vector<Town*> _neighbors;
};
I have a Map class which contains a 2D vector of Towns and pretty much makes my random graph.
class Map
{
public:
Map(const int elements, const int size, const int seed);
public:
vector <vector<Town> > _map;
vector <Town*> _towns;
vector <vector<int> > _adjacency;
vector <vector<double> > _mDistance;
vector <Line> _edges;
const int _elements;
const int _size;
Town* _start;
Town* _exit;
};
Then my AI class receives a Map object and solves it depending on the algorithm, right now I am implementing Astar.
class AI
{
private:
struct TownWithCost
{
Town town;
double cost;
};
struct OrderByTotalCost
{
bool operator()(TownWithCost lfs, TownWithCost rhs)
{
return lfs.cost > rhs.cost;
}
};
public:
AI(Map map);
private:
bool AStar(Town* town);
double GetTotalCost(Town town);
public:
bool _success;
private:
Map _map;
};
Here is my Astar implementation:
bool AI::AStar(Town* town)
{
AI::OrderByTotalCost comparator;
vector<TownWithCost> priorityQueue;
TownWithCost currentTown = { *town, 0 };
Town temp = currentTown.town;
priorityQueue.push_back(currentTown);
SetEnvironment(temp, State::visited);
while (!priorityQueue.empty())
{
currentTown = priorityQueue.front();
Town temp = currentTown.town;
priorityQueue.erase(priorityQueue.begin());
SetEnvironment(temp, State::visited);
PrintEnvironment();
if (temp._name == _map._exit->_name)
{
return true;
}
vector <Town*> neighbors = town->_neighbors;
for each (Town* neighbor in neighbors)
{
Town tempNeighbor = *neighbor;
if (tempNeighbor._state == State::town)
{
tempNeighbor._parent = &temp;
TownWithCost neighborWithCost = { tempNeighbor, GetTotalCost(tempNeighbor) };
priorityQueue.push_back(neighborWithCost);
}
}
make_heap(priorityQueue.begin(), priorityQueue.end(), comparator);
}
return false;
}
As you can probably notice I don't have yet implemented looking inside the priorityQueue to see if I already have a Town in there and compare the costs to see which one I want to keep but I plan on implementing that after I solve my current problem.
What my problem is, is that I do not want to have pointers inside the priorityQueue. I am trying to make temp variables which will copy a Town and it's cost from a certain path.
Let's say I start from Town 9.
9 has neighbors 0, 7, 8, 3 specifically the priorityQueue at the first loop looks like this:
Then I get 3 as my currentTown and I am checking it's neighbors.
The moment I reach the line Town temp = currentTown.town; for the second time the parents of each element in the priorityQueue are being set to 3. Now I understand why this is happening, what I don't understand is how to prevent this.
What I basically need is priorityQueue to store the same Towns (not same memory addresses) with different parents and different costs (I have already taken care of the separate cost with the struct TownWithCost). So all in all make copies each time.
For example I can get from 9 to 0 directly with total cost 81 but I can also get to 0 through 3 (9 -> 3 -> 0) with total cost 50. I want to be able to differentiate these two.
How do I differentiate between them in my priorityQueue and how do I avoid resetting the parents or in other words how do I allocate another part of memory to the Town temp each time the loop runs so I can have different temps each time?
If you have another way (as newbie friendly as possible) of doing this then feel free to say it.
You're passing by value instances of Map and this class doesn't have a copy constructor or assignment operator. When this class is shallow copied (ala memcpy) vector instances will cause a crash when they are destroyed (multiple times).
Try working with pointers or references. Will also work faster.
You could also use a vector of index pointing to an array or vector of the towns. No need for pointers. But personally, I'd prefer to use std:shared_ptr instead.
Related
I try to find optimal data structure for next simple task: class which keeps N last added item values in built-in container. If object obtain N+1 item it should be added at the end of the container and first item should be removed from it. It like a simple queue, but class should have a method GetAverage, and other methods which must have access to every item. Unfortunately, std::queue doesn't have methods begin and end for this purpose.
It's a part of simple class interface:
class StatItem final
{
static int ITEMS_LIMIT;
public:
StatItem() = default;
~StatItem() = default;
void Reset();
void Insert(int val);
int GetAverage() const;
private:
std::queue<int> _items;
};
And part of desired implementation:
void StatItem::Reset()
{
std::queue<int> empty;
std::swap(_items, empty);
}
void StatItem::Insert(int val)
{
_items.push(val);
if (_items.size() == ITEMS_LIMIT)
{
_items.pop();
}
}
int StatItem::GetAverage() const
{
const size_t itemCount{ _items.size() };
if (itemCount == 0) {
return 0;
}
const int sum = std::accumulate(_items.begin(), _items.end(), 0); // Error. std::queue doesn't have this methods
return sum / itemCount;
}
Any ideas?
I'm not sure about std::deque. Does it work effective and should I use it for this task or something different?
P.S.: ITEMS_LIMIT in my case about 100-500 items
The data structure you're looking for is a circular buffer. There is an implementation in the Boost library, however in this situation since it doesn't seem you need to remove items you can easily implement one using a std::vector or std::array.
You will need to keep track of the number of elements in the vector so far so that you can average correctly until you reach the element limit, and also the current insertion index which should just wrap when you reach that limit.
Using an array or vector will allow you to benefit from having a fixed element limit, as the elements will be stored in a single block of memory (good for fast memory access), and with both data structures you can make space for all elements you need on construction.
If you choose to use a std::vector, make sure to use the 'fill' constructor (http://www.cplusplus.com/reference/vector/vector/vector/), which will allow you to create the right number of elements from the beginning and avoid any extra allocations.
I have a list that hold an array of lists.
I have 2 object types "Flight" and "People" The other one is "Management". I created a list that holds a list of people for each Flight object made. I'm trying to make a list of lists that holds lists of people assigned to each Flight.
But I can only add 1 list to the list of list at location 0. Anything beyond that is a segmentation fault.
This is my Flight Class;
class Flight {
public:
int maxPeople;
int currentPos = -1;
int flightNo;
People list[50]; // list of people
public:
Passenger *list;
Flight();
Flight(int maxPassenger, int flightNo);
void addPeople(Passenger passenger);
};
class Management {
public:
const int maxFlights=20;
public:
Management();
addFlight(Flight flight);
};
This is my implementation of the prototypes:
//Global Variables
int currentPos1=-1; //
Flight *list2[20]; //list of list
//Constructor
Flight::Flight(int maxPeople2, int flightNo2) {
maxPeople = maxPeople2;
list = new People[maxPassenger]; //List means List of Passengers
flightNo = flightNo2;
Management::Management() {};
//Addflight
void Management::addFlight(Flight flight) {
currentPos1++;
*list2[currentPos1] = flight;
}
//Main
int main(void) {
Flight f1 (25, 333);
Flight f2 (25, 444);
a.addFlight(f1); // works
a.addFlight(f2); //Segfault
}
I am incrementing the currentPos1 everytime I add. And the list of lists (*list[20]) has 20 spots assigned. I can't figure out why it'll try to access a location out of that 20 that doesn't exist and causing segmentation fault.
Any Help would be very appreciated.
You don't initialize or allocate storage for any of the pointers in list2 anywhere. It's random that the first call to addFlight() doesn't segfault. This code
*list2[currentPos1]
ends up dereferencing a random memory location. If you change it to this:
list2[currentPos1] = &flight;
Well that's about as bad, because flight is a function parameter that's going to go away as soon as addFlight() returns.
Why are you using pointers and native arrays? Don't do that. Use std::vector.
Change list2 to
std::vector< Flight > list2;
and in addFlight()
list2[currentPos1] = flight;
i changed function addFlight() in Management as follows and it worked(atleast in my complier which didnt have complete code)
list2[currentPos1]=& flight;
which origiinally was
*list2[currentPos1]=flight;
I have a situation similar to the following
struct Cell
{
uint16_t x, y;
// other fields
Cell* right();
Cell* above();
...
}
class Container
{
private:
uint16_t width, height;
Cell* data;
public:
Container(uint16_t width, uint16_t height) :
width(width), height(height), data(new Cell[width*height]) { }
Cell* cellAt(uint16_t x, uint16_t y) { &data[x*height + y]; }
};
Container* container;
Cell* Cell::right() { return container->cellAt(x+1, y); }
...
I trimmed down much of code (eg range checks and whatnot) just to show the design.
Basically this allow me everywhere in the code to access neighbour cells without passing by Container object directly (which would produce more verbose code and neighbours are accesses hundreds of times all around the code base). The solution works nicely and Container class is not even need to be known around the code, since Cell is enough.
This approach has a strong limit though: it allows only one instance of Container. Now I find myself in the situation of wanting multiple instances of Container, with independent Cell arrays but I don't want to change the structure of the code.
I'm thinking about a smart way to allow multiple Container, but
I want to keep the structure as it is
I absolutely don't want to store a Container* inside each Cell to avoid wasting a lot memory (we're talking about million of cells)
I want to keep it as much efficient as possible since these neighbour functions are used a lot
I was thinking about allocating width*height + 1 Cell instances and use the first instance to store a Container* in its memory, but the problem is how to compute the address of the first Cell considering that the total width/height are fields of Container itself (and not known by Cell).
So I guess I should store at least one pointer to Container* for each column (they are stored by column as shown by cellAt function for secondary reasons useless to the question). This would waste height*sizeof(Cell) bytes for each Container which could be quite a lot but I guess there's no way with with a single pointer.
So basically I could do something like:
Container** container = reinterpret_cast<Container**>(&data[0]);
*container = this;
And then retrieve the object. Of course this is a dirty hack which could give problems on architecture which doesn't support unaligned accesses if sizeof(Cell) % alignof(void*) != 0.
Are there smarter solutions which I'm missing?
I have 3 solutions for you.
Cells know they are in a contiguous 2d buffer.
Finding the first element in the lower dimension is easy. So now you are at (N,0). If N is 0 we are done, we found the start of the 2d array.
The element before that is (N-1,Last), where Last+1 is the size of the lower dimension. Now you can jump to (0,0).
Alternatively, drop x and y from the cell, replace with container pointer. Calculate x and y on the fly from address of this and container pointer.
If we want to get serious, we drop all redundant information.
Kill x and y. Write a cell view type that stores a Cell* and a Container*. Mediate all interactions with Cell through this view. It calculates x and y and knows container size. It could just do nothing but pass Container* pointers to each method of Cell.
The CellView then replaces Cell* in your codebase. You can even override -> to return this and keep most use unchanged.
CellView cellAt(uint16_t x, uint16_t y) { return {&data[x*height + y], this}; }
struct Cell{
// uint16_t x, y;
// other fields
Cell* right(Container*);
Cell* above(Container*);
...
};
struct CellView{
// maybe: uint16_t x, y;
Cell* cell;
Container* container;
CellView right()const{ return {cell->right(container), container}; };
CellView above()const{ return {cell->above(container), container}; };
...
};
Basically move state into the "pointer" and out of the cell.
Here are two possible solutions that come to mind, given the limitations you've stated:
1) For all functions which need a Container to accomplish their work, just require the Container as a parameter.
For example:
Cell* Cell::right(Container* container)
{
return container->cellAt(x+1, y);
}
2) Instead of asking Cells about things which the Container knows, ask the Container about its Cells. In other words move the right, above, and similar functions to the Container.
For example:
Cell* Container::nextRightCell(Cell* from)
{
return cellAt(from->x+1, from->y);
}
Using an array of global Container and using polymorphism over Cell and over Container to have a template integer parameter where to store the index of the Container...
I don't think it's a good idea (Cell become a pure virtual abstract struct) but, just for fun...
#include <cstdint>
#include <iostream>
struct Cell
{
uint16_t x, y;
// other fields
virtual Cell* right() = 0;
//Cell* above();
};
class Container
{
private:
uint16_t width, height;
Cell* data;
public:
Container(uint16_t w0, uint16_t h0, Cell * d0)
: width(w0), height(h0), data(d0)
{ }
Cell* cellAt(uint16_t x, uint16_t y)
{ return &data[x*height + y]; }
};
Container * containers[10];
template <std::size_t I>
struct CellI : public Cell
{
Cell* right()
{ std::cout << I << std::endl; return containers[I]->cellAt(x+1, y); }
};
template <std::size_t I>
class ContainerI : public Container
{
public:
ContainerI (uint16_t w0, uint16_t h0)
: Container(w0, h0, new CellI<I>[w0*h0])
{ }
};
int main()
{
containers[0] = new ContainerI<0>(10, 20);
containers[1] = new ContainerI<1>(20, 40);
containers[2] = new ContainerI<2>(30, 60);
// ...
containers[0]->cellAt(5,5)->right(); // print 0
containers[1]->cellAt(5,5)->right(); // print 1
containers[2]->cellAt(5,5)->right(); // print 2
}
I have this code that in my mind, it recieved an item called Vehicle and it has to store it in an array called Node. This is the code related to this part of the program:
void Table::process(Vehicle v, int cont) {
char a='A'+cont;
putVehicle(a,v);
Node.a_v[cont]=v;
if(cont==0) a_surt=v.rowVehicle();
}
This is how I have the array on the private part of Table.h:
struct Node{
Vehicle a_v;
};
The error I get is:
error: expected primary-expression before '.' token
I have the includes I need, but everytime I type this: Node.a_v It gives me that error.
Any advice?
If you want to use a struct, you need to declare a Node before using it. Also, the struct needs to contain an array (or better, look into vectors for more flexibility).
struct Node {
Vehicle[10] a_v; // 10 is max number of Vehicles in array
};
Node myNode;
myNode.a_v[cont] = v;
Remember that if you want to keep this Node around and put more things in it, it needs to be declared in the right scope. For example, to have your process function add a Vehicle to a Node that exists outside of the function process, you could something like this:
void Table::process(Node n, Vehicle v, int cont) {
char a = 'A'+cont;
putVehicle(a,v);
if (cont < 10) {
n.a_v[cont] = v;
}
if (cont == 0) a_surt = v.rowVehicle();
}
It kind of looks like you're just trying to use an array. In that case you're looking for something like this:
// This would go somewhere in your program. Again, 10 is just an example.
Vehicle vehicleArray[10];
// Send this array to this function
void Table::process(Vehicle[] vArray, Vehicle v, int cont) {
char a = 'A'+cont;
putVehicle(a,v);
if (cont < 10) { // In a real program, don't hard-code array limits.
vArray[cont] = v;
}
if (cont == 0) a_surt = v.rowVehicle();
}
You should use Node object to get access to the a_v variable. This line
Node.a_v[cont]=v;
Is incorrect. You should do something like that:
Node n;
n.a_v[cont]=v;
everytime I type this: Node.a_v It gives me that error.
Node is a type; types define the structure of a objects, but they do not have fields of their own (except the static fields, which belong to all instances at once; they are accessed differently anyway).
In order to use a . or -> operator, you need an instance of a Node, like this:
Node x;
x.a_v = ...
It is not clear in your case from where the Node instances should be coming, though. In order to access them, you would need to either pass them in as parameters, or make them available statically/globally (not recommended).
Okay, so Node is NOT the name of your array. It's the name of a user-defined type that is supposed to contain an array. Your Node, however, does not contain an array. It contains one Vehicle, named a_v. I assume a_v is supposed to represent an Array of Vehicles. Therefore, you need to allocate the array. Something like this:
struct Node {
Vehicle a_v[AMOUNT];
};
If you don't know at compile-time how large you want your arrays to be, then they must be dynamically allocated, like this:
struct Node {
Vehicle* a_v;
Node() {
a_v = new Vehicle[AMOUNT];
}
};
If it's dynamically allocated, then it must also be deallocated:
struct Node {
Vehicle* a_v;
Node() {
a_v = new Vehicle[AMOUNT];
}
~Node() {
delete[] a_v;
}
};
AND if it's dynamically allocated, you need to add provisions for copying or disable copying:
struct Node {
Vehicle* a_v;
Node() {
a_v = new Vehicle[AMOUNT];
}
~Node() {
delete[] a_v;
}
// Disable copies (with C++11 support):
Node(const Node&) = delete;
Node& operator=(const Node&) = delete;
// Disable copies (without C++11 support) by making them private and not defining them.
private:
Node(const Node&);
Node& operator=(const Node&);
};
Then to access one of the Vehicles, you'd need to do so like this:
Node n; // Declare a node, which contains an array of Vehicles
n.a_v[cont] = v; // Copy a Vehicle into the array of Vehicles
Note, however, that if you declare the Node instance in this function, then it is local and it will go out of scope as soon as your function ends. You need to declare the Node instance as a member of your Table if you want it to persist past the function call.
class Table
{
private:
Node n;
};
Lastly, as others have suggested, I'd highly recommend that you read a C++ book to learn C++. My personal recommendation is this book (5th edition, don't buy 6th or 7th - the author of those editions is terrible).
I have struct like this:
struct element{
char ulica[10];
vector<int> dane[3];
int wolne;
int w;
element *lewy, *prawy, *ojciec;
};
And I'm implementing kind of AVL tree. When key's are the same i need to put some int values to dane (dane[0], dane[1], dane[2] describe 3 different value) so I use
tmp2->dane[0].push_back(number)
EDIT. Here is code where I'm adding a values to this vector, it's half of the function because secod half is about rotations in AVL.
void wstaw_wezel(){
element *tmp2; //tmp2 bedzie ojcem nowo wstawionego elementu
tmp2=korzen;
while(tmp2!=NULL){
if(strcmp(tmp2->ulica, tmp->ulica)<0){
if(tmp2->prawy!=NULL){
tmp2=tmp2->prawy;
}
else{
tmp->ojciec=tmp2;
tmp2->prawy=tmp;
cout<<"Wstawiam pod prawy "<<tmp2->ulica<<endl;
if(tmp2->w!=0) tmp2->w=0;
else tmp2->w=-1;
break;
}
}
else if(strcmp(tmp2->ulica, tmp->ulica)>0){
if(tmp2->lewy!=NULL){
tmp2=tmp2->lewy;
}
else{
tmp->ojciec=tmp2;
tmp2->lewy=tmp;
if(tmp2->w!=0) tmp2->w=0;
else tmp2->w=1;
cout<<"Wstawiam pod lewy "<<tmp2->ulica<<endl;
break;
}
}
else{
cout<<"2 bloki na tej samej ulicy"<<endl;
for(int i=0; i<tmp2->dane[0].size(); i++) cout<<tmp2->ulica<<" "<<tmp2->dane[0][i]<<endl;
tmp2->numery.push_back(tmp->numery[0]);
tmp2->dane[0].push_back(tmp->dane[0][0]);
for(int i=0; i<tmp2->dane[0].size(); i++) cout<<tmp2->ulica<<" "<<tmp2->dane[0][i]<<endl;
tmp2->dane[1].push_back(tmp->dane[1][0]);
tmp2->dane[2].push_back(tmp->dane[2][0]);
tmp2->wolne+=tmp->dane[2][0];
break;
}
}
if(tmp->ojciec==NULL){
korzen=tmp;
return;
}
where tmp2 is a pointer to this struct (I checked adrres where it points and every time it's the same adrres).
Where is problem? If I add new value to vector it is until the loop where i do it ends. Finally instead having fe. 4 values in vector i have one, the last added value. Vector don't add new value to the end, just replacing it.
You declare the initial size of a std::vector in its constructor, so one way you can accomplish this is:
struct element
{
char ulica[10];
std::vector<int> dane;
int wolne;
int w;
element *lewy, *prawy, *ojciec;
element() : dane(3) {}
};
If you don't include the constructor, the initial size of the vector will be 0. In any event, to add an element to the back, just use tmp2->dane.push_back(number); This will add the value in number to the back of the vector tmp2->dane which may result in a change in the amount of allocated memory for the vector instance.
UPDATE: Based on the comment from the OP that he needs three vectors try this:
struct element
{
char ulica[10];
std::vector<std::vector<int> > dane;
int wolne;
int w;
element *lewy, *prawy, *ojciec;
element() : dane(3) {}
};
To add elements to the vectors, simply use tmp2->dane[i].push_back(number) where i is the index of the vector to use, and number is the new number to add to the ith vector, which is the same convention you seem to be using in your code segment above.
Update 2: Based on additional information below, I think a redesign of your data structure is called for. You're mixing the meaning of the various components and by more clearly delineating the functions of the data element and the AVL data structure management, you will be able to more clearly distinguish between the two. So try this instead. Have a data structure specifically for the "value" portion of your tree nodes, as in:
struct house
{
int house_number;
int unique_value0;
int unique_value1;
house(int hn, int uv0, int uv2)
: house_number(hn),
unique_value0(uv0),
unique_value1(uv1) {}
};
template <typename VALUE> struct node
{
std::string key;
std::vector<VALUE> values;
int left, right;
node<VALUE> *leftNode, *rightNode, *parentNode;
};
From here, you create a root node:
node<house> *root;
When you want to add a house to a street, node<house> *s, all you need to do is
s->values.push_back(house(a, b, c));
Of course a better alternative is to use what C++ already has for this. That is, there is a structure in the standard library called std::multimap which does pretty much what you're trying to do. In this case, you can simple declare
std::multimap<std::string, house> myMap;
This probably won't use AVL balancing. It more likely will be a Red-Black Tree, but it's all done for you.
How do you alloc the struct element?, it seems that the vector<int> dane[3]; has been initialized successful, but its inner vector does not been initialised.
try to add a ctor method to the struct element?
struct element
{
char ulica[10];
vector<int> dane[3];
int wolne;
int w;
element *lewy, *prawy, *ojciec;
element()
{
dane[0] = vector<int>();
dane[1] = vector<int>();
dane[2] = vector<int>();
}
};