Reputation: 468
It's a sort of an algorithmic question, without a bond to any of the particular languages.
Let's say I have Np
point particles with continuous (read double
) x, y
coordinates on a 2d plane. The 2d plane is divided into N ⨉ N
cells.
For each particle I want a quick way (faster than O(Np^2)
) to find other particles in the same cell. Also, I don't want to go too far in memory usage, so I don't want another N ⨉ N + Np
array to store.
I "invented" a tricky way to realize this, but I'm asking this question just in case there's a canonical way of doing this.
Upvotes: 2
Views: 219
Reputation: 4236
Here is a solution with O(Np * log(Np)) time and O(Np) memory:
Initialize a dynamic DS container with {row,col} tuple as a key \
and a list of particles as a value
Iterate over each particle
Find {row, col} tuple for current particle
Find a value-list in container by {row, col} key
If there is no value in container for a value by this key
Then initialise a new particle list
Append current particle to a value-list
Container may be implemented as a balanced binary tree, which will give log(Np) multiplier to overall time complexity.
Another way to solve with O(Np + N) time and O(N) memory solution:
Initialize a simple lookup array byRow of size N, \
it will contain a list of particles in each cell
Iterate over each particle
Place the particle in corresponding cell of lookup array byRow by its ROW
Initialize another lookup array byCol of size N, \
it will contain a list of particles in each cell as well
Iterate over each cell of lookup list byRow
Iterate over each particle of the list in byRow[cellRow]
Place the particle in corresponding cell of byCol by its COL
Iterate over each particle of the list in byRow[cellRow]
\\ Now you have a list of other particles in the same NxN cell
\\ by looking at byCol[particleCol]
If byCol[particleCol] is not cleared
Print byCol[particleCol] list or put into other global storage and use later \
Clear byCol[particleCol] list
The idea is very simple. First you group particles by row storing them in lists of byRow
array. Then for particles of every list of byRow
array you make the same grouping by column. Each time you are reusing byCol
array. So overall memory complexity is O(N). Even we have two loops nested one in other we still have O(Np + N) time complexity because no inner step will be executed more than Np times.
Edit: Time complexity is O(Np + N) to be precise.
Upvotes: 1
Reputation: 13486
The canonical way to do this is to use a spatial indexing data structure, e.g. a kd-tree, with O(Np*log(Np)) construction time, O(Np^(1−1/K)+Mp) axis-aligned range (which is your cell) query time (K=2 dimensions, Mp points reported), O(Np) space.
Upvotes: 1
Reputation: 6404
There's no real answer other than to have a list of particles attached to each cell. Which is another N x N + p data structure. However memory is cheap and you should be able to afford it.
Upvotes: 0
Reputation: 452
Construct a list (or array) of sorted tuples of (used cell id, a list of particles in that cell) sorted by the cell id. The cell id could just be its (x, y) coordinates. The space complexity is O(Np)
. Constructing it should take O(Np log(Np))
time. Looking up the particles in the same cell is then O(log(Np))
via standard binary search.
To replace log(Np)
by 1
in these complexity estimates to get O(Np)
construction time and O(1)
look-up, replace the sorted list with a hash table.
Upvotes: 0