Skip to content
This repository has been archived by the owner on Nov 19, 2019. It is now read-only.

Stack with time complexity of O(N logN) #26

Open
wants to merge 7 commits into
base: master
Choose a base branch
from

Conversation

saharki
Copy link

@saharki saharki commented Jul 28, 2018

Stacking with time complexity of O(N log N) instead of O(N^2).

Closes #20

@vlsi
Copy link

vlsi commented Jul 28, 2018

@saharki , thanks for the PR, however it does not seem to work.
What would be the output of your algorithm for the case like

0, 2
1, 3
2, 4
3, 5
4, 6
5, 7

?
It could fit in two lanes, however you seem to just pile the items up.

@saharki
Copy link
Author

saharki commented Jul 28, 2018

Thanks for pointing it out.

Although the last commit piles the items of your example to 3 levels (not 2 as you'd expect), it has the same output as the current stacking algorithm.

In addition, in some cases, my implementation of the stacking algorithm is more compact than the current algorithm.

For instance:

1, 3
2, 4
3, 5
3, 6
5, 7

Current stacking algorithm output:
currentalg

My stacking algorithm:
myalg

@vlsi
Copy link

vlsi commented Jul 29, 2018

Although the last commit piles the items of your example to 3 levels (not 2 as you'd expect)

Why item "3" is put on its own lane?
It should put it to the first one, shouldn't it?

I assume you use 0 (or a negative value) for horizontal margin to avoid dealing with small fractions.

@vlsi
Copy link

vlsi commented Jul 29, 2018

@saharki , just to clarify:

Suppose the algorithm has processed 100 items (out of 1000), and suppose it has allocated 10 rows.
Then comes item 101. Where should it put it?
I think the rule is

  1. Put the item to existing row if free space permits
  2. Use a row with maximal end value (to minimize "space loss")
  3. If none of the rows can handle the item, then a new row should be created

Naive implementation would be to store the latest item for each row in array and iterate over the array when placing each item.
That would produce O(N^2) for case like (1,10),(1,10),(1,10),(1,10),... Basically each item should be placed to its own row, the array size would become N, and so on.

In order to implement 2 and 3, I think a tree is required. The contents is "latest intervals for each row", and the ordering is "by end time".
So for each new interval X, the tree would be used "to find maximum entry that is less than x.start".

@saharki
Copy link
Author

saharki commented Jul 29, 2018

@vlsi

1. Put the item to existing row if free space permits
2. Use a row with maximal end value (to minimize "space loss")
3. If none of the rows can handle the item, then a new row should be created

What you described here wouldn't be a greedy algorithm, which has its pros and cons.

Of course my algorithm doesn't have the best output for this function that can be implemented, but the approach here is much KISS-er than the one you have suggested.

My implementation of the stacking algorithm is an improvement comparing to the current one in time complexity and space-saving output. Therefore, I suggest this PR should be approved and I will continue working for a more "dense" implementation later on (which justifies new issue to be open).

@vlsi
Copy link

vlsi commented Jul 29, 2018

What you described here wouldn't be a greedy algorithm,

Why do you think so?

Of course my algorithm doesn't have the best output

What is the algorithm exactly?
I have tried to follow it several times, yet I fail to understand what it does and how it works.

the approach here is much KISS-er than the one you have suggested.

So what?

improvement comparing to the current one in space-saving output

It is hard to tell if there are space savings or not. You have provided a single chart only, and it looks like the only cause original algorithm used 4 rows was margins.

I suggest this PR should be approved

Of course it is not up to me to decide, however:

  1. The algorithm is obscure. You do add 3 comments like "initialize top position for the next item", however the commends do not clarify the algorithm.
  2. It has apparent flaws in terms of interval packing
  3. Unit tests are missing

@saharki saharki force-pushed the master branch 3 times, most recently from 3684dda to f47818f Compare September 24, 2018 22:14
for (let j = 0, jj = items.length; j < jj; j++) {
const other = items[j];
shouldBail = shouldBailItemsRedrawFunction() || false;
if (items[i].stack && items[i + 1] && items[i + 1].top === null) {
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

items[i] -> item
items[i + 1] -> nextItem

if (shouldBail) { return true; }
shouldBail = shouldBailItemsRedrawFunction() || false;

if (shouldBail) { return true; }
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Move this to the beginning of the for loop before getting in to the conditionals

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

Successfully merging this pull request may close these issues.

How about using greedy algorithm for stacking?
3 participants