It does not matter in general.
Your examples aren't exactly fair. Your "player does collision" check looks like this:
for each player:
for each bullet:
if player.intersects(bullet), report it
Your "bullet does collision" check looks like this:
for each bullet:
for each other object in the world:
if bullet.intersects(object), report it
Yes, in that case, the first example is definitely better. It will execute 100 times, whereas the second example executes 10,000 times. A more fair example would be
for each bullet, for each player for the second case, which will also loop 100 times. If the first example is allowed to take advantage of the fact that system has individual lists of types and that bullets don't need to test against other bullets, why is the second not?
Most general-purpose collision systems don't operate like that because they don't have the foreknowledge of the system required by your first example, and because to build it out could be expensive in terms of memory, and not always a computational win. Doing so means you need to store collision properties in separate arrays for each type of object that can interact, or otherwise similarly manage and configure different blocks of collision data and iterate them possibly several times at different times in the update loop and it can quickly become a cumbersome and potentially cache-unfriendly mess. There are scenarios where such a specialized collision handling structure could be advantageous over other methods. But they are specialized scenarios.
In general collision handling works by looking at N objects and (modulo various optimizations for spatial organization, preventing duplicate checks in a given frame, et cetera), tests them all against each other, blindly firing out notifications to any interested party that "these two things hit each other, do something about it if you want."