If you can reliably detect that overlapping responses have occurred
(either by detecting gibberish - bad CRC, formatting, etc. - or line
noise - framing errors, etc.), this isn't too hard.
Broadcast an "identify" a query, with a range of addresses, initially
the whole address space. Any device with an address in the specified
range should respond. If you get one good response (or several, if
you're timing constraints allow that), life is good, record those and
move on. If, OTOH, you get an error, divide the range in half, and
resend the query for the half range. Continue the binary-like search
until each range returns either nothing, or good responses. Of course
you have to probe both sides of the division.
You need to allow enough time between queries to allow the line to
settle (IOW, the slowest possible response plus a bit).
At worst that will run in O(m*n), where m is the number of devices to
be found, and n is the number of bits in the address space. Actually
I think for cases where both n and m are not close to unity, the
runtime has to be considerably smaller than that.
For robustness, you need to have a little chat with each device to
verify it's existence after you've found it, and then you should tell
each found device to stop responding to ident queries. And then
repeat the whole process a few times (starting with the "whole address
space" query).
If you can't detect collision reliably, but with some probability, an
appropriate number of repetitions would allow you to reduce the
probability of missing a device to an arbitrarily low value. This
assumes that there are no systemic problems that would prevent you
from ever detecting a collision between two specific devices
(explicitly adding some random timing jitter to the responses may help
with that).