flip set of pixels with respect to a given row coordinate - c++

I'm trying to write a program that flips a region(represented as a set of Segments) with respect to a given row coordinate.
I don't know c++ well, so I got some errors I don't know why they appeared and how to fixed them.
Here is what I got so far:
struct Segment
{
int row;
int colStart;
int colStop;
};
std::vector<Segment> FlipVertically(const std::vector<Segment>& region, const int flipRow){
std::vector<Segment> vec, more, less;
for (std::vector<Segment>::reverse_iterator it = region.rbegin(); it != region.rend(); ++it){
if ((*it).row > flipRow){
more.insert(more.begin(), *it);
}
else{less.insert(less.begin(), *it);}
};
std::sort(more.begin(), more.end(), [](Segment const &a, Segment const &b){
return a.row > b.row;
});
std::sort(less.begin(), less.end(), [](Segment const &a, Segment const &b){
return a.row > b.row;
});
vec.insert(vec.end(), more.begin(), more.end());
vec.insert(vec.end(), less.begin(), less.end());
int counter = 1;
int i = 0;
while(i + 1 < vec.size()){
if (vec[i].row == vec[i + 1].row){
vec[i].row = counter;
}
else{
vec[i].row = counter;
counter++;}
i++;
}
vec.back().row = counter;
return vec;
}
The function should return Segments stored from top to bottom row, and in the same row from left to right column.
It says there is an error in while loop: comparison between signed and unsigned integer expressions [-Wsign-compare].
Also, I'm looking for tips to improve my algorithm because I feel it is not good because of two sorts I do after dividing data. I was thinking if it is possible to iterate through region and place Segments in the order I want during first iteration but wasn't able to find a way to do it.

