Find first range not in set of ranges - c++

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..
}
}
}

Related

flip set of pixels with respect to a given row coordinate

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.

How to reduce time complexity under c++ with nested loops and regex?

I have such function.
Input argument - vector of user names, vector of strings, number of top users.
First I count amount of occurancies for each user in strings. If there are several occurancies in one string - it still counts as 1.
Then I sort it by amount of occurancies. If amount of occurancies are equal - sort alphabetically user names.
And function return top N users with the most occurancy.
std::vector<std::string> GetTopUsers(const std::vector<std::string>& users,
const std::vector<std::string>& lines, const int topUsersNum) {
std::vector<std::pair<std::string, int>> userOccurancies;
//count user occurancies
for (const auto & user : users) {
int count = 0;
for (const auto &line : lines) {
std::regex rgx("\\b" + user + "\\b", std::regex::icase);
std::smatch match;
if (std::regex_search(line, match, rgx)) {
++count;
auto userIter = std::find_if(userOccurancies.begin(), userOccurancies.end(),
[&user](const std::pair<std::string, int>& element) { return element.first == user; });
if (userIter == userOccurancies.end()) {
userOccurancies.push_back(std::make_pair(user, count));
}
else {
userIter->second = count;
}
}
}
}
//sort by amount of occurancies, if occurancies are equal - sort alphabetically
std::sort(userOccurancies.begin(), userOccurancies.end(),
[](const std::pair<std::string, int>& p1, const std::pair<std::string, int>& p2)
{ return (p1.second > p2.second) ? true : (p1.second == p2.second ? p1.first < p2.first : false); });
//extract top N users
int topUsersSz = (topUsersNum <= userOccurancies.size() ? topUsersNum : userOccurancies.size());
std::vector<std::string> topUsers(topUsersSz);
for (int i = 0; i < topUsersSz; i++) {
topUsers.push_back(userOccurancies[i].first);
}
return topUsers;
}
So for the input
std::vector<std::string> users = { "john", "atest", "qwe" };
std::vector<std::string> lines = { "atest john", "Qwe", "qwe1", "qwe," };
int topUsersNum = 4;
output will be qwe atest john
But it looks very complex. O(n^2) for loops + regex inside. It must be O(n^3) or even more.
Can you give me please advices how to make it with less complexity in c++11?
And also give me advices about code.
Or maybe there are better board for questions about complexity and performance?
Thank you.
UDP
std::vector<std::string> GetTopUsers2(const std::vector<std::string>& users,
const std::vector<std::string>& lines, const size_t topUsersNum) {
std::vector<std::pair<std::string, int>> userOccurancies(users.size());
auto userOcIt = userOccurancies.begin();
for (const auto & user : users) {
userOcIt->first = std::move(user);
userOcIt->second = 0;
userOcIt++;
}
//count user occurancies
for (auto &user: userOccurancies) {
int count = 0;
std::regex rgx("\\b" + user.first + "\\b", std::regex::icase);
std::smatch match;
for (const auto &line : lines) {
if (std::regex_search(line, match, rgx)) {
++count;
user.second = count;
}
}
}
//sort by amount of occurancies, if occurancies are equal - sort alphabetically
std::sort(userOccurancies.begin(), userOccurancies.end(),
[](const std::pair<std::string, int>& p1, const std::pair<std::string, int>& p2)
{ return (p1.second > p2.second) ? true : (p1.second == p2.second ? p1.first < p2.first : false); });
//extract top N users
auto middle = userOccurancies.begin() + std::min(topUsersNum, userOccurancies.size());
int topUsersSz = (topUsersNum <= userOccurancies.size() ? topUsersNum : userOccurancies.size());
std::vector<std::string> topUsers(topUsersSz);
auto topIter = topUsers.begin();
for (auto iter = userOccurancies.begin(); iter != middle; iter++) {
*topIter = std::move(iter->first);
topIter++;
}
return topUsers;
}
Thanks to #Jarod42. I updated first part. I think that allocate memory to vector once at constructor is faster than call emplace_back every time, so I used it. If I am wrong - mark me.
Also I use c++11, not c++17.
time results:
Old: 3539400.00000 nanoseconds
New: 2674000.00000 nanoseconds
It is better but still looks complex, isn't it?
constructing regex is costly, and can be moved outside the loop:
also you might move string instead of copy.
You don't need to sort all range. std::partial_sort is enough.
And more important, you might avoid the inner find_if.
std::vector<std::string>
GetTopUsers(
std::vector<std::string> users,
const std::vector<std::string>& lines,
int topUsersNum)
{
std::vector<std::pair<std::string, std::size_t> userCount;
userCount.reserve(users.size());
for (auto& user : users) {
userCount.emplace_back(std::move(user), 0);
}
for (auto& [user, count] : userCount) {
std::regex rgx("\\b" + user + "\\b", std::regex::icase);
for (const auto &line : lines) {
std::smatch match;
if (std::regex_search(line, match, rgx)) {
++count;
}
}
}
//sort by amount of occurancies, if occurancies are equal - sort alphabetically
auto middle = userCount.begin() + std::min(topUsersNum, userCount.size());
std::partial_sort(userCount.begin(),
middle,
userCount.end(),
[](const auto& lhs, const auto& rhs)
{
return std::tie(rhs.second, lhs.first) < std::tie(lhs.second, rhs.first);
});
//extract top N users
std::vector<std::string> topUsers;
topUsers.reserve(std::distance(userCount.begin(), middle));
for (auto it = userCount.begin(); it != middle; ++it) {
topUsers.push_back(std::move(it->first));
}
return topUsers;
}
i'm no professional coder, but i've made your code a bit faster (~90% faster, unless my math is wrong or i timed it wrong).
what it does is, it goes trough each of the lines, and for each line it counts the number of occurences for each user given. if the number of occurences for the current user are larger than the previous one, it moves the user at the beginning of the vector.
#include <iostream>
#include <Windows.h>
#include <vector>
#include <string>
#include <regex>
#include <algorithm>
#include <chrono>
std::vector<std::string> GetTopUsers(const std::vector<std::string>& users,
const std::vector<std::string>& lines, const int topUsersNum) {
std::vector<std::pair<std::string, int>> userOccurancies;
//count user occurancies
for (const auto & user : users) {
int count = 0;
for (const auto &line : lines) {
std::regex rgx("\\b" + user + "\\b", std::regex::icase);
std::smatch match;
if (std::regex_search(line, match, rgx)) {
++count;
auto userIter = std::find_if(userOccurancies.begin(), userOccurancies.end(),
[&user](const std::pair<std::string, int>& element) { return element.first == user; });
if (userIter == userOccurancies.end()) {
userOccurancies.push_back(std::make_pair(user, count));
}
else {
userIter->second = count;
}
}
}
}
//sort by amount of occurancies, if occurancies are equal - sort alphabetically
std::sort(userOccurancies.begin(), userOccurancies.end(),
[](const std::pair<std::string, int>& p1, const std::pair<std::string, int>& p2)
{ return (p1.second > p2.second) ? true : (p1.second == p2.second ? p1.first < p2.first : false); });
//extract top N users
int topUsersSz = (topUsersNum <= userOccurancies.size() ? topUsersNum : userOccurancies.size());
std::vector<std::string> topUsers(topUsersSz);
for (int i = 0; i < topUsersSz; i++) {
topUsers.push_back(userOccurancies[i].first);
}
return topUsers;
}
unsigned int count_user_occurences(
std::string & line,
std::string & user
)
{
unsigned int occur = {};
std::string::size_type curr_index = {};
// while we can find the name of the user in the line, and we have not reached the end of the line
while((curr_index = line.find(user, curr_index)) != std::string::npos)
{
// increase the number of occurences
++occur;
// increase string index to skip the current user
curr_index += user.length();
}
// return the number of occurences
return occur;
}
std::vector<std::string> get_top_users(
std::vector<std::string> & user_list,
std::vector<std::string> & line_list
)
{
// create vector to hold results
std::vector<std::string> top_users = {};
// put all of the users inside the "top_users" vector
top_users = user_list;
// make sure none of the vectors are empty
if(false == user_list.empty()
&& false == line_list.empty())
{
// go trough each one of the lines
for(unsigned int i = {}; i < line_list.size(); ++i)
{
// holds the number of occurences for the previous user
unsigned int last_user_occur = {};
// go trough each one of the users (we copied the list into "top_users")
for(unsigned int j = {}; j < top_users.size(); ++j)
{
// get the number of the current user in the current line
unsigned int curr_user_occur = count_user_occurences(line_list.at(i), top_users.at(j));
// user temporary name holder
std::string temp_user = {};
// if the number of occurences of the current user is larger than the one of the previous user, move it at the top
if(curr_user_occur >= last_user_occur)
{
// save the current user's name
temp_user = top_users.at(j);
// erase the user from its current position
top_users.erase(top_users.begin() + j);
// move the user at the beginning of the vector
top_users.insert(top_users.begin(), temp_user);
}
// save the occurences of the current user to compare further users
last_user_occur = curr_user_occur;
}
}
}
// return the top user vector
return top_users;
}
int main()
{
std::vector<std::string> users = { "john", "atest", "qwe" };
std::vector<std::string> lines = { "atest john", "Qwe", "qwel", "qwe," };
// time the first function
auto start = std::chrono::high_resolution_clock::now();
std::vector<std::string> top_users = get_top_users(users, lines);
auto stop = std::chrono::high_resolution_clock::now();
// save the time in milliseconds
double time = std::chrono::duration_cast<std::chrono::nanoseconds>(stop - start).count();
// print time
printf("%.05f nanoseconds\n", time);
// time the second function
auto start2 = std::chrono::high_resolution_clock::now();
std::vector<std::string> top_users2 = GetTopUsers(users, lines, 4);
auto stop2 = std::chrono::high_resolution_clock::now();
// save the time in milliseconds
double time2 = std::chrono::duration_cast<std::chrono::nanoseconds>(stop2 - start2).count();
// print time
printf("%.05f nanoseconds", time2);
getchar();
return 0;
}
results (for my PC at least, they're pretty consistent across multiple runs):
366800.00000 nanoseconds
4235900.00000 nanoseconds

C++ map::find() in stl

map <int, map<int, string>> DP;
if( DP.find( ? ) != DP.end() )
{
// have found
}
How to fill in (). It seem like two dimension. I know how to deal with one dimension, for example:
map<int, string> DP;
if( DP.find(1) != DP.end() )
{
// have found
}
But I don't know how to deal with two dimension.
One dimension at a time:
auto it1 = DP.find(1);
if (it1 != DP.end()) {
auto it2 = it1->find(2);
if (it2 != it1->end()) {
// found: it2->second
}
}
I think Kerrek SB`s codes exists a little problem. The way of visiting second(inner) dimension should be like this:
auto OuterIter = DP.find(1);
if (OuterIter != DP.end())
{
auto InnerMap = OuterIter->second;
auto InnerIter = InnerMap.find(0);
if (InnerIter != InnerMap.end())
{
// found the second(inner) dimension element
}
}
And you can think about chtz`s advise: You may also consider directly using std::map, std::string>

Execute a function on matching pairs in a map

I have some code that looks roughly like this; given two maps, if the first key exists in both maps, then multiply the two second values together, then sum all the products. For example:
s1 = {{1, 2.5}, {2, 10.0}, {3, 0.5}};
s2 = {{1, 10.0}, {3, 20.0}, {4, 3.33}};
The answer should be 2.5*10.0 + 0.5*20.0, the sum of the products of the matching keys.
double calcProduct(std::map<int, double> const &s1, std::map<int, double> const &s2)
{
auto s1_it = s1.begin();
auto s2_it = s2.begin();
double result = 0;
while (s1_it != s1.end() && s2_it != s2.end())
{
if (s1_it->first == s2_it->first)
{
result += s1_it->second * s2_it->second;
s1_it++:
s2_it++;
}
else if (s1_it->first < s2_it->first)
{
s1_it = s1.lower_bound(s2_it->first);
}
else
{
s2_it = s2.lower_bound(s1_it->first);
}
}
return result;
}
I would like to refactor this and std::set_intersection seems to be close to what I want as the documentation has an example using std::back_inserter, but is there a way to get this to work on maps and avoid the intermediate array?
The code you're using is already very close to the way that set_intersect would be implemented. I can't see any advantage to creating a new map and iterating over it.
However there were a couple of things with your code I wanted to mention.
If you're going to increment your iterators you shouldn't make them constant.
I would expect that there will be more misses than hits when looking for equivalent elements. I would suggest having the less than comparisons first:
double calcProduct( std::map<int , double> const &s1 , std::map<int , double> const &s2 )
{
auto s1_it = s1.begin();
auto s2_it = s2.begin();
double result = 0;
while ( s1_it != s1.end() && s2_it != s2.end() )
{
if ( s1_it->first < s2_it->first )
{
s1_it = s1.lower_bound( s2_it->first );
}
else if(s2_it->first < s1_it->first )
{
s2_it = s2.lower_bound( s1_it->first );
}
else
{
result += s1_it->second * s2_it->second;
s1_it++;
s2_it++;
}
}
return result;
}

c++ Remove element from list and assign it to an object variable

I have a list of vector of Data (object) and I need to iterate through the list, find the biggest vector, remove it from the list and assign it to a new variable (which is a vector of Data). I am having problems during execution (it compiles ok but then stops working). How can I get the element without destroying it so I can manipulate later?
This is the code:
int biggestIndex = 0, biggestValue = -1;
i = 0;
list< vector<Data> >::iterator it;
for (it = (myList).begin(); it!= (myList).end(); it++) {
if ((*it).size() > biggerSize) {
biggestIndex = i;
biggestValue = basePList.size();
}
i++;
}
it = (myList).begin();
advance(it,biggestIndex);
vector<Data> partition = (vector<Data>) *it;
auto biggest = thelist.begin();
for (auto itr = thelist.begin() ; itr != thelist.end(); itr++) {
if (itr->size() > biggest->size()) {
biggest = itr;
}
}
vector<int> thebiggest = *biggest;
This of course needs to be compiled with at least C++11 extensions enabled, so add -std=c++11 or higher to your g++ command.
auto longest = *max_element(begin(myList),
end(myList),
[](const vector<Data>& v1, const vector<Data>& v2)
{return v1.size() < v2.size();});