Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

MergeSkylines could be O(n) #8

Open
briterator opened this issue Nov 20, 2016 · 2 comments
Open

MergeSkylines could be O(n) #8

briterator opened this issue Nov 20, 2016 · 2 comments

Comments

@briterator
Copy link

MergeSkylines calls erase in a loop potentially N times. Each call is O(n), making this function O(n^2).

If you use an algorithm like std::unique this function would be O(n).

pseudocode:

auto compare = [](SkylineNode& a, SkylineNode& b)
{
	if (a.y == b.y)
	{
		a.width += b.width;
		return true;
	}
	return false;
};
auto new_end = std::unique(skyLine.begin(), skyLine.end(), compare);
skyLine.erase( new_end , skyLine.end());

cppreference states that the predicate is not allowed to modify a and b in the above code which we are doing. To work around this limitation you could simply copy the implementation of std::unique found on cppreference and put it into your own algorithm. The reference implementation of std::unique that they provide should work fine with mutating the values. Alternatively you could just use the implementation of std::unique as inspiration for a specialized solution.

Thanks for providing this library!

@juj
Copy link
Owner

juj commented Nov 20, 2016

Thanks for reporting. Didn't yet have time to check into too close detail, but I think that MergeSkylines() can actually merge a skyline at most twice, since it is called after each new rectangle has been placed, so the skyline can at most line up on both left and right sides. So the loop would be able to find the location where that case happens, and return out immediately afterwards.

A location where such a quadratic erase could occur is at https://github.com/juj/RectangleBinPack/blob/master/SkylineBinPack.cpp#L246. Although that can be fixed by deferring the erases until after the end of the loop body, because the erase range is always contiguous.

@briterator
Copy link
Author

briterator commented Nov 20, 2016

MergeSkylines() can actually merge a skyline at most twice, since it is called after each new rectangle has been placed, so the skyline can at most line up on both left and right sides.

Ah, okay! If that is the case then maybe MergeSkylines can be simplified to only examine this more restricted domain of candidates around the recently added entry. That would be much better than what I suggested.

A location where such a quadratic erase could occur is at ...

I agree, that looks like it could be done as a single call to erase() after the loop.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants