This question already has answers here:
Rationale of enforcing some operators to be members
(2 answers)
What are the basic rules and idioms for operator overloading?
(8 answers)
Closed 7 years ago.
I am working with Graphs, and writing code some well known algorithms. Currently I am working on the Dijkstra Algorithm.
So, I have made my own Heap class which works as a min-priority queue for the implementation of the Dijkstra algorithm. Since, in the Dijkstra algorithm, you need to update the distance of a vertex (which is already in the heap), from the source vertex in the Graph, if its distance is less than it's current distance, and then accordingly adjust the values in a Heap.
For this, I need to keep an int position[] array to keep a track of the positions at which the elements are currently in the Heap
This is my Vertex Class ::
class Node{
public:
int data;
int weight;
.....
friend int& operator [](int *a, Node i) {
return a[i.data];
}
};
My minPriorityQueue class ::
template <typename t>
class minPriorityQueue {
int size, currentPosition;
int *position;
t *data;
bool (*compare)(t data1, t data2);
public:
minPriorityQueue(int size, bool (*func1)(t data1, t data2), int *position) {
this->size = size;
currentPosition = 1;
data = new t[size];
compare = func1;
this->position = position;
}
........
void swapPositionValue(int parent, int temp) {
int tempPosition = position[data[parent]];
position[data[parent]] = position[data[temp]];
position[data[temp]] = tempPosition;
}
......
};
Since my vertices are 0,1,2,3, ... So, I try to overload the []operator of my Vertex class so that it returns me the data of the current vertex (which is one from 0,1,2,3 ..., so I can use it to access that index of the position array.
I get the compilation error :: error: 'int operator[](int*, graph::Vertex)' must be a nonstatic member function
Well, since I get this error I assume that it must have been specified in the standard that I cannot overload the []operator using a friend function, but why I cannot do it?? Does it lead to any ambiguity? I don't see what can be ambiguous in what I am currently using.
Secondly, is there any way I can swap the values in my position array? My minPriorityQueue class is a generic class which I am using at several other places at my code as well. In the function swapPositionValue if I change my swap statements to this ::
int tempPosition = position[data[parent].data];
position[data[parent].data] = position[data[temp].data];
position[data[temp].data] = tempPosition;
Then the whole idea of "generic" priority queue will be sacrificed! Since, it won't work with other classes!
Is there a way that I can achieve this functionality??
EDIT1 :: The complete Code :: http://ideone.com/GRQHHZ
(Using Ideone to paste the code, Because the code is still very large, containing 2 classes)
This is what I am trying to achieve :: http://www.geeksforgeeks.org/greedy-algorithms-set-7-dijkstras-algorithm-for-adjacency-list-representation/
(I am just using the algorithm)
Explanation of what is the functionality of operator[]::
In my Dijkstra implementation all the nodes are initially inserted into the Heap, with the start node, having the weight = 0, and all the other nodes with weight = INFINITY (which means I cannot reach the vertices) so start vertex is the topmost element of the heap! Now when I remove the topmost element, all the Node that have a path from the removed Node will get modified, their weight will be modified from INFINITY to some finite value. So, I need to update the Nodes in the Heap, and then I need to move them to their correct positions, according to their new weights!! To update their weights, I need to know at what position are the Nodes located in the Heap, and the position is decided by the data of the Node. So, overloading the []operator was just a small way out for me, so that when I do position[Node], I can access position[Node.data].
Why this is not a duplicate:: The linked question is a broad operator overloading post, it just mentions 1 point where it states that []operator can only be overloaded with member functions and not otherwise, does not state why! And this is a specific problem I am facing where I do not want to sacrifice the generic property of my self made Heap, and use it for the Dijkstra as well.
EDIT2 :: While writing this explanation I realize I had made a big mistake in my overloaded function. I have changed it! Please check it. Probably it makes more sense now. Apologies!!
The overloaded function now looks like ::
friend int& operator [](int *a, Node i) {
return a[i.data];
}
EDIT3 :: In implement my Graph class with Adjacency Matrix, and it is a boolean 2D array, because my current implementation is for Unweighted graphs, and accordingly the shortest path becomes the least number of edges traversed! (Just in case that mattered!)
Thanks for reading all of this huge question, and for any help! :)
Related
I am developing a Barnes–Hut simulation in C++ for a course project. Here you can find a detailed explanation of the algorithm.
I briefly explain the datatypes I will use later.
A body is represented by the Body datatype, which is a struct containing a Vector2f representing the position, and a float for the mass).
A node in the quadtree is represented by the Node datatype. Of course, the node struct contains some data, which can be: 1) Its four children, corresponding to its four subquadrants. This holds only the node is a fork in the tree. 2) Its body. This holds only when the node is a leaf of the tree. 3) Empty. This holds when the node does not contain any body. Therefore, data is a std::variant.
I wrote the recursive function that calculates the net force acting on a body. It takes in input a Node (at the first call, the quadtree's root) and the Body we want to query, and returns a Vector2f representing the net force acting on the body.
Of course, the function needs to visit the variant and dispatch to the correct lambda.
Vector2f compute_approximate_net_force_on_body(const Node& node,
const Body& body) {
const auto visit_empty = [](const Empty&) -> Vector2f { return {0, 0}; };
const auto visit_body = [body](const Body& visited) -> Vector2f {
return compute_gravitational_force(visited, body);
};
const auto visit_region = [&](const Subquadrants& subquadrants) -> Vector2f {
float distance = (body.m_position - node.center_of_mass()).norm();
if (node.length() / distance < OMEGA) {
// Approximation
return bh::compute_gravitational_force(
{node.center_of_mass(), node.total_mass()}, body);
} else {
return std::accumulate(
subquadrants.begin(), subquadrants.end(), Vector2f{0, 0},
[body](const Vector2f& total, const std::shared_ptr<Node>& curr) {
return (total + compute_approximate_net_force_on_body(*curr, body))
.eval();
});
}
};
return std::visit(overloaded{visit_empty, visit_body, visit_region},
node.data());
}
The interesting part is the one with accumulate. Essentially, it invokes the algorithm recursively, with the same node and the four node's subquadrants, and accumulates the result into a Vector2f.
Since that the four calls are completely independent, I thought that I could make the computation parallel. Initially, I converted the accumulate into a reduce, but I later discovered that this can't work because
the types of the signature of the binary operation function must be identical (mine are not);
The binary operation must be associative and commutative (mine is not).
I am looking for suggestions on how to parallelize the recursive calls, possibly using the STL library. If possible, the C++ standard must be C++17 or below. One approach that I have in mind is to use std::async and std::future, but it is less elegant than the accumulate-like one. Are there any other else?
Thank you for your insights.
Closed. This question needs details or clarity. It is not currently accepting answers.
Want to improve this question? Add details and clarify the problem by editing this post.
Closed 5 years ago.
Improve this question
I've been searching lots of sites and browsed few books about this but failed to come across to find good sources about implementation of how to dynamically (within execution of the program) compare different datatypes in a class with less- < or , bigger than > operators.
Let's say we've the following snippet code:
#include <iostream>
using namespace std;
class OP
{
private:
string alias;
float locatorX;
int coordinate;
public:
bool operator<(const OP& rhs)
{
return (this->locatorX < rhs.locatorX);
//Here! How do I do to make the compiler understand that
//I compare i.e alias or coordinate whenever I need?
//I tried with:
return (this->coordinate < rhs.coordinate, this->alias < rhs.alias);
//But it didn't really do the trick when implemented
//a sort algorithm inside main as it failed to sort a string array.
}
};
EDIT:
Since most of the kind people here did not understand the question, here is a scenario which you hopefully get.
Let us say we want to create a map that accepts a string, int and float types. We create a function inside of the class OP that accepts all given datatypes and saves them in the created class array. And so we have i.e 15 records in our class array.
How do I do so that I can dynamically bubble sort (with help of < operator), alias (string) locatorX(float) and coordinate(int) (whichever I choose) in ascending order with less than operator?
For example I somewhat need to sort coordinates or alias (if needed) at run time. How do I do this?
Example output:
(First position in array):
"Albert street 5th"
Coordinate: 1691
locatorX: 19.52165
(Second position in array):
"Main street 7th alley"
Coordinate: 59
locatorX: 8175. 12
(Third position in array):
"Elm/Kentucky"
Coordinate: 9517
locatorX: 271.41
Typically you'd create a separate comparator for each comparison you wish to implement. You can't munge them into a single operator< and, although you could technically produce a different function that performed a different comparison depending on the value of some new, third argument, it would be incompatible with almost everything currently existing that knows how to work with comparators.
This is one of the scenarios in which operator overloading specifically is the wrong tool for the job.
There seems to be several ways to do so:
Switch between comparison functions at the call site
You have to define separate compare functions for different fields.
std::vector<Object> v;
enum class OrderBy
{
alias,
coordinate
}
OrderBy order_by = get_orderBy_from_user();
switch (order_by)
{
case OrderBy::alias:
std::sort(v.begin(), v.end(), compare_by_alias());
break;
case OrderBy::coordinate:
std::sort(v.begin(), v.end(), compare_by_coordinate());
break;
}
Make a choice inside a comparison function.
You must communicate the choice of ordering field somehow into the function.
The options are: global or singleton "configuration" object, member variable in the comparison class. I would avoid any globals, thus the second option:
struct compare_by_field
{
OrderBy order_by_;
compare_by_field(OrderBy order_by) : order_by_(order_by)
{}
bool operator()(const Object & lhs, const Object & rhs) const
{
switch (order_by_)
{
case OrderBy::alias:
return lhs.alias < rhs.alias;
case OrderBy::coordinate:
return lhs.coordinate < rhs.coordinate;
}
}
}
std::sort(v.begin(), v.end(), compare_by_field(get_order_by_from_user()));
I have items in array created from this struct:
struct ks{
int cap;
int val;
};
Array is named items and contains quantity of items.
items = new ks[quantity];
I want to put them in priority queue - which basically means sort them.
This is my compare function:
struct itemsCompare{
bool operator () (const ks &item1, const ks &item2){
if (item1.val/item1.cap > item2.val/item2.cap) return true;
return false;
}
};
How should creating of this queue looks like?
priority_queue <ks, What should I put here?, itemsCompare> comparedItems;
for(int i=0; i<quantity; i++) comparedItems.push(items[i]);
I know, that template requires having vector as container. How should I modify code to make it work? I know that I can put items into vector just before declaration of priority queue, but I'm curious if there's a way to do it just with array.
To create a std::priorty_queue from the array you can use
std::priority_queue <ks, std::vector<ks>, itemsCompare> comparedItems(items, items + quantity);
Answering the question as asked:
std::priority_queue <ks, std::vector<ks>, itemsCompare> comparedItems;
However, the question has some issues not directly asked. First, it sports division on uncontrolled substances :). What is going to happen if you divide by 0?
Second. You divide integer by integer. This result is always integer, and somehow I doubt this is what you want.
I'm working on an octree implementation where the tree nodes are templated with their dimensional length (as a power of 2):
template<long N>
struct node_t {
enum { DIM = 1 << N };
node_t<N+1> * parent;
node_t<N-1> * children[8];
long count;
}
And specialized for N = 0 (leaves) to point to data.
struct node_t<0> {
enum { DIM = 1 };
node_t<1> * parent;
data_t data;
long count;
}
(Aside: I suppose I probably also need a specialization for N_MAX that excludes a parent pointer, or else C++ will generate types of increasing N ad finitum? But that's not really relevant to my question.)
I'd like to create a function that steps along a ray in the 3D space that my octree occupies, so ostensibly I could just keep a pointer to the root node (which has a known type) and traverse the octree from the root at every step. However, I would prefer a more 'local' option, in which I can keep track of the current node so that I can start lower in the tree when possible and thus avoid unnecessarily traversing the upper nodes of the octree.
But I don't know what that type pointer could be (or any other way of implementing this) so that I don't experience slicing.
I'm not tied down to templates, as the dimension can simply be implemented as a long const. But then I don't know how to make it so that the leaves have a different child type than inodes.
Thanks for your help!
Update
The reason I'd like to do it this way rather than something similar to this is because of the count variable in each node: if the count is 0, I'd like to jump through the whole cube, rather wasting time going through leaves that I know to be empty. (This is for a raytracing voxel engine.)
As much as I love templates, your code might actually be simpler with:
class node {
node* parent; // NULL for root node
long dim;
long count;
virtual rayTrace(Ray) = 0;
};
class leafNode : node {
data_t data;
virtual rayTrace(Ray);
};
class nonLeafNode : node {
vector<node*> children;
virtual rayTrace(Ray);
};
This has the advantage that the tree can be whatever depth you want, including some subtrees can be deeper than others. It has the downside that dim must be computed at runtime, but even that has the silver lining that you can make it a double if your tree gets really big.
I'm writing a sparse matrix class in C++ in which every row and column are arrays of linked lists from a class I created (aptly named: LinkedList).
I want to write a class that is a "smart" pointer to one cell in this matrix.
In that class, let say LIPointer, I will implement a ++ operator function for moving in the linked lists of the matrix.
Is there an elegant way of doing this without moving the references of the matrix arrays and sized elements each time I create a linkedlistPointer?
I can't use stl::array etc. because I have to build them myself.
Here are the declarations:
class LinkedItem
{
private:
int Column, Row;
double Value;
LinkedItem* Right;
LinkedItem* Down;
public:
...
};
class SparseLinkedMatrix
{
private: //members
int ColSize;
int RowSize;
LinkedItem ** Columns;
LinkedItem ** Rows;
public: //functions
SparseLinkedMatrix();
...
};
class LIPointer;
private:
LinkedItem * CellPointer;
public:
LIPointer();
void operator++();//???
...
};
Any advice or direction would be appreciated.
Update: It needs to run on the whole matrix. That is why I think I need to move (by reference) the arrays and the size of the matrix. The intended effect is that this would from the last cell in the linked list of the first row to the first cell in the second row.
For compressed row matrices, I use something like:
std::vector<std::map<size_t, double> > matrix;
I can then add an entry using:
matrix[row][col] += val;
For each row, I can then iterate through the column entries in ascending order and read out the value.
Edit: The person posing the question does point out that they cannot use the STL. Perhaps they can use some kind of map versus a linked list. Otherwise I suggest using a vector of linked lists and keep adding entries to the end of each list. Then do a sort of each linked list when adding entries has been completed.
Can you please elaborate on exactly what you want operator++() to do?
For instance, to have LIPointer's operator++() go to the next right element:
void operator++()
{
if ( CellPointer != NULL )
CellPointer = CellPointer->Right;
}
It stops when it gets to the end, though.