This line
for (std::vector<Segment>::reverse_iterator it = region.rbegin(); it != region.rend(); ++it){
needs to be changed to
for (std::vector<Segment>::const_reverse_iterator it = region.rbegin(); it != region.rend(); ++it){
since region is a const container. Thus calling begin/rbegin/end/rend on const containers will return const_...iterator_type... for these.
But, better yet, use auto to simplify.
for(auto it = region.rbegin(); it != region.rend(); ++it)
But the whole first loop can be modified to go faster by looping forward
for(auto const& value : region)
{
if(value.row > flipRow)
{
more.push_back(value);
}
else
{
less.push_back(value);
}
}
On a final note. The first part of you algorithm
std::vector<Segment> vec, more, less;
for (std::vector<Segment>::reverse_iterator it = region.rbegin(); it != region.rend(); ++it){
if ((*it).row > flipRow){
more.insert(more.begin(), *it);
}
else{less.insert(less.begin(), *it);}
};
std::sort(more.begin(), more.end(), [](Segment const &a, Segment const &b){
return a.row > b.row;
});
std::sort(less.begin(), less.end(), [](Segment const &a, Segment const &b){
return a.row > b.row;
});
vec.insert(vec.end(), more.begin(), more.end());
vec.insert(vec.end(), less.begin(), less.end());
can be condensed down to
auto vec = region;
std::sort(vec.begin(), vec.end(), [](Segment const& a, Segment const& b) {
return a.row > b.row;
});
This rendering the use of flipRow obsolete. If you think it is needed
then there is likely another flaw in the implementation.

Related

Find first range not in set of ranges

I'm already familiar with the 1D bin packing nextFit, firstFit and bestFit + their offline algorithm variations. I mention these just for context.
My problem is about trying to find narrowest range (i,i+required_size) with width >= 1 that is not in the set of non-overlapping ranges:
int required_size;
std::set<std::pair<int,int>> ranges;
std::pair<int,int> result = findNarrowestFitFor(ranges,required_size);
How should I try solve this?
Explaining it to the duck: Obliviously I need to iterate the ranges and find two adjacent items that don't overlap.
Beta asked for example code, so here is what I'm at:
std::vector<char> buffer;
std::map<int,int> ranges;
// Search for free space by finding narrowest range
// that is not in ranges
const char * find_free_area(size_t nbytes) {
ptrdiff_t fit = buffer.capacity();
auto pos = ranges.begin();
auto itr = pos;
if(ranges.empty()) {
return buffer.data();
}
while(itr != ranges.end()) {
// Find next hole begin
itr = std::adjacent_find(ritr, ranges.end(),
[]( const std::pair<const int,int> & a,
const std::pair<const int,int> & b) {
return a.second != b.first;
});
if(itr == ranges.end()) {
itr = ranges.rbegin().base();
}
// Get next range
auto next = std::next(itr);
if(next != ranges.end()) {
auto space = next->first - itr->second;
if(space < fit) {
fit = space;
pos = ranges.begin();
std::advance(pos, itr->second);
}
} else if(itr->second ) {
// todo..
}
}
}

How to erase element from std::vector<string> by its length(erase not working)

i have given a vector `
vector<string> inputArray = { "aba","aa","ad","vcd","aba" };
and i want to return this vector which contains only string with the longest length, in this case i want to return only {"aba","vcd","aba"}, so for now i want to erase elements which length is not equal to the highest `
vector<string> allLongestStrings(vector<string> inputArray) {
int length = inputArray.size();
int longstring = inputArray[0].length();
int count = 0;
vector<string> result;
for (int i = 0; i < length; i++)
{
if (longstring < inputArray[i].length())
{
longstring = inputArray[i].length();
}
count++;
}
for (int = 0; i<count;i++)
{
if (inputArray[i].length() != longstring)
{
inputArray[i].erase(inputArray.begin() + i);
count--;
i--;
}
}
return inputArray;
}
but i get this error no instance of overloaded fucntion "std::basic_string<_Elem,_Traits,_Alloc>::erase[with_Elem=char,_Traits=std::char_traits<char>,_Alloc=std::allocator<char>]" matches the argument list" in inputArray[i].erase(inputArray.begin()+i); this line
what's wrong?
There are other problems, but this specific compiler message is telling you that's not the right way to remove specific character(s) from a string.
However, reading the question in the OP, we see that you wanted to remove a string from a vector. To fix that one specific error, simply change
inputArray[i].erase( /*character position(s) in the string*/ )
to
inputArray.erase( /*some position in the array*/ )
Or you could fix it so it uses an iterator in the string denoted by inputArray[i] to actually delete characters from that string, which of course isn't what you said you wanted to do. The point is, the error message is because you're using the wrong iterator type because you think that you're working with a vector, but you actually told it to work with a string that you got out of the vector.
And then you will compile and have other issues which are well covered in comments already.
The issue with inputArray[i].erase(inputArray.begin() + i); can be fixed as shown in Kenny Ostrom's answer.
I'd like to point out that the OP could make use of the erase-remove idiom or even create a new vector with only the bigger strings instead (the posted code is already copying the source vector).
#include <iostream>
#include <vector>
#include <string>
#include <algorithm>
template <typename InputIt>
auto only_the_longest_of(InputIt first, InputIt last)
{
using value_type = typename std::iterator_traits<InputIt>::value_type;
std::vector<value_type> result;
// find the longest size
auto longest = std::max_element(first, last,
[](value_type const &a, value_type const &b) {
return a.size() < b.size();
});
if ( longest == last )
return result;
// extract only the longest ones, instead of erasing
std::copy_if( first, last, std::back_inserter(result)
, [max_size = longest->size()] (value_type const& v) {
return v.size() >= max_size;
});
return result;
}
template <typename T>
auto erase_the_shortest_from(std::vector<T> &input)
{
// find the longest size
auto longest = std::max_element(input.cbegin(), input.cend(),
[](T const &a, T const &b) {
return a.size() < b.size();
});
if ( longest == input.cend() || longest->size() == 0 )
return input.end();
// implement erase-remove idiom
return input.erase(std::remove_if(
input.begin(), input.end(), [max_size = longest->size()] (T const &v) {
return v.size() < max_size;
}));
}
int main()
{
std::vector<std::string> test = {
"aba", "aa", "ad", "vcd", "aba"
};
// The original vector remain unchanged
auto result = only_the_longest_of(test.cbegin(), test.cend());
for (auto const& str : result)
std::cout << str << '\n';
std::cout << '\n';
// This will change the vector
erase_the_shortest_from(test);
for (auto const& str : test)
std::cout << str << '\n';
}

C++ remove_if without iterating through whole vector

I have a vector of pointers, pointing to approx 10MB of packets. In that, from first 2MB, I wanna delete all those that matches my predicate. The problem here is remove_if iterates through the whole vector, even though its not required in my use case. Is there any other efficient way?
fn_del_first_2MB
{
uint32 deletedSoFar = 0;
uint32 deleteLimit = 2000000;
auto it = std::remove_if (cache_vector.begin(), cache_vector.end(),[deleteLimit,&deletedSoFar](const rc_vector& item){
if(item.ptr_rc->ref_count <= 0) {
if (deletedSoFar < deleteLimit) {
deletedSoFar += item.ptr_rc->u16packet_size;
delete(item.ptr_rc->packet);
delete(item.ptr_rc);
return true;
}
else
return false;
}
else
return false;
});
cache_vector.erase(it, cache_vector.end());
}
In the above code, once the deletedSoFar is greater than deleteLimit, any iteration more than that is unwanted.
Instead of cache_vector.end() put your own iterator marker myIter. With the remove_if option you should follow the erase-remove idiom. Here is an example that affects only the first 4 elements:
#include <iostream>
#include <vector>
#include <algorithm>
int main()
{
std::vector<int> vec = { 1, 2, 3, 4, 5, 6, 7, 8, 9 };
size_t index = 4; // index is something you need to calculate
auto myIter = vec.begin() + index; // Your iterator instead of vec.end()
vec.erase(std::remove_if(vec.begin(), myIter, [](int x){return x < 3; }), myIter);
// modified vector:
for (const auto& a : vec)
{
std::cout << a << std::endl;
}
return 0;
}
You may use your own loop:
void fn_del_first_2MB()
{
const uint32 deleteLimit = 2000000;
uint32 deletedSoFar = 0;
auto dest = cache_vector.begin();
auto it = dest
for (; it != cache_vector.end(); ++it) {
const auto& item = *it;
if (item.ptr_rc->ref_count <= 0) {
deletedSoFar += item.ptr_rc->u16packet_size;
delete(item.ptr_rc->packet);
delete(item.ptr_rc);
if (deletedSoFar >= deleteLimit) {
++it;
break;
}
} else if (dest != it) {
*dest = std::move(*it);
++dest;
}
}
cache_vector.erase(dest, it);
}
There is no need for std::remove_if() to pass the .end() iterator as the second argument: as long as the first argument can reach the second argument by incrementing, any iterators can be passed.
There is somewhat of a complication as your condition depends on the accumulated size of the elements encountered so far. As it turns out, it looks as if std::remove_if() won't be used. Something like this should work (although I'm not sure if this use of std::find_if() is actually legal as it keeps changing the predicate):
std::size_t accumulated_size(0u);
auto send(std::find_if(cache_vector.begin(), cache_vector.end(),
[&](rc_vector const& item) {
bool rc(accumulated_size < delete_limit);
accumulated_size += item.ptr_rc->u16packet_size;
return rc;
});
std::for_each(cache_vector.begin(), send, [](rc_vector& item) {
delete(item.ptr_rc->packet);
delete(item.ptr_rc);
});
cache_vector.erase(cache_vector.begin(), send);
The std::for_each() could be folded into the use of std::find_if() as well but I prefer to keep things logically separate. For a sufficiently large sequence there could be a performance difference when the memory needs to be transferred to the cache twice. For the tiny numbers quoted I doubt that the difference can be measured.

C++ Bimap Left unordered_map Right sorted mutable multimap

I need to implement the following datastructure for my project. I have a relation of
const MyClass*
to
uint64_t
For every pointer I want to save a counter connected to it, which can be changed over time (in fact only incremented). This would be no problem, I could simply store it in a std::map. The problem is that I need fast access to the pointers which have the highest values.
That is why I came to the conclusion to use a boost::bimap. It is defined is follows for my project:
typedef boost::bimaps::bimap<
boost::bimaps::unordered_set_of< const MyClass* >,
boost::bimaps::multiset_of< uint64_t, std::greater<uint64_t> >
> MyBimap;
MyBimap bimap;
This would work fine, but am I right that I can not modify the uint64_t on pair which were inserted once? The documentation says that multiset_of is constant and therefore I cannot change a value of pair in the bimap.
What can I do? What would be the correct way to change the value of one key in this bimap? Or is there a simpler data structure possible for this problem?
Here's a simple hand-made solution.
Internally it keeps a map to store the counts indexed by object pointer, and a further multi-set of iterators, ordered by descending count of their pointees.
Whenever you modify a count, you must re-index. I have done this piecemeal, but you could do it as a batch update, depending on requirements.
Note that in c++17 there is a proposed splice operation for sets and maps, which would make the re-indexing extremely fast.
#include <map>
#include <set>
#include <vector>
struct MyClass { };
struct store
{
std::uint64_t add_value(MyClass* p, std::uint64_t count = 0)
{
add_index(_map.emplace(p, count).first);
return count;
}
std::uint64_t increment(MyClass* p)
{
auto it = _map.find(p);
if (it == std::end(_map)) {
// in this case, we'll create one - we could throw instead
return add_value(p, 1);
}
else {
remove_index(it);
++it->second;
add_index(it);
return it->second;
}
}
std::uint64_t query(MyClass* p) const {
auto it = _map.find(p);
if (it == std::end(_map)) {
// in this case, we'll create one - we could throw instead
return 0;
}
else {
return it->second;
}
}
std::vector<std::pair<MyClass*, std::uint64_t>> top_n(std::size_t n)
{
std::vector<std::pair<MyClass*, std::uint64_t>> result;
result.reserve(n);
for (auto idx = _value_index.begin(), idx_end = _value_index.end() ;
n && idx != idx_end ;
++idx, --n) {
result.emplace_back((*idx)->first, (*idx)->second);
}
return result;
}
private:
using map_type = std::map<MyClass*, std::uint64_t>;
struct by_count
{
bool operator()(map_type::const_iterator l, map_type::const_iterator r) const {
// note: greater than orders by descending count
return l->second > r->second;
}
};
using value_index_type = std::multiset<map_type::iterator, by_count>;
void add_index(map_type::iterator iter)
{
_value_index.emplace(iter->second, iter);
}
void remove_index(map_type::iterator iter)
{
for(auto range = _value_index.equal_range(iter);
range.first != range.second;
++range.first)
{
if (*range.first == iter) {
_value_index.erase(range.first);
return;
}
}
}
map_type _map;
value_index_type _value_index;
};

fill structure while finding min_element, C++

I want to fill some structure while finding minimum element. Pl find the code below
tyoedef struct Point
{
double x, y;
}Point;
I have a vector of points - std::vector<Point> V in which i have few thousand points.
There is another struct I have
typedef struct cart
{
Point pt;
double val_1; // computed using only Pt
double val_2; // computer using only Pt
}cart;
Now I have two tasks:
I need to find minimum element from structure V.
Fill the structure cart, which is directly dependent on V.
I can do this using following code.
std::vector<cart> vCart;
for(unsigned i = 0; i < V.size(); ++i)
{
cart thsElement;
thsElement.pt = V[i];
thsElement.val_1 = compute_val_1(V[i]);
thsElement.val_2 = compute_val_2(V[i]);
vCart.push_back(thsElement)
}
auto it = std::min_element(vCart.begin(), vCart.end(), lex_sort);
bool lex_sort(cart const &a, cart const &b)
{
if(a.pt.x < b.pt.x) return true;
if(a.pt.x == b.pt.x) return (a.pt.y < b.pt.y);
}
Now there is an evident problem with this implementation.
There are two loops. One for filling the structure and other for finding the min element (std::min_element() has to have a loop to iterate over all the values). I am fighting for few miliseconds' improvement. So this is not a good code. Moreover, this seems so C_style
So I came up with following code.
std::vector<cart> vCart;
std::iterator <vCart> st_ite;
auto it = std::min_element(V.begin(), V.end(), boost::bind(FillStruct_LexSort, st_ite, _1, _2)); // V is a vector of Point
bool FillStruct_LexSort(std::insert_iterator< std::vector<Cart>> vcpInput, const Point &a, const Point &b)
{
Cart thsPt;
if(a.x() < b.x())
{
thsPt.pt = b;
thsPt.val_1 = compute_val_1(b);
thsPt.val_2 = compute_val_2(b);
(*vcpInput++) = (thsPt);
return true;
}
if (a.x() == b.x())
{
if(a.y() < b.y())
{
thsPt.pt = b;
thsPt.val_1 = compute_val_1(b);
thsPt.val_2 = compute_val_2(b);
(*vcpInput++) = (thsPt);
return true;
}
}
thsPt.pt = a;
thsPt.val_1 = compute_val_1(b);
thsPt.val_2 = compute_val_2(b);
(*vcpInput++) = (thsPt);
return false;
}
Now, the problem is - I get segmentation fault. I do not know how should I use iterator to insert a value. I tried passing reference to vCart, but vCart is empty after calling min_element(..). I even tried insert_iterator, but with no success.
So pl suggest.
It seems you want something like:
bool lex_sort(const Point& lhs, const Point& rhs)
{
return std::tie(lhs.x, lhs.y) < std::tie(rhs.x, rhs.y);
}
and then
auto it = std::min_element(V.begin(), V.end(), &lex_sort);
if (it == V.end()) {
// V is empty.
} else {
Cart thsPt;
thsPt.pt = it;
thsPt.val_1 = compute_val_1(*it);
thsPt.val_2 = compute_val_2(*it);
return thsPt;
}
Note that if val_1/val_2 always depend of pt, you can add a constructor for Cart which take a Point