How to implement an unordered data structure using set? - c++

I want to build an unordered set for my Face structure, that is
class myFace
{
public:
//the three points
int u;
int v;
int k;
myFace() = default;
myFace(int u, int v, int k) : u(u), v(v), k(k) {}
bool operator< (const myFace& e) const
{
bool result = true;
min(u, v, k);
if ((u == e.u && v == e.v && k == e.k) ||
(u == e.u && v == e.k && k == e.v) ||
(u == e.v && v == e.u && k == e.k) ||
(u == e.v && v == e.k && k == e.u) ||
(u == e.k && v == e.u && k == e.v) ||
(u == e.k && v == e.v && k == e.u))
{
result = false;
}
return result;
}
};
I want to make sure that:
set<myFace> con;
myFace f1(1,2,3);
myFace f2(2,3,1);
myFace f3(3,1,2);
con.insert(f1);
con.insert(f2);
con.insert(f3);
cout << con.size() << endl;
the output should be 1.
Since f1,f2,f3 are same.
Or we can just say how to implement a set for 3 unordered elements, that is 123,132,213,231,312,321 are all same.

The secret is, to use the correct Comparator for your class and give it to the set. I used a similar approach for sets here.
I adapted this solution and created the below example code:
#include <iostream>
#include <set>
#include <vector>
#include <algorithm>
struct myFace
{
//the three points
int u;
int v;
int k;
myFace() = default;
myFace(int u, int v, int k) : u(u), v(v), k(k) {}
};
struct Comparator {
bool operator () (const myFace& lhs, const myFace& rhs) const {
// Convert the structs to vectors
std::vector<int> v1 = { lhs.u, lhs.v, lhs.k };
std::vector<int> v2 = { rhs.u, rhs.v, rhs.k };
// Sort them
std::sort(v1.begin(), v1.end());
std::sort(v2.begin(), v2.end());
// Compare them
return v1 < v2;
}
};
int main() {
std::set<myFace, Comparator> con;
myFace f1(1, 2, 3);
myFace f2(2, 3, 1);
myFace f3(3, 1, 2);
con.insert(f1);
con.insert(f2);
con.insert(f3);
std::cout << con.size() << std::endl;
return 0;
}

I found that use set can achieve the goal: implementing a set for 3 unordered elements, that is 123,132,213,231,312,321 are all same.
set<int> face;
face.insert(1);
face.insert(2);
face.insert(3);
set<int> face2;
face2.insert(2);
face2.insert(1);
face2.insert(3);
set<int> face3;
face3.insert(3);
face3.insert(1);
face3.insert(2);
set<set<int>> faces;
faces.insert(face);
faces.insert(face2);
faces.insert(face3);
cout << "----" << endl;
cout << faces.size() << endl;

Related

How to find point of intersection in qcustomplot?

I have an app based on qt (qcustomplot) that prints two different graphs. They have one point of intersection. How to find x and y coordinates of this point?
This doesn't have much to do with plotting, since you'd be investigating the underlying data. Let's say that we can interpolate between data points using lines, and the data sets are single-valued (i.e. for any x or key coordinate, there's only one value).
Online demo of the code below
Let's sketch a solution. First, some preliminaries, and we detect whether QCustomPlot was included so that the code can be tested without it - the necessary classes are mocked:
#define _USE_MATH_DEFINES
#include <algorithm>
#include <cassert>
#include <cmath>
#include <iostream>
#include <optional>
#include <type_traits>
#include <vector>
//#include "qcustomplot.h"
constexpr bool debugOutput = false;
#ifndef QCP_PLOTTABLE_GRAPH_H
struct QCPGraphData {
double key, value;
QCPGraphData() = default;
QCPGraphData(double x, double y) : key(x), value(y) {}
};
#endif
auto keyLess(const QCPGraphData &l, const QCPGraphData &r) { return l.key < r.key; }
#ifndef QCP_PLOTTABLE_GRAPH_H
template <typename T> struct QCPDataContainer : public std::vector<T> {
using std::vector<T>::vector;
void sort() { std::sort(this->begin(), this->end(), keyLess); }
};
using QCPGraphDataContainer = QCPDataContainer<QCPGraphData>;
#endif
using Point = QCPGraphData;
using Container = QCPGraphDataContainer;
static_assert(std::is_copy_constructible_v<Point>, "Point must be copy-constructible");
Some helper functions:
std::ostream &operator<<(std::ostream &os, const Point &p) {
return os << "(" << p.key << ", " << p.value << ")";
}
template <class T> bool has_unique_keys(const T &v) {
constexpr auto keyEqual = [](const Point &l, const Point &r) { return l.key == r.key; };
return std::adjacent_find(std::begin(v), std::end(v), keyEqual) == std::end(v);
}
template <class T> bool has_valid_points(const T& v) {
constexpr auto isValid = [](const Point &p) { return std::isfinite(p.key) && std::isfinite(p.value); };
return std::all_of(std::begin(v), std::end(v), isValid);
}
The line segment intersection finder:
// intersection of two line segments
std::optional<Point> intersection(const Point &a1, const Point &a2, const Point &b1, const Point &b2)
{
auto p1 = a1, p2 = a2, p3 = b1, p4 = b2;
assert(p1.key <= p2.key);
assert(p3.key <= p4.key);
if (debugOutput) std::cout << p1 << "-" << p2 << ", " << p3 << "-" << p4;
auto const denom = (p1.key - p2.key)*(p3.value - p4.value)
- (p1.value - p2.value)*(p3.key - p4.key);
if (fabs(denom) > 1e-6*(p2.key - p1.key)) {
// the lines are not parallel
auto const scale = 1.0/denom;
auto const q = p1.key*p2.value - p1.value*p2.key;
auto const r = p3.key*p4.value - p3.value*p4.key;
auto const x = (q*(p3.key-p4.key) - (p1.key-p2.key)*r) * scale;
if (debugOutput) std::cout << " x=" << x << "\n";
if (p1.key <= x && x <= p2.key && p3.key <= x && x <= p4.key) {
auto const y = (q*(p3.value-p4.value) - (p1.value-p2.value)*r) * scale;
return std::optional<Point>(std::in_place, x, y);
}
}
else if (debugOutput) std::cout << "\n";
return std::nullopt;
}
An algorithm that walks down two lists of points sorted in ascending key (x) order, and finds all intersections of line segments spanning consecutive point pairs from these two lists:
std::vector<Point> findIntersections(const Container &a_, const Container &b_)
{
if (a_.size() < 2 || b_.size() < 2) return {};
static constexpr auto check = [](const auto &c){
assert(has_valid_points(c));
assert(std::is_sorted(c.begin(), c.end(), keyLess));
assert(has_unique_keys(c));
};
check(a_);
check(b_);
bool aFirst = a_.front().key <= b_.front().key;
const auto &a = aFirst ? a_ : b_, &b = aFirst ? b_ : a_;
assert(a.front().key <= b.front().key);
if (a.back().key < b.front().key) return {}; // the key spans don't overlap
std::vector<Point> intersections;
auto ia = a.begin(), ib = b.begin();
Point a1 = *ia++, b1 = *ib++;
while (ia->key < b1.key) a1=*ia++; // advance a until the key spans overlap
for (Point a2 = *ia, b2 = *ib;;) {
auto const ipt = intersection(a1, a2, b1, b2);
if (ipt)
intersections.push_back(*ipt);
bool advanceA = a2.key <= b2.key, advanceB = b2.key <= a2.key;
if (advanceA) {
if (++ia == a.end()) break;
a1 = a2, a2 = *ia;
}
if (advanceB) {
if (++ib == b.end()) break;
b1 = b2, b2 = *ib;
}
}
return intersections;
}
And a more generic version that can also sort the points in ascending key order:
auto findIntersections(Container &d1, Container &d2, bool presorted)
{
if (!presorted) {
d1.sort();
d2.sort();
}
return findIntersections(d1, d2);
}
And now some simple demonstration:
template <typename Fun>
Container makeGraph(double start, double step, double end, Fun &&fun) {
Container result;
int i = 0;
for (auto x = start; x <= end; x = ++i * step)
result.emplace_back(x, fun(x));
return result;
}
int main()
{
for (auto step2: {0.1, 0.1151484584}) {
auto sinPlot = makeGraph(-2*M_PI, 0.1, 3*M_PI, sin);
auto cosPlot = makeGraph(0., step2, 2*M_PI, cos);
auto intersections = findIntersections(sinPlot, cosPlot);
std::cout << "Intersections:\n";
for (auto &ip : intersections)
std::cout << " at " << ip << "\n";
}
}
Demo output:
Intersections:
at (0.785613, 0.706509)
at (3.92674, -0.706604)
Intersections:
at (0.785431, 0.706378)
at (3.92693, -0.706732)

set::find finds an element that does not exist

I have the following Edgeclass:
class Edge {
public:
int src, dest;
bool operator== (const Edge &edge) const {
return ((src == edge.src) && (dest == edge.dest)) || ((src == edge.dest) && (dest == edge.src));
}
bool operator<(const Edge& edge) const {
return !(((src == edge.src) && (dest == edge.dest)) || ((src == edge.dest) && (dest == edge.src)));
}
Edge(int src, int dest) {
this->src = src;
this->dest = dest;
}
};
The point of overriding the < operator is when I try to find an edge in a set Edge(0, 1) should be equal to Edge(1, 0). However, the following test code fails to do so and std::find returns an edge that doesn't even exist:
Edge edge(0, 3);
set<Edge> test;
test.insert(Edge(3, 1));
test.insert(Edge(3, 0));
auto a = test.find(edge);
cout << a->src << " " << a->dest << endl;
This will strangely print out 2 0. I can't figure out why and I'm new to C++ any help is appreciated.
You currently don't have a valid Compare for std::set, so your program has undefined behaviour.
Here is one that is compatible with your ==
bool operator<(const Edge& edge) const {
return std::minmax(src, dest) < std::minmax(edge.src, edge.dest);
}
This can also be used to simplify your ==
bool operator==(const Edge& edge) const {
return std::minmax(src, dest) == std::minmax(edge.src, edge.dest);
}
There are two issues in your code.
First, you do not check whether test.find() returns a valid edge; note that find returns end() if no element was found.
Second, your <-operator does not implement a strict ordering, it actually just defines a !=. To overcome this, I'd normalize each edge such that the lower node is always treated as the start; then decide based on the starting nodes, and only if they are equal, consider the destination nodes:
class Edge {
public:
int src, dest;
bool operator== (const Edge &edge) const {
return ((src == edge.src) && (dest == edge.dest)) || ((src == edge.dest) && (dest == edge.src));
}
bool operator<(const Edge& edge) const {
// return !(((src == edge.src) && (dest == edge.dest)) || ((src == edge.dest) && (dest == edge.src)));
int thisSrc = std::min(src,dest);
int thisDest = std::max(src,dest);
int eSrc = std::min(edge.src,edge.dest);
int eDest = std::max(edge.src,edge.dest);
if (thisSrc < eSrc) {
return true;
} else if (thisSrc > eSrc) {
return false;
} else {
return thisDest < eDest;
}
}
Edge(int src, int dest) {
this->src = src;
this->dest = dest;
}
};
#include <set>
int main() {
Edge edge(0, 3);
std::set<Edge> test;
test.insert(Edge(3, 1));
test.insert(Edge(3, 0));
auto a = test.find(edge);
if (a == test.end()) {
std::cout << "edge not found." << std::endl;
} else {
std::cout << a->src << " " << a->dest << std::endl;
}
}
Output:
3 0

How to recursively compare vectors?

