construction of a concept lattice - c++

I'm working for my project of the end of the year with c++ language and I'm really stressed because I have 5 days in this error and there is no enough time . I hope you help me :
the error is:
no match for 'operator<<' in 'std::operator<< <std::char_traits<char> >((* &(& std::operator<< <std::char_traits<char> >((* & tempout.std::basic_ofstream<char>::<anonymous>), ((const char*)"Node ")))->std::basic_ostream<_CharT, _Traits>::operator<< <char, std::char_traits<char> >(i.__gnu_cxx::__normal_iterator<_Iterator, _Container>::operator-><Lattice<std::pair<std::vector<int>, std::vector<int> > >::Node*
the line of the error is : tempout<<"Node " << i->index << ": " <<i->c<<endl; and more sepifically in i->c
My code is the following:
//template named N
template<typename N>
//class latice that contains structure Node and other attribytes
class Lattice {
public:
int count; //count is incremented at every Node insertion in the latticeSet
typedef std::pair<std::vector<int>, std::vector<int> > Concept;
// Node is a set of concepts
//a latticeSet is a set of Node
struct Node {
int index;
typedef std::pair<std::vector<int>, std::vector<int> > Concept;
Node() {}; //constructor
Node(const N& con, int i) : c(con), index(i) {};
N c;
bool operator== (const Node& n) const { return c.first == n.c.first; }
std::pair<std::vector<int>,std::vector<int> > lowerUpperNeighbors;
};
std::vector<Node> latticeSet;//a set of Node
int last_position_cached;
bool was_insert_called;
Lattice() : count(0), last_position_cached(0), was_insert_called(false) {} //constructor
friend ostream& operator<< ( std::ostream& out,const Concept &c) {
out << "{";
if (c.first.size()!=0) {
for(std::vector<int>::const_iterator j = c.first.begin(); j < c.first.end() - 1; ++j)
out << *j << ", ";
out << *(c.first.end() - 1);
}
out << "}, {";
if (c.second.size()!=0) {
for(vector<int>::const_iterator j = c.second.begin(); j < c.second.end() - 1; ++j)
out << *j << ", ";
out << *(c.second.end() - 1);
}
out << "}";
return out;
}
/* The following method is a combination of both insert(x, L) and lookup(x, L) from the FCA Lattice Algorithm.
insertLookup takes a reference to a concept x, and c as input.
Concept x is an upper neighbor of c found by Neighbors, and c is the concept in which x was found to be its upper neighbor.
First, latticeSet is searched for the upper neighborx of c, and if it is not found then it is inserted in the lattice (same fashion as insert).
Next, the lattice is checked if it contains concept c, and if it does then the method returns false due to some unexpected case.
This condition is checked if insert was called, and if the last position of a concept cached by next is not equal to c.
Then, the lattice is searched for concept c in order to add its upper neighbor x.
Finally, concept x/c adds concept c/x as its lower/upper neighbor, respectively.
This method returns true if concept x was inserted in the lattice and c was added to its upper neighbors.
*/
bool insertLookup(const N& x, const N& c) {
std::vector<Node> latticeSet;
typename vector<Node>::iterator x_pos = find(latticeSet.begin(), latticeSet.end(), Node(x, count));
if (x_pos == latticeSet.end()) {
latticeSet.push_back(Node(x, count++));
x_pos = latticeSet.end() - 1;
}
typename vector<Node>::iterator c_pos;
if (was_insert_called && !(latticeSet[last_position_cached].c.first == c.first)) {
c_pos = find(latticeSet.begin(), latticeSet.end(), Node(c, count));
if (c_pos == latticeSet.end()) {
return false;
}
}
else
c_pos = latticeSet.begin() + last_position_cached;
x_pos->lowerUpperNeighbors.first.push_back(c_pos->index);
c_pos->lowerUpperNeighbors.second.push_back(x_pos->index);
return true;
}
//This method inserts a concept in the concept lattice.
bool insert(const N& c) {
latticeSet.push_back(Node(c, count++));
was_insert_called = true;
return true;
}
bool next(const N& c, N& output) {
typename vector<Node>::iterator pos = find(latticeSet.begin(), latticeSet.end(), Node(c, 0));
if (pos == latticeSet.end() || ++pos == latticeSet.end())
return false;
output = pos->c;
last_position_cached = pos - latticeSet.begin();
return true;
}
/* The following method is used to generate the required input file for graphplace.
printGraphplaceInput takes a reference to an output file stream out, and a flag (with a default value of zero).
First an output file stream tempout is in- stantiated with a file called “explain.graph” (see section 4.2).
If the flag passed is zero, then each Node’s concept of the latticeSet is printed to the lattice output file out;
else if the flag passed equals one, then each Node’s unique index number of the latticeSet is printed to the lattice output file out.
During the creation of the lattice output file, “explain.graph” is created by writing each Node index and its corresponding concept to tempout.
This method returns nothing.
*/
void printGraphplaceInput(ofstream& out, int flag = 1) {
ofstream tempout("explain.graph");
for (typename std::vector<Node>:: iterator i = latticeSet.begin(); i!=latticeSet.end();++i) {
//the error is here in i->c it doesn't work .and the error is that na match for operator<< and i didi'nt find a solution
tempout << "Node " << i->index << ": " << i->c <<endl;
out << "(";
if(flag == 0) {
cout << i->index << endl;
}
else if(flag == 1) {
out << i->index;
}
out << ") " << i->index << " node" << endl;
for (typename vector<int>::iterator j = i->lowerUpperNeighbors.second.begin(); j < i->lowerUpperNeighbors.second.end();++j)
out << *j << " " << i->index << " edge" << endl;
}
};
//get the size of the lattice
unsigned int getLatticeSize() {
return latticeSet.size();
}
void LatticeAlgorithm(const Context& GMI, Lattice<Concept>& L) {
vector<int> temp;
Concept c;
GMI.objDPrime((const vector<int>&) temp, c.first);
GMI.objPrime((const vector<int>&) temp, c.second);
L.insert(c);
neighbors n;
vector<Concept> neighborSet;
do {
n.Neighbors(c, GMI, neighborSet);
for(vector<Concept>::const_iterator x = neighborSet.begin(); x < neighborSet.end(); ++x) {
L.insertLookup(*x, c);
}
}
while(L.next(c, c));
}

Related

Storing equal objects in a set

What I'm trying to do: order elements in the set by elem->value, but still recognize that they're distinct elements based on the memory address they're pointing to.
#include <iostream>
#include <set>
using namespace std;
struct Node {
int value;
Node(int v) : value(v) {}
};
int main()
{
Node* a = new Node(10);
Node* b = new Node(10);
Node* c = new Node(20);
if (a == b) {
cout << "a == b" << endl;
}
if (a == c) {
cout << "a == c" << endl;
}
auto comparator = [](Node* lhs, Node* rhs) {
return lhs->value < rhs->value;
};
set<Node*, decltype(comparator)> s(comparator);
s.insert(a);
s.insert(b);
s.insert(c);
cout << "after inserts, s.size() = " << s.size() << endl;
s.erase(a);
cout << "after erase, s.size() = " << s.size() << endl;
delete(a);
delete(b);
delete(c);
return 0;
}
Since a != b, I expect to get:
after inserts, s.size() = 3
after erase, s.size() = 2
But instead, I get:
after inserts, s.size() = 2
after erase, s.size() = 1
With lhs->value <= rhs->value, I get:
after inserts, s.size() = 3
after erase, s.size() = 3
With multiset, I get:
after inserts, s.size() = 3
after erase, s.size() = 1
You should use the memory address for tie-break.
Example:
auto comparator = [](Node* lhs, Node* rhs) {
return lhs->value < rhs->value ||
(lhs->value == rhs->value && lhs < rhs);
};

unordered_map for custom class does not cause error when inserting the same key

I'm trying to figure out some points on using unordered_map for custom class. Below are the codes I use to take exercise where I define a simple class Line. I'm confused that why the insertion of Line2 in main() does not make the program outputs insert failed when the value of m for Line1 and Line2 are both 3. Note since I only compare the first value (i.e. m) in the operator== function in class Line, thus Line1 and Line2 in this code should have the same key. Shouldn't the insertion of an already existed key be invalid? Could some one explain why to me? Thanks!
#include<iostream>
#include<unordered_map>
using namespace std;
class Line {
public:
float m;
float c;
Line() {m = 0; c = 0;}
Line(float mInput, float cInput) {m = mInput; c = cInput;}
float getM() const {return m;}
float getC() const {return c;}
void setM(float mInput) {m = mInput;}
void setC(float cInput) {c = cInput;}
bool operator==(const Line &anotherLine) const
{
return (m == anotherLine.m);
}
};
namespace std
{
template <>
struct hash<Line>
{
size_t operator()(const Line& k) const
{
// Compute individual hash values for two data members and combine them using XOR and bit shifting
return ((hash<float>()(k.getM()) ^ (hash<float>()(k.getC()) << 1)) >> 1);
}
};
}
int main()
{
unordered_map<Line, int> t;
Line line1 = Line(3.0,4.0);
Line line2 = Line(3.0,5.0);
t.insert({line1, 1});
auto x = t.insert({line2, 2});
if (x.second == false)
cout << "insert failed" << endl;
for(unordered_map<Line, int>::const_iterator it = t.begin(); it != t.end(); it++)
{
Line t = it->first;
cout << t.m << " " << t.c << "\n" ;
}
return 1;
}
Your hash and operator == must satisfy a consistency requirement that they currently violate. When two objects are equal according to ==, their hash codes must be equal according to hash. In other words, while non-equal objects may have the same hash code, equal objects must have the same hash code:
size_t operator()(const Line& k) const {
return hash<float>()(k.getM());
}
Since you compare only one component for equality, and ignore the other component, you need to change your hash function to use the same component that you use to decide the equality.
you are using both the values of "m" and "c" in you hash, so 2 "Line" instances would have the same key if both their "m" and "c" are equal, which is not the case in your example. So if you do this :
Line line1 = Line(3.0,4.0);
Line line2 = Line(3.0,4.0);
t.insert({line1, 1});
auto x = t.insert({line2, 2});
if (x.second == false)
cout << "insert failed" << endl;
you'll see that it will print "insert failed"
You can always use custom function to compare the keys upon insertion:
#include <iostream>
#include <unordered_map>
class Line {
private:
float m;
float c;
public:
Line() { m = 0; c = 0; }
Line(float mInput, float cInput) { m = mInput; c = cInput; }
float getM() const { return m; }
float getC() const { return c; }
};
struct hash
{
size_t operator()(const Line& k) const
{
return ((std::hash<float>()(k.getM()) ^ (std::hash<float>()(k.getC()) << 1)) >> 1);
}
};
// custom key comparison
struct cmpKey
{
bool operator() (Line const &l1, Line const &l2) const
{
return l1.getM() == l2.getM();
}
};
int main()
{
std::unordered_map<Line, int, hash, cmpKey> mymap; // with custom key comparisom
Line line1 = Line(3.0, 4.0);
Line line2 = Line(4.0, 5.0);
Line line3 = Line(4.0, 4.0);
auto x = mymap.insert({ line1, 1 });
std::cout << std::boolalpha << "element inserted: " << x.second << std::endl;
x = mymap.insert({ line2, 2 });
std::cout << std::boolalpha << "element inserted: " << x.second << std::endl;
x = mymap.insert({ line3, 3 });
std::cout << std::boolalpha << "element inserted: " << x.second << std::endl;
return 0;
}
Prints:
element inserted: true
element inserted: true
element inserted: false

Coordinate iterator of point

How can I get a coordinate iterator of a Point p where Point is fulfilling the Point Concept?
It depends what's the Point type exactly. If you're using bg::model::point<> then this may be problematic since the run-time to compile-time translation of dimension index is needed, so e.g. some number of if conditions in a for-loop or recursive function (as you implemented).
However you could also implement your own Point type and define whatever members you need (e.g. operator[]) or use Point type already implemented in another library (assuming that max dimension is known at compile-time). Then, to let know Boost.Geometry how to handle your Point type you'd be forced to adapt it to Point concept by:
using macros provided by Boost.Geometry for typical 2D and 3D cases
specializing traits the same way how it's done e.g. for model::point_xy<> or model::point<>
I need a coordinate iterator to calculate the smallest enclosing ball (minimum bounding sphere/circle) of points of a (boost geometry) linestring using this library. The following solution contains a modified version of this example at the end:
#include <boost/geometry.hpp>
#include "Miniball.hpp"
namespace bg = boost::geometry;
template<std::size_t>
struct int2type {
};
template<class Point, std::size_t I>
typename bg::coordinate_type<Point>::type
get_imp(std::size_t index, const Point &point, int2type<I>) {
return (I == index)
? bg::get<I>(point)
: get_imp(index, point, int2type<I - 1>());
}
template<class Point>
typename bg::coordinate_type<Point>::type
get_imp(std::size_t index, const Point &point, int2type<0>) {
return bg::get<0>(point);
}
template<class Point>
typename bg::coordinate_type<Point>::type
get(std::size_t index, const Point &point) {
static std::size_t const size = bg::dimension<Point>::value;
return get_imp(index, point, int2type<size - 1>());
}
template<class Point, std::size_t I>
void set_imp(std::size_t index,
Point &point,
typename bg::coordinate_type<Point>::type value,
int2type<I>) {
return (I == index)
? bg::set<I>(point, value)
: set_imp(index, point, value, int2type<I - 1>());
}
template<class Point>
void set_imp(std::size_t index,
Point &point,
typename bg::coordinate_type<Point>::type value,
int2type<0>) {
return bg::set<0>(point, value);
}
template<class Point>
void set(std::size_t index, Point &point, typename bg::coordinate_type<Point>::type value) {
static std::size_t const size = bg::dimension<Point>::value;
return set_imp(index, point, value, int2type<size - 1>());
}
template<class Point>
class CoordinateIterator {
using self_t = CoordinateIterator<Point>;
public:
using iterator_category = std::forward_iterator_tag;
using value_type = typename bg::coordinate_type<Point>::type;
using difference_type = std::size_t;
using pointer = value_type *;
using reference = value_type &;
private:
Point _point;
difference_type _pos;
public:
CoordinateIterator()
: CoordinateIterator(Point()) {}
CoordinateIterator(Point point)
: CoordinateIterator(point, 0) {}
CoordinateIterator(Point point, difference_type pos)
: _point(point), _pos(pos) {}
inline value_type operator*() {
return get(_pos, _point);
}
inline const value_type operator*() const {
return get(_pos, _point);
}
inline self_t &operator++() {
++_pos;
return *this;
}
inline self_t operator++(int) {
self_t copy(*this);
++_pos;
return copy;
}
};
template<typename Linestring>
struct CoordinateAccessor {
using Pit = typename Linestring::const_iterator;
using Cit = CoordinateIterator<typename bg::point_type<Linestring>::type>;
inline Cit operator()(Pit it) const { return Cit(*it); }
};
int main(int argc, char *argv[]) {
using point = bg::model::point<double, 2, bg::cs::cartesian>;
using linestring = bg::model::linestring<point>;
using coordinate_type = bg::coordinate_type<linestring>::type;
using PointIterator = CoordinateAccessor<linestring>::Pit;
const int dimension = bg::dimension<linestring>::value;
const int numberOfPoints = 1000000;
// initialize random number generator
const double seed = (argc != 2) ? 0 : std::atoi(argv[1]);
std::srand(seed);
// generate random points and store them in a linestring
// ----------------------------------------------------------
linestring line;
for (int i = 0; i < numberOfPoints; ++i) {
point p;
for (int j = 0; j < dimension; ++j) {
set(j, p, rand());
}
bg::append(line, p);
}
// create an instance of Miniball
// ------------------------------
using MB = Miniball::Miniball<CoordinateAccessor<linestring>>;
MB mb(dimension, line.begin(), line.end());
// output results
// --------------
// center
std::cout << "Center:\n ";
const coordinate_type *center = mb.center();
for (int i = 0; i < dimension; ++i, ++center)
std::cout << *center << " ";
std::cout << std::endl;
// squared radius
std::cout << "Squared radius:\n ";
std::cout << mb.squared_radius() << std::endl;
// number of support points
std::cout << "Number of support points:\n ";
std::cout << mb.nr_support_points() << std::endl;
// support points on the boundary determine the smallest enclosing ball
std::cout << "Support point indices (numbers refer to the input order):\n ";
MB::SupportPointIterator it = mb.support_points_begin();
PointIterator first = line.begin();
for (; it != mb.support_points_end(); ++it) {
std::cout << std::distance(first, *it) << " "; // 0 = first point
}
std::cout << std::endl;
// relative error: by how much does the ball fail to contain all points?
// tiny positive numbers come from roundoff and are ok
std::cout << "Relative error:\n ";
coordinate_type suboptimality;
std::cout << mb.relative_error(suboptimality) << std::endl;
// suboptimality: by how much does the ball fail to be the smallest
// enclosing ball of its support points? should be 0
// in most cases, but tiny positive numbers are again ok
std::cout << "Suboptimality:\n ";
std::cout << suboptimality << std::endl;
// validity: the ball is considered valid if the relative error is tiny
// (<= 10 times the machine epsilon) and the suboptimality is zero
std::cout << "Validity:\n ";
std::cout << (mb.is_valid() ? "ok" : "possibly invalid") << std::endl;
// computation time
std::cout << "Computation time was " << mb.get_time() << " seconds\n";
return 0;
}

Quick Sort applied to a vector of pointers to objects - infinite loop

I cannot figure out why the algorithm results in an infinite loop. I am trying to sort the vector according to the final price. The pivot always stays the same. Maybe the problem is with the swapping of the objects
Motorbike findPivotPricee(vector<Motorbike*>& available, int left, int right)
{
int center = (left + right) / 2;
if (available[center]->finalPrice() < available[left]->finalPrice())
{
swap(*available[left], *available[center]);
}
if (available[right]->finalPrice()< available[left]->finalPrice())
{
swap(*available[left], *available[right]);
}
if (available[right]->finalPrice() < available[center]->finalPrice())
{
swap(*available[center], *available[right]);
}
Motorbike pivot = *available[center];
swap(*available[center], *available[right - 1]);
return pivot;
}
void quickSortMotorbikeByPrice(vector<Motorbike*>& available, int left, int right)
{
int i = left;
int j = right-1;
Motorbike pivot = findPivotPricee(available, left, right);
cout << pivot.finalPrice() << endl;
while (i < j)
{
while (available[i]->finalPrice() < pivot.finalPrice())
{
i++;
}
while (available[j]->finalPrice() > pivot.finalPrice())
{
j--;
}
if (i <= j)
{
swap(*available[i], *available[j]);
i++;
j--;
}
else {
break;
}
}
swap(*available[i], *available[right - 1]);//restore the pivot
if (left < right) {
if (left<j) quickSortMotorbikeByPrice(available, left, j);
if (right>i) quickSortMotorbikeByPrice(available, i, right);
}
}
void quickSortMotorbikeByPrice(vector<Motorbike*>& available)
{
quickSortMotorbikeByPrice(available, 0, available.size() - 1);
}
Often, algorithms from wikipedia, e.g. the quicksort algorithms are hard to transform into a working implementation because they fail to point out the assumed programming model implied by the given algorithm. For example, if it is a 0 based or a 1 based array and that they assume that the indices used are signed not unsigned integers.
Then, people start trying to use those algorithms, here, for example in C++ and run into all sorts of problems. Quite a waste of time... And from looking at the code given in the question, I assume the author of the question tried to use info from wikipedia...
Since this is obviously homework, impress your teacher and use the code below. Quicksort is tricky to get right and it can take quite a while to find out if you should write lo = left + 1 or lo = left etc.
#include <cstdint>
#include <memory>
#include <vector>
#include <iostream>
#include <cassert>
template <class X>
void vswap(std::vector<X>& v, size_t i1, size_t i2)
{
X temp = v[i1];
v[i1] = v[i2];
v[i2] = temp;
}
template <typename X>
std::ostream& operator<<(std::ostream& stm, const std::vector<X>& v)
{
stm << "[|";
size_t i = 0;
for (auto& x : v)
{
if (0 == i)
stm << x;
else
stm << "; " << x;
i++;
}
stm << "|]";
return stm;
}
template <typename X>
std::ostream& operator<<(std::ostream& stm, const std::vector<X*>& v)
{
stm << "[|";
size_t i = 0;
for (auto& x : v)
{
if (0 == i)
if (nullptr == x) stm << "nullptr"; else stm << *x;
else
if (nullptr == x) stm << "; nullptr"; else stm << "; " << *x;
i++;
}
stm << "|]";
return stm;
}
template <class X, class Predicate>
size_t partition(std::vector<X> & v, Predicate p, size_t left, size_t right)
{
size_t boundary = left;
X x = v[boundary];
for (size_t i = left; i < right; i++)
{
if (p(v[i], x))
{
vswap(v, boundary, i);
boundary++;
}
}
return boundary;
}
template<class X, class Predicate>
void mysort(std::vector<X> & v, Predicate p, size_t left, size_t right)
{
//std::cout << "mysort: " << v << " " << left << " " << right << std::endl;
if ((right - left) > 1)
{
size_t boundary = partition(v, p, left, right);
//std::cout << "boundary = " << boundary << std::endl;
mysort(v, p, left, boundary);
mysort(v, p, boundary == left ? boundary + 1 : boundary, right);
}
}
class Motorbike
{
size_t m_id;
int32_t m_finalPrice;
public:
Motorbike()
: m_id(0)
, m_finalPrice(0)
{}
Motorbike(size_t id, int32_t finalPrice)
: m_id(id)
, m_finalPrice(finalPrice)
{}
void Id(size_t id)
{
m_id = id;
}
size_t Id() const
{
return m_id;
}
void Price(int32_t price)
{
m_finalPrice = price;
}
int32_t Price() const
{
return m_finalPrice;
}
};
std::ostream& operator<< (std::ostream& stm, const Motorbike& bike)
{
stm << "(" << bike.Id() << ", " << bike.Price() << ")";
return stm;
}
std::vector<Motorbike> randomBikes(size_t count, int32_t lowPrice = 100, int32_t highPrice = 1000)
{
std::vector<Motorbike> result;
result.resize(count);
for (size_t i = 0; i < count; i++)
{
result[i].Id(i);
result[i].Price(lowPrice + rand() * (highPrice - lowPrice) / RAND_MAX);
}
return result;
}
std::vector<Motorbike*> bikePointers(std::vector<Motorbike> & bikes)
{
std::vector<Motorbike*> result;
result.resize(bikes.size());
for (size_t i = 0; i < bikes.size(); i++)
{
result[i] = &bikes[i];
}
return result;
}
int main()
{
//_CrtSetDbgFlag(_CRTDBG_CHECK_ALWAYS_DF);
//_CrtDumpMemoryLeaks();
//{
//{
// std::vector<int32_t> data = { 3, 5, 1, 4, 2, 0 };
// std::cout << "original: " << data << std::endl;
// mysort(data, [](int32_t a, int32_t b) -> bool {return a < b;}, 0, data.size());
// std::cout << "sorted? " << data << std::endl;
//}
//std::cout << "--------------------------------------------------------" << std::endl;
//{
// std::vector<int32_t> data = { 3, 6, 1, 4, 2, 0, 5 };
// std::cout << "original: " << data << std::endl;
// mysort(data, [](int32_t a, int32_t b) -> bool {return a < b;}, 0, data.size());
// std::cout << "sorted? " << data << std::endl;
//}
for(size_t run = 0; run < 10; run++)
{
auto bikes = randomBikes(5+run%2);
auto bikes_p = bikePointers(bikes);
std::cout << "original: " << bikes_p << std::endl;
mysort(bikes_p, [](const Motorbike* m1, const Motorbike* m2)-> bool { return m1->Price() < m2->Price(); }, 0, bikes_p.size());
std::cout << "sorted? " << bikes_p << std::endl;
std::cout << "--------------------------------------------------------" << std::endl;
}
//}
//_CrtDumpMemoryLeaks();
return 0;
}

How to use different comparators for a priority queue depending on conditions

I'm working on an assignment, where I have a priority queue and I want it to work like this:
if(field == '0')
priority_queue<record_t*,vector<record_t*>, CompareRecordID > pq;
else if(field == '1')
priority_queue<record_t*,vector<record_t*>, CompareRecordNum > pq;
else if(field == '2')
priority_queue<record_t*,vector<record_t*>, CompareRecordStr > pq;
else if(field == '3')
priority_queue<record_t*,vector<record_t*>, CompareRecordNumStr > pq;
Where record_t is:
typedef struct {
unsigned int recid;
unsigned int num;
char str[STR_LENGTH];
bool valid; // if set, then this record is valid
int blockID; //The block the record belongs too -> Used only for minheap
} record_t;
Which means, depending on a function argument field, the queue will "sort" a different field of record_t. However, I cannot declare a queue inside an if statement, since it will obviously give me an error "pq was not declared in this scope". What can I do?
You can use the std::priority_queue constructor that takes a comparator object as a parameter. Then you can feed it a configurable comparator a bit like this:
#include <vector>
#include <queue>
#include <cstring>
#include <iostream>
const int STR_LENGTH = 20;
struct record_t
{
unsigned int recid;
unsigned int num;
char str[STR_LENGTH];
bool valid; // if set, then this record is valid
int blockID; //The block the record belongs too -> Used only for minheap
};
// switchable priority comparator
struct CompareRecord
{
int field;
CompareRecord(int field = 0): field(field) {}
bool operator() (const record_t* lhs, const record_t* rhs) const
{
switch(field)
{
case 0: return lhs->recid < rhs->recid;
case 1: return lhs->num < rhs->num;
case 2: return std::strcmp(lhs->str, rhs->str) < 0;
}
return true;
}
};
int main()
{
// physical records
std::vector<record_t> records;
record_t r;
r.recid = 1;
r.num = 1;
std::strcpy(r.str, "banana");
records.push_back(r);
r.recid = 2;
r.num = 4;
std::strcpy(r.str, "orange");
records.push_back(r);
r.recid = 3;
r.num = 2;
std::strcpy(r.str, "apple");
records.push_back(r);
// input priority type: 0, 1 or 2
int field;
std::cout << "Sort type [0, 1, 2]: " << std::flush;
std::cin >> field;
std::cout << '\n';
// build priority view
CompareRecord cmp(field);
std::priority_queue<record_t*, std::vector<record_t*>, CompareRecord> pq(cmp);
for(auto& r: records)
pq.push(&r);
while(!pq.empty())
{
std::cout << "rec: " << pq.top()->recid << '\n';
std::cout << "num: " << pq.top()->num << '\n';
std::cout << "str: " << pq.top()->str << '\n';
std::cout << '\n';
pq.pop();
}
}
Output:
Sort type [0, 1, 2]: 0
rec: 3
num: 2
str: apple
rec: 2
num: 4
str: orange
rec: 1
num: 1
str: banana
A priority_queue can take a comparator as a constructor argument.
std::priority_queue<record_t*,vector<record_t*>, CompareRecord > pq((CompareRecord(field)));
You just need to define the CompareRecord comparator appropriately. A simple way to do it would be:
struct CompareRecord{
char type;
CompareRecord(char type):type(type){}
bool operator()(const record_t* lhs, const record_t* rhs){
switch(type){
case '1': return lhs->recid < rhs->recid;
.. and so forth.
}
}