Я думаю, что ваш первый пример немного неоднозначен - узлы как объекты и ребра как указатели. Вы можете отслеживать их, сохраняя только указатель на некоторый корневой узел, и в этом случае доступ к данному узлу может быть неэффективным (скажем, вам нужен узел 4 - если объект узла не предоставлен, вам, возможно, придется его искать) . В этом случае вы также потеряете части графа, которые недоступны из корневого узла. Я думаю, что это тот случай, когда радуга f64 предполагает, когда он говорит, что временная сложность для доступа к данному узлу составляет O (n).
В противном случае вы также можете сохранить массив (или хэш-карту), полный указателей на каждый узел. Это позволяет O (1) доступ к данному узлу, но немного увеличивает использование памяти. Если n - количество узлов, а e - количество ребер, пространственная сложность этого подхода будет O (n + e).
Сложность пространства для матричного подхода будет примерно равна O (n ^ 2) (при условии, что ребра однонаправлены). Если ваш график разреженный, в вашей матрице будет много пустых ячеек. Но если ваш график полностью связан (e = n ^ 2), это выгодно отличается от первого подхода. Как говорит RG, при таком подходе у вас может быть меньше промахов в кэше, если вы выделяете матрицу как один фрагмент памяти, что может ускорить отслеживание множества ребер вокруг графа.
Третий подход, вероятно, наиболее эффективен по пространству для большинства случаев - O (e) - но сделает поиск всех ребер данного узла задачей O (e). Я не могу придумать случая, когда это было бы очень полезно.