I'm trying to write a function which recursively checks if a given vector A is in any contiguous block in vector B. For example, if A={5,6,7} and B={1,2,3,4,5,6,7}, it should return true. If B = {1,2,3,4,5,7,6}, it should return false. Currently, my code keeps outputting true because I don't think my logic is correct. I have not been able to modify it to produce any results yet. Any help will be appreciated!
bool r_app(vector<int>& a1, vector<int> b1, size_t k)
{
k=0;
if (a1.size() == 0) {
cout << "true";
return true;;
}
for (int i=0;i<a1.size();i++){
for(int j=0;j<b1.size();j++){
if (a1.at(i)==b1.at(j)) {
cout << "true" << endl;
return true;
}
}
cout << "false" << endl;
return false;
return r_app(a1,b1,k+1);
}
}
EDIT: So this is what I got from Smac89, and I added the cout lines so that when I call the function in main, it outputs either true or false. The function currently outputs true for every true input, but doesnt output false.. I'm not sure why.
bool r_app(std::vector<int>& a1, std::vector<int> &b1, std::size_t start)
{
std::size_t savedPos = start + 1, k = 0;
for (; k < a1.size() && start < b1.size() && a1[k] == b1[start];
k++, start++)
{
if (k != 0 && a1[0] == b1[start])
savedPos = start;
}
if (k == a1.size())
cout << "true" << endl;
return true;
if (start < b1.size())
return r_app(a1, b1, savedPos);
cout << "false" << endl;
return false;
}
template <typename T>
bool r_app(std::vector<T>& a1, std::vector<T> &b1, std::size_t start) {
std::size_t savedPos = start + 1, k = 0;
for (; k < a1.size() && start < b1.size() && a1[k] == b1[start];
k++, start++)
{
if (k != 0 && a1[0] == b1[start])
savedPos = start;
}
if (k == a1.size())
return true;
if (start < b1.size())
return r_app(a1, b1, savedPos);
return false;
}
template <typename T>
bool r_app(std::vector<T>& a1, std::vector<T>& b1) {
return r_app(a1, b1, 0);
}
Example:
http://rextester.com/COR69755
EDIT:
V2
Now more efficient searching - start a search either where the last search ended or at a character that matches the start of the search string
You can also print out where the first match occurred by looking at savedPos - 1
You need1 two recursive functions here if you want to do everything recursively.
One to test if the sequence is found at a particular point, and one to use this other function to test for equality at every point. Here is a simple template implementation that will work with any STL container that allows iteration, as well as non-STL sequences (such as raw arrays):
template <typename NeedleIterator, typename HaystackIterator = NeedleIterator>
bool recursive_sequence_equals(
NeedleIterator needle_begin,
NeedleIterator needle_end,
HaystackIterator haystack_begin,
HaystackIterator haystack_end)
{
// The sequences are equal because we reached the end of the needle.
if (needle_begin == needle_end) {
return true;
}
// If we reached the end of the haystack, or the current elements are not equal
// then the sequences are not equal here.
if (haystack_begin == haystack_end || *needle_begin != *haystack_begin) {
return false;
}
// We are not at the end of the haystack nor the needle, and the elements were
// equal. Move on to the next element.
return recursive_sequence_equals(
++needle_begin, needle_end,
++haystack_begin, haystack_end);
}
template <typename NeedleIterator, typename HaystackIterator = NeedleIterator>
HaystackIterator recursive_sequence_find(
NeedleIterator needle_begin,
NeedleIterator needle_end,
HaystackIterator haystack_begin,
HaystackIterator haystack_end)
{
// We reached the end with no match.
if (haystack_begin == haystack_end) {
return haystack_begin;
}
// If the sequences are equal at this point, return the haystack iterator.
if (recursive_sequence_equals(needle_begin, needle_end,
haystack_begin, haystack_end)) {
return haystack_begin;
}
// Check the next position in the haystack.
return recursive_sequence_find(
needle_begin, needle_end,
++haystack_begin, haystack_end);
}
Used like this:
std::vector<int> a = { 5, 6, 7 };
std::vector<int> b = { 1, 2, 3, 4, 5, 6, 7 };
auto found = recursive_sequence_find(
a.begin(), a.end(),
b.begin(), b.end());
if (found != b.end()) {
// There was a match, found is an iterator to the beginning of the match in b.
} else {
// No match. (Or both containers were empty!)
}
(Demo)
1 Technically you can do this with one function if you use some extra parameters to convey whether or not you are in the middle of an equality test. However this adds a lot of extra complication to the logic for no gain. It's easier and more straightforward to implement using two different recursive functions.
#include <stdio.h>
#include <string.h>
#include <vector>
#include <iostream>
using namespace std;
bool r_app(vector<int> a, vector<int> b, int starta, int startb)
{
if(a.size() == 0) return 0;
if(starta == 0) {
int i=0;
while(1) {
while(a[0] != b[i] && i < b.size())
i++;
if(i >= b.size()) return 0;
if(r_app(a, b, starta+1, i+1) == 1)
return 1;
else i++;
}
}
else {
if(starta == a.size())
return 1;
else if(startb == b.size())
return 0;
else if(a[starta] == b[startb])
return r_app(a, b, starta+1, startb+1);
else
return 0;
}
}
int main() {
vector<int> a;
vector<int> b;
b.push_back(1);
b.push_back(2);
b.push_back(3);
b.push_back(4);
b.push_back(5);
a.push_back(3);
a.push_back(4);
cout << r_app(a,b,0,0);
return 0;
}
It will be easier if you do not use recursion. Also, KMP algorithm will give you much optimized solution.
My try, using iterator:
#include <iostream>
#include <vector>
#include <algorithm>
template<typename Iter>
bool r_app(Iter first_a, Iter last_a, Iter first_b, Iter last_b)
{
if(first_a == last_a) //trivial case
return true;
auto found = std::find(first_b, last_b, *first_a);
if(found == last_b)
return false;
else
return r_app(++first_a, last_a, found, last_b); //recursion
}
int main()
{
std::vector<int> a{5,6,7};
std::vector<int> b{1,2,3,4,5,6,7};
std::cout << r_app(a.begin(),a.end(),b.begin(),b.end());
return 0;
}

Determining if two vectors contain two adjacent items the same

