One way to split them up is in terms of input and output: 1) input-only, 2) output-only, 3) input-output, and 4) no input, no output.
There's not a lot of #1, since nearly anything that happens could have some sort of response. The only examples I can think of are delete hooks, e.g. hook_file_delete(), hook_comment_delete(), where the hook gets the deleted object, but that object is already deleted, so there's no reason for a response.
The "registry-style" hooks would be #2, output only. They just feed data into a central registry and don't take any input. hook_menu() and hook_help() are examples.
hook_nodeapi() was #3, but now it's broken up into different functions like hook_node_presave() -- still #3 -- and hook_node_delete() -- which is now #1. This is the most common group. Many of the examples explicitly have the word "alter" in the hook name, e.g. hook_form_alter().
Something like hook_init() would be #4. Beyond general notification of an event, there's no input nor output.
That's a pretty arbitrary break-down though. You could easily argue for breaking up #3 into hooks where the output has the same structure as the input (alter) vs. hooks where the output has a completely different structure (call-response). Or you could combine #1 and #4, since the function call itself is a type of input, so the difference is just in level of detail.