I have a problem that concerns determining if two vectors contain two elements the same. The elements may be anywhere in the vector, but they must be adjacent.
EDITED FOR MORE EXAMPLES
For example the following two vectors, when compared, would return false.
Vector 1 = [ 0, 1, 2, 3, 4, 6 ]
Vector 2 = [ 1, 4, 2, 0, 5, 3 ]
But the following two would return true:
Vector 1 = [ 0, 1, 2, 3, 4, 5 ]
Vector 2 = [ 4, 2, 1, 5, 0, 3 ]
because the 1,2 in the first vector would correspond to the 2,1 in the second vector.
True:
Vector 1 = [ 0, 1, 2, 3, 4, 5 ]
Vector 2 = [ 1, 4, 2, 0, 5, 3 ]
{5,0} is a pair, despite looping around the vector (I originally said this was false, thanks for spotting that 'Vlad from Moscow').
True:
Vector 1 = [ 0, 1, 2, 3, 4, 5 ]
Vector 2 = [ 4, 8, 6, 2, 1, 5, 0, 3 ]
{2,1} is still a pair, even though they are not in the same position
The actual application is that I have a polygon (face) with N points stored in a vector. To determine if a set of polygons completely enclose a 3D volume, I test each face to ensure that each edge is shared by another face (where an edge is defined by two adjacent points).
Thus, Face contains a vector of pointers to Points...
std::vector<Point*> points_;
and to check if a Face is surrounded, Face contains a member function...
bool isSurrounded(std::vector<Face*> * neighbours)
{
int count = 0;
for(auto&& i : *neighbours) // for each potential face
if (i != this) // that is not this face
for (int j = 0; j < nPoints(); j++) // and for each point in this face
for (int k = 0; k < i->nPoints(); k++ ) // check if the neighbour has a shared point, and that the next point (backwards or forwards) is also shared
if ( ( this->at(j) == i->at(k) ) // Points are the same, check the next and previous point too to make a pair
&& ( ( this->at((j+1)%nPoints()) == i->at((k+1)%(i->nPoints())) )
|| ( this->at((j+1)%nPoints()) == i->at((k+i->nPoints()-1)%(i->nPoints())) )))
{ count++; }
if (count > nPoints() - 1) // number of egdes = nPoints -1
return true;
else
return false;
}
Now, obviously this code is horrible. If I come back to this in 2 weeks, I probably won't understand it. So faced with the original problem, how would you neatly check the two vectors?
Note that if you are trying to decipher the provided code. at(int) returns the Point in a face and nPoints() returns the number of points in a face.
Many thanks.
Here is way if your element are same set of elements then assign index for each. (Didnt mention corner cases in pseudo ) :-
for(int i=0;i<vect1.size;i++) {
adj[vect1[i]][0] = vect1[i-1];
adj[vect2[i]][1] = vect2[i+1];
}
for(int j=0;j<vect2.size();j++) {
if(arr[vect2[i]][0]==(vect2[j-1] or vect[j+1]))
return true
if(arr[vect2[i]][1]==(vect2[j-1] or vect[j+1]))
return true
}
#include <vector>
#include <algorithm>
#include <iterator>
#include <iostream>
using namespace std;
class AdjacentSort
{
public:
AdjacentSort(const vector<int>& ref);
~AdjacentSort();
bool operator()(int e1,int e2) const;
private:
const vector<int>& ref_;
};
AdjacentSort::AdjacentSort(const vector<int>& ref):
ref_(ref)
{
}
bool AdjacentSort::operator()(int e1, int e2) const
{
auto it1 = find(ref_.begin(),ref_.end(),e1);
auto it2 = find(ref_.begin(),ref_.end(),e2);
return distance(it1,it2) == 1;
}
AdjacentSort::~AdjacentSort()
{
}
int main()
{
vector<int> vec {1,2,3,4,5};
vector<int> vec2 {1,3,5,4,2};
AdjacentSort func(vec);
auto it = adjacent_find(vec2.begin(),vec2.end(),func);
cout << *it << endl;
return 0;
}
It returns the first element where two adjacent numbers are found, else it returns the end iterator.
Not efficient but following is a possibility.
bool comparePair ( pair<int,int> p1, pair<int,int> p2 ) {
return ( p1.first == p2.first && p1.second == p2.second )
|| ( p1.second == p2.first && p1.first == p2.second );
}
//....
vector< pair<int,int> > s1;
vector< pair<int,int> > s1;
vector< pair<int,int> > intersect( vec1.size() + vec2.size() );
for ( int i = 0; i < vec1.size()-1; i++ ) {
pair<int, int> newPair;
newPair.first = vec1[i];
newPair.first = vec1[i+1];
s1.push_back( newPair );
}
for ( int i = 0; i < vec2.size()-1; i++ ) {
pair<int, int> newPair;
newPair.first = vec2[i];
newPair.first = vec2[i+1];
s2.push_back( newPair );
}
auto it = std::set_intersection ( s1.begin(), s1.end(), s2.begin(), s2.end(),
intersect.begin(), comparePair );
return ( it != intersect.begin() ); // not sure about this.
If I have understood correctly these two vectors
std::vector<int> v1 = { 0, 1, 2, 3, 4, 5 };
std::vector<int> v2 = { 3, 5, 2, 1, 4, 0 };
contain adjacent equal elements. They are pair {1, 2 } in the first vector and pair { 2, 1 } in the second vector though positions of the pairs are different in the vectors.
In fact you already named the appropriate standard algorithm that can be used in this task. It is std::adjacent_find. For example
#include <iostream>
#include <iomanip>
#include <algorithm>
#include <vector>
int main()
{
std::vector<int> v1 = { 0, 1, 2, 3, 4, 5 };
std::vector<int> v2 = { 3, 5, 2, 1, 4, 0 };
bool result =
std::adjacent_find( v1.begin(), v1.end(),
[&v2]( int x1, int y1 )
{
return std::adjacent_find( v2.begin(), v2.end(),
[=]( int x2, int y2 )
{
return ( x1 == x2 && y1 == y2 || x1 == y2 && y1 == x2 );
} ) != v2.end();
} ) != v1.end();
std::cout << "result = " << std::boolalpha << result << std::endl;
return 0;
}
Here's my attempt at this problem. Quite simply, iterate through a, find the same element in b and then compare the next element in a with the elements before and after our position in b.
If it's a little wordier than it needed to be it was so that this function can be called with any containers. The only requirement is that the containers' iterators have to bidirectional.
#include <vector>
#include <iostream>
#include <algorithm>
#include <list>
using namespace std;
template <class Iter>
pair<Iter, Iter> get_neighbors(Iter begin, Iter current, Iter end)
{
auto p = make_pair(end, next(current));
if(current != begin)
p.first = prev(current);
return p;
}
template <class Iter1, class Iter2>
bool compare_if_valid(Iter1 p1, Iter1 end1, Iter2 p2)
{
return p1 != end1 && *p1 == *p2;
}
template <class C1, class C2>
auto neighbors_match(const C1 & a, const C2 & b) ->
decltype(make_pair(begin(a), begin(b)))
{
for(auto i = begin(a); i != end(a) && next(i) != end(a); ++i)
{
auto pos_in_b = find(begin(b), end(b), *i);
if(pos_in_b != end(b))
{
auto b_neighbors = get_neighbors(begin(b), pos_in_b, end(b));
if(compare_if_valid(b_neighbors.first, end(b), next(i)))
return {i, b_neighbors.first};
else if(compare_if_valid(b_neighbors.second, end(b), next(i)))
return {i, pos_in_b};
}
}
return {end(a), end(b)};
}
int main()
{
vector<int> a = {0, 1, 2, 3, 4, 5};
vector<int> b = {1, 4, 2, 0, 5, 3};
cout << boolalpha << (neighbors_match(a, b).first != a.end()) << endl;
vector<int> a2 = {0, 1, 2, 3, 4, 5};
list<int> b2 = {4, 2, 1, 5, 0, 3};
auto match = neighbors_match(a2, b2);
cout << boolalpha << distance(a2.cbegin(), match.first)
<< ' ' << distance(b2.cbegin(), match.second) << endl;
return 0;
}
First, write a make_paired_range_view which takes a range and returns a range whose iterators return std::tie( *it, *std::next(it) ). boost can help here, as their iterator writing code makes this far less annoying.
Next, unordered_equal takes two pairs and compares them ignoring order (so they are equal if the first both equal and the second both equal, or if the first equals the other second and vice versa).
Now we look for each of the left hand side's pairs in the right hand side using unordered_equal.
This has the advantage of taking 0 extra memory, but the disadvantage of O(n^2) time.
If we care more about time than memory, we can instead shove the pairs above into an unordered_set after sorting the pair to be in a canonical order. We then to through the second container, testing each pair (after sorting) to see if it is in the unordered_set. This takes O(n) extra memory, but runs in O(n) time. It can also be done without fancy dancy vector and range writing.
If the elements are more expensive than int, you can write a custom pseudo_pair that holds pointers and whose hash and equality is based on the content of the pointers.
An interesting "how would you do it..." problem... :-) It got me to take a 15 minute break from slapping edit boxes and combo boxes on forms and do a bit of programming for a change... LOL
So, here's how I think I'd do it...
First I'd define a concept of an edge as a pair of values (pair of ints - following your original example). I realize your example is just a simplification and you're actually using vectors of your own classes (Point* rather than int?) but it should be trivial to template-ize this code and use any type you want...
#include <stdlib.h>
#include <iostream>
#include <vector>
#include <set>
#include <vector>
using namespace std;
typedef pair<int, int> edge;
Then I would create a set class that will keep its elements (edges) ordered in the way we need (by comparing edges in the order insensitive manner - i.e. if e1.first==e2.first and e1.second==e2.second then edges e1 and e2 are the same, but they are also same if e1.first==e2.second and e1.second==e2.first). For this, we could create a functional:
struct order_insensitive_pair_less
{
bool operator() (const edge& e1, const edge& e2) const
{
if(min(e1.first,e1.second)<min(e2.first,e2.second)) return true;
else if(min(e1.first,e1.second)>min(e2.first,e2.second)) return false;
else return(max(e1.first,e1.second)<max(e2.first,e2.second));
}
};
Finally, our helper class (call it edge_set) would be a simple derivative of a set ordered using the above functional with a couple of convenience methods added - a constructor that populates the set from a vector (or your Face class in practice) and a tester function (bool shares_edge(const vector&v)) that tells us whether or not the set shares an edge with another. So:
struct edge_set : public set<edge, order_insensitive_pair_less>
{
edge_set(const vector<int>&v);
bool shares_edge(const vector<int>&v);
};
Implemented as:
edge_set::edge_set(const std::vector<int>&v) : set<edge, order_insensitive_pair_less>()
{
if(v.size()<2) return; // assume there must be at least 2 elements in the vector since it is supposed to be a list of edges...
for (std::vector<int>::const_iterator it = v.begin()+1; it != v.end(); it++)
insert(edge(*(it-1), *it));
}
bool edge_set::shares_edge(const std::vector<int>& v)
{
edge_set es(v);
for(iterator es_it = begin(); es_it != end(); es_it++)
if(es.count(*es_it))
return true;
return false;
}
The usage then becomes trivial (and reasonably elegant). Assuming you have the two vectors you gave as examples in the abstract of your problem in variables v1 and v2, to test whether they share an edge you would just write:
if(edge_set(v1).shares_edge(v2))
// Yup, they share an edge, do something about it...
else
// Nope, not these two... Do something different...
The only assumption about the number of elements in this approach is that each vector will have at least 2 (since you cannot have an "edge" without at least to vertices). However, even if this is not the case (one of the vectors is empty or has just one element) - this will result in an empty edge_set so you'll just get an answer that they have no shared edges (since one of the sets is empty). No big deal... In my opinion, doing it this way would certainly pass the "two week test" since you would have a dedicated class where you could have a couple of comment lines to say what it's doing and the actual comparison is pretty readable (edge_set(v1).shares_edge(v2))...
If I understand your question:
std::vector<int> a, b;
std::vector<int>::iterator itB = b.begin();
std::vector<int>::iterator itA;
std::vector<std::vector<int>::iterator> nears;
std::vector<int>::iterator near;
for(;itB!=b.end() ; ++itB) {
itA = std::find(a.begin(), a.end(), *itB);
if(nears.empty()) {
nears.push_back(itA);
} else {
/* there's already one it, check the second */
if(*(++nears[0])==*itA && itA != a.end() {
nears.push_back(itA);
} else {
nears.clear();
itB--;
}
}
if(nears.size() == 2) {
return true;
}
}
return false;
I think this is the most concise i can come up with.
bool check_for_pairs(std::vector<int> A, std::vector<int> B) {
auto lastA = A.back();
for (auto a : A) {
auto lastB = B.back();
for (auto b : B) {
if ((b == a && lastB == lastA) || (b == lastA && lastB == a)) return true;
lastB = b;
}
lastA = a;
}
return false;
}
Are more time efficient approach would be to use a set
bool check_for_pairs2(std::vector<int> A, std::vector<int> B) {
using pair = std::pair<int,int>;
std::unordered_set< pair, boost::hash<pair> > lookup;
auto last = A.back();
for (auto a : A) {
lookup.insert(a < last ? std::make_pair(a,last) : std::make_pair(last,a));
last = a;
}
last = B.back();
for (auto b : B) {
if (lookup.count(b < last ? std::make_pair(b,last) : std::make_pair(last,b)))
return true;
last = b;
}
return false;
}
If you implement a hash function that hashes (a,b) and (b,a) to the same, you could remove the check for which value is smallest
What you are essentially asking for is whether the edge sets of two faces (let's call them a and b) are disjoint or not. This can be decomposed into the problem of whether any of the edges in b are in a, which is just a membership test. The issue then, is that vectors are not great at membership tests.
My solution, is to convert one of the vectors into an unordered_set< pair<int, int> >.
an unordered_set is just a hash table, and the pairs represent the edges.
In representing edges, I've gone for a normalising scheme where the indices of the vertices are in increasing order (so [2,1] and [1,2] both get stored as [1,2] in my edge set). This makes equality testing that little bit easier (in that it is just the equality of the pair)
So here is my solution:
#include <iostream>
#include <utility>
#include <functional>
#include <vector>
#include <unordered_set>
using namespace std;
using uint = unsigned int;
using pii = pair<int,int>;
// Simple hashing for pairs of integers
struct pii_hash {
inline size_t
operator()(const pii & p) const
{
return p.first ^ p.second;
}
};
// Order pairs of integers so the smallest number is first
pii ord_pii(int x, int y) { return x < y ? pii(x, y) : pii(y, x); }
bool
shares_edge(vector<int> a, vector<int> b)
{
unordered_set<pii, pii_hash> edge_set {};
// Create unordered set of pairs (the Edge Set)
for(uint i = 0; i < a.size() - 1; ++i)
edge_set.emplace( ord_pii(a[i], a[i+1]) );
// Check if any edges in B are in the Edge Set of A
for(uint i = 0; i < b.size() - i; ++i)
{
pii edge( ord_pii(b[i], b[i+1]) );
if( edge_set.find(edge) != edge_set.end() )
return true;
}
return false;
}
int main() {
vector<int>
a {0, 1, 2, 3, 4, 5},
b {1, 4, 2, 0, 5, 3},
c {4, 2, 1, 0, 5, 3};
shares_edge(a, b); // false
shares_edge(a, c); // true
return 0;
}
In your particular case, you may want to make shares_edge a member function of your Face class. It may also be beneficial to precompute the edge set and store it as an instance variable of Face as well, but that depends on how often the edge data changes vs how often this calculation occurs.
EDIT Extra Solution
EDIT 2 Fixed for question change: edge set now wraps around point list.
Here's what it would look like if you added the edge set, precomputed at initialisation to some sort of Face class. The private nested Edge class can be thought of as decorating your current representation of an edge (i.e. two adjacent positions in the point list), with an actual class, so that collections like sets can treat the index into the point list as an actual edge:
#include <cassert>
#include <iostream>
#include <utility>
#include <functional>
#include <vector>
#include <unordered_set>
using uint = unsigned int;
class Face {
struct Edge {
int _index;
const std::vector<int> *_vertList;
Edge(int index, const std::vector<int> *vertList)
: _index {index}
, _vertList {vertList}
{};
bool
operator==(const Edge & other) const
{
return
( elem() == other.elem() && next() == other.next() ) ||
( elem() == other.next() && next() == other.elem() );
}
struct hash {
inline size_t
operator()(const Edge & e) const
{
return e.elem() ^ e.next();
}
};
private:
inline int elem() const { return _vertList->at(_index); }
inline int
next() const
{
return _vertList->at( (_index + 1) % _vertList->size() );
}
};
std::vector<int> _vertList;
std::unordered_set<Edge, Edge::hash> _edgeSet;
public:
Face(std::initializer_list<int> verts)
: _vertList {verts}
, _edgeSet {}
{
for(uint i = 0; i < _vertList.size(); ++i)
_edgeSet.emplace( Edge(i, &_vertList) );
}
bool
shares_edge(const Face & that) const
{
for(const Edge & e : that._edgeSet)
if( _edgeSet.find(e) != _edgeSet.end() )
return true;
return false;
}
};
int main() {
Face
a {0, 1, 2, 3, 4, 5},
b {1, 4, 2, 0, 5, 3},
c {4, 2, 1, 0, 5, 3},
d {0, 1, 2, 3, 4, 6},
e {4, 8, 6, 2, 1, 5, 0, 3};
assert( !d.shares_edge(b) );
assert( a.shares_edge(b) );
assert( a.shares_edge(c) );
assert( a.shares_edge(e) );
return 0;
}
As you can see, this added abstraction makes for a quite pleasing implementation of shares_edge(), but that is because the real trick is in the definition of the Edge class (or to be more specific the relationship that e1 == e2 <=> Edge::hash(e1) == Edge::hash(e2)).
I know I'm a little late with this, but here's my take at it:
Not in-situ:
#include <algorithm>
#include <iostream>
#include <tuple>
#include <vector>
template<typename Pair>
class pair_generator {
public:
explicit pair_generator(std::vector<Pair>& cont)
: cont_(cont)
{ }
template<typename T>
bool operator()(T l, T r) {
cont_.emplace_back(r, l);
return true;
}
private:
std::vector<Pair>& cont_;
};
template<typename Pair>
struct position_independant_compare {
explicit position_independant_compare(const Pair& pair)
: pair_(pair)
{ }
bool operator()(const Pair & p) const {
return (p.first == pair_.first && p.second == pair_.second) || (p.first == pair_.second && p.second == pair_.first);
}
private:
const Pair& pair_;
};
template<typename T>
using pair_of = std::pair<T, T>;
template<typename T>
std::ostream & operator <<(std::ostream & stream, const pair_of<T>& pair) {
return stream << '[' << pair.first << ", " << pair.second << ']';
}
int main() {
std::vector<int>
v1 {0 ,1, 2, 3, 4, 5},
v2 {4, 8, 6, 2, 1, 5, 0, 3};
std::vector<pair_of<int> >
p1 { },
p2 { };
// generate our pairs
std::sort(v1.begin(), v1.end(), pair_generator<pair_of<int>>{ p1 });
std::sort(v2.begin(), v2.end(), pair_generator<pair_of<int>>{ p2 });
// account for the fact that the first and last element are a pair too
p1.emplace_back(p1.front().first, p1.back().second);
p2.emplace_back(p2.front().first, p2.back().second);
std::cout << "pairs for vector 1" << std::endl;
for(const auto & p : p1) { std::cout << p << std::endl; }
std::cout << std::endl << "pairs for vector 2" << std::endl;
for(const auto & p : p2) { std::cout << p << std::endl; }
std::cout << std::endl << "pairs shared between vector 1 and vector 2" << std::endl;
for(const auto & p : p1) {
const auto pos = std::find_if(p2.begin(), p2.end(), position_independant_compare<pair_of<int>>{ p });
if(pos != p2.end()) {
std::cout << p << std::endl;
}
}
}
Example output on ideone
In-situ:
#include <algorithm>
#include <iostream>
#include <iterator>
#include <tuple>
#include <vector>
template<typename T>
struct in_situ_pair
: std::iterator<std::forward_iterator_tag, T> {
using pair = std::pair<T, T>;
in_situ_pair(std::vector<T>& cont, std::size_t idx)
: cont_(cont), index_{ idx }
{ }
pair operator*() const {
return { cont_[index_], cont_[(index_ + 1) % cont_.size()] };
}
in_situ_pair& operator++() {
++index_;
return *this;
}
bool operator==(const pair& r) const {
const pair l = operator*();
return (l.first == r.first && l.second == r.second)
|| (l.first == r.second && l.second == r.first);
}
bool operator==(const in_situ_pair& o) const {
return (index_ == o.index_);
}
bool operator!=(const in_situ_pair& o) const {
return !(*this == o);
}
public:
friend bool operator==(const pair& l, const in_situ_pair& r) {
return (r == l);
}
private:
std::vector<T>& cont_;
std::size_t index_;
};
template<typename T>
using pair_of = std::pair<T, T>;
template<typename T>
std::ostream & operator <<(std::ostream & stream, const pair_of<T>& pair) {
return stream << '[' << pair.first << ", " << pair.second << ']';
}
namespace in_situ {
template<typename T>
in_situ_pair<T> begin(std::vector<T>& cont) { return { cont, 0 }; }
template<typename T>
in_situ_pair<T> end(std::vector<T>& cont) { return { cont, cont.size() }; }
template<typename T>
in_situ_pair<T> at(std::vector<T>& cont, std::size_t i) { return { cont, i }; }
}
int main() {
std::vector<int>
v1 {0 ,1, 2, 3, 4, 5},
v2 {4, 8, 6, 2, 1, 5, 0, 3};
for(std::size_t i = 0; i < v1.size(); ++i) {
auto pos = std::find(in_situ::begin(v2), in_situ::end(v2), in_situ::at(v1, i));
if(pos != in_situ::end(v2)) {
std::cout << "common: " << *pos << std::endl;
}
}
}
Example output on ideone
There have been a lot of great answers, and I'm sure people searching for the general problem of looking for adjacent pairs of equal elements in two vectors will find them enlightening. I have decided to answer my own question because I think a neater version of my original attempt is the best answer for me.
Since there doesn't seem to be a combination of std algorithms that make the methodology simpler, I believe looping and querying each element to be the most concise and understandable.
Here is the algorithm for the general case:
std::vector<int> vec1 = { 1, 2, 3, 4, 5, 6 };
std::vector<int> vec2 = { 3, 1, 4, 2, 6, 5 };
// Loop over the elements in the first vector, looking for an equal element in the 2nd vector
for(int i = 0; i < vec1.size(); i++) for(int j = 0; j < vec2.size(); j++)
if ( vec1[i] == vec2[j] &&
// ... Found equal elements, now check if the next element matches the next or previous element in the other vector
( vec1[(i+1) % vec1.size()] == vec2[(j+1) % vec2.size()]
||vec1[(i+1) % vec1.size()] == vec2[(j-1+vec2.size()) % vec2.size()] ) )
return true;
return false;
Or in my specific case, where I am actually checking a vector of vectors, and where the elements are no longer ints, but pointers to a class.
(The operator[] of the Face class returns an element of a vector belonging to the face).
bool isSurrounded(std::vector<Face*> * neighbours)
{
// We can check if each edge aligns with an edge in a nearby face,
// ... if each edge aligns, then the face is surrounded
// ... an edge is defined by two adjacent points in the points_ vector
// ... so we check for two consecutive points to be equal...
int count = 0;
// for each potential face that is not this face
for(auto&& i : *neighbours) if (i != this)
// ... loop over both vectors looking for an equal point
for (int j = 0; j < nPoints(); j++) for (int k = 0; k < i->nPoints(); k++ )
if ( (*this)[j] == (*i)[k] &&
// ... equal points have been found, check if the next or previous points also match
( (*this)[(j+1) % nPoints()] == (*i)[(k+1) % i->nPoints()]
|| (*this)[(j+1) % nPoints()] == (*i)[(k-1+i->nPoints()) % i->nPoints()] ) )
// ... an edge is shared
{ count++; }
// number of egdes = nPoints -1
if (count > nPoints() - 1)
return true;
else
return false;
}

Compare versions as strings

Comparing version numbers as strings is not so easy...
"1.0.0.9" > "1.0.0.10", but it's not correct.
The obvious way to do it properly is to parse these strings, convert to numbers and compare as numbers.
Is there another way to do it more "elegantly"? For example, boost::string_algo...
I don't see what could be more elegant than just parsing -- but please make use of standard library facilities already in place. Assuming you don't need error checking:
void Parse(int result[4], const std::string& input)
{
std::istringstream parser(input);
parser >> result[0];
for(int idx = 1; idx < 4; idx++)
{
parser.get(); //Skip period
parser >> result[idx];
}
}
bool LessThanVersion(const std::string& a,const std::string& b)
{
int parsedA[4], parsedB[4];
Parse(parsedA, a);
Parse(parsedB, b);
return std::lexicographical_compare(parsedA, parsedA + 4, parsedB, parsedB + 4);
}
Anything more complicated is going to be harder to maintain and isn't worth your time.
I would create a version class.
Then it is simple to define the comparison operator for the version class.
#include <iostream>
#include <sstream>
#include <vector>
#include <iterator>
class Version
{
// An internal utility structure just used to make the std::copy in the constructor easy to write.
struct VersionDigit
{
int value;
operator int() const {return value;}
};
friend std::istream& operator>>(std::istream& str, Version::VersionDigit& digit);
public:
Version(std::string const& versionStr)
{
// To Make processing easier in VersionDigit prepend a '.'
std::stringstream versionStream(std::string(".") + versionStr);
// Copy all parts of the version number into the version Info vector.
std::copy( std::istream_iterator<VersionDigit>(versionStream),
std::istream_iterator<VersionDigit>(),
std::back_inserter(versionInfo)
);
}
// Test if two version numbers are the same.
bool operator<(Version const& rhs) const
{
return std::lexicographical_compare(versionInfo.begin(), versionInfo.end(), rhs.versionInfo.begin(), rhs.versionInfo.end());
}
private:
std::vector<int> versionInfo;
};
// Read a single digit from the version.
std::istream& operator>>(std::istream& str, Version::VersionDigit& digit)
{
str.get();
str >> digit.value;
return str;
}
int main()
{
Version v1("10.0.0.9");
Version v2("10.0.0.10");
if (v1 < v2)
{
std::cout << "Version 1 Smaller\n";
}
else
{
std::cout << "Fail\n";
}
}
First the test code:
int main()
{
std::cout << ! ( Version("1.2") > Version("1.3") );
std::cout << ( Version("1.2") < Version("1.2.3") );
std::cout << ( Version("1.2") >= Version("1") );
std::cout << ! ( Version("1") <= Version("0.9") );
std::cout << ! ( Version("1.2.3") == Version("1.2.4") );
std::cout << ( Version("1.2.3") == Version("1.2.3") );
}
// output is 111111
Implementation:
#include <string>
#include <iostream>
// Method to compare two version strings
// v1 < v2 -> -1
// v1 == v2 -> 0
// v1 > v2 -> +1
int version_compare(std::string v1, std::string v2)
{
size_t i=0, j=0;
while( i < v1.length() || j < v2.length() )
{
int acc1=0, acc2=0;
while (i < v1.length() && v1[i] != '.') { acc1 = acc1 * 10 + (v1[i] - '0'); i++; }
while (j < v2.length() && v2[j] != '.') { acc2 = acc2 * 10 + (v2[j] - '0'); j++; }
if (acc1 < acc2) return -1;
if (acc1 > acc2) return +1;
++i;
++j;
}
return 0;
}
struct Version
{
std::string version_string;
Version( std::string v ) : version_string(v)
{ }
};
bool operator < (Version u, Version v) { return version_compare(u.version_string, v.version_string) == -1; }
bool operator > (Version u, Version v) { return version_compare(u.version_string, v.version_string) == +1; }
bool operator <= (Version u, Version v) { return version_compare(u.version_string, v.version_string) != +1; }
bool operator >= (Version u, Version v) { return version_compare(u.version_string, v.version_string) != -1; }
bool operator == (Version u, Version v) { return version_compare(u.version_string, v.version_string) == 0; }
https://coliru.stacked-crooked.com/a/7c74ad2cc4dca888
Here's a clean, compact C++20 solution, using the new spaceship operator <=>, and Boost's string split algorithm.
This constructs and holds a version string as a vector of numbers - useful for further processing, or can be disposed of as a temporary. This also handles version strings of different lengths, and accepts multiple separators.
The spaceship operator lets us provide results for <, > and == operators in a single function definition (although the equality has to be separately defined).
#include <compare>
#include <boost/algorithm/string.hpp>
struct version {
std::vector<size_t> data;
version() {};
version(std::string_view from_string) {
/// Construct from a string
std::vector<std::string> data_str;
boost::split(data_str, from_string, boost::is_any_of("._-"), boost::token_compress_on);
for(auto const &it : data_str) {
data.emplace_back(std::stol(it));
}
};
std::strong_ordering operator<=>(version const& rhs) const noexcept {
/// Three-way comparison operator
size_t const fields = std::min(data.size(), rhs.data.size());
// first compare all common fields
for(size_t i = 0; i != fields; ++i) {
if(data[i] == rhs.data[i]) continue;
else if(data[i] < rhs.data[i]) return std::strong_ordering::less;
else return std::strong_ordering::greater;
}
// if we're here, all common fields are equal - check for extra fields
if(data.size() == rhs.data.size()) return std::strong_ordering::equal; // no extra fields, so both versions equal
else if(data.size() > rhs.data.size()) return std::strong_ordering::greater; // lhs has more fields - we assume it to be greater
else return std::strong_ordering::less; // rhs has more fields - we assume it to be greater
}
bool operator==(version const& rhs) const noexcept {
return std::is_eq(*this <=> rhs);
}
};
Example usage:
std::cout << (version{"1.2.3.4"} < version{"1.2.3.5"}) << std::endl; // true
std::cout << (version{"1.2.3.4"} > version{"1.2.3.5"}) << std::endl; // false
std::cout << (version{"1.2.3.4"} == version{"1.2.3.5"}) << std::endl; // false
std::cout << (version{"1.2.3.4"} > version{"1.2.3"}) << std::endl; // true
std::cout << (version{"1.2.3.4"} < version{"1.2.3.4.5"}) << std::endl; // true
int VersionParser(char* version1, char* version2) {
int a1,b1, ret;
int a = strlen(version1);
int b = strlen(version2);
if (b>a) a=b;
for (int i=0;i<a;i++) {
a1 += version1[i];
b1 += version2[i];
}
if (b1>a1) ret = 1 ; // second version is fresher
else if (b1==a1) ret=-1; // versions is equal
else ret = 0; // first version is fresher
return ret;
}