Tôi nghĩ ví dụ đầu tiên của bạn hơi mơ hồ - các nút là đối tượng và các cạnh là con trỏ. Bạn có thể theo dõi những điều này bằng cách chỉ lưu trữ một con trỏ đến một số nút gốc, trong trường hợp đó việc truy cập vào một nút nhất định có thể không hiệu quả (giả sử bạn muốn nút 4 - nếu đối tượng nút không được cung cấp, bạn có thể phải tìm kiếm nó) . Trong trường hợp này, bạn cũng sẽ mất các phần của biểu đồ không thể truy cập được từ nút gốc. Tôi nghĩ đây là trường hợp f64 Rainbow đang giả định khi anh ấy nói độ phức tạp về thời gian để truy cập một nút nhất định là O (n).
Nếu không, bạn cũng có thể giữ một mảng (hoặc bản đồ băm) chứa đầy các con trỏ đến mỗi nút. Điều này cho phép O (1) truy cập vào một nút nhất định, nhưng làm tăng mức sử dụng bộ nhớ một chút. Nếu n là số nút và e là số cạnh, thì độ phức tạp không gian của cách tiếp cận này sẽ là O (n + e).
Độ phức tạp không gian đối với cách tiếp cận ma trận sẽ nằm dọc theo các dòng của O (n ^ 2) (giả sử các cạnh là một hướng). Nếu đồ thị của bạn thưa thớt, bạn sẽ có rất nhiều ô trống trong ma trận của mình. Nhưng nếu đồ thị của bạn được kết nối đầy đủ (e = n ^ 2), điều này so sánh thuận lợi với cách tiếp cận đầu tiên. Như RG nói, bạn cũng có thể có ít lần bỏ lỡ bộ nhớ cache hơn với cách tiếp cận này nếu bạn phân bổ ma trận dưới dạng một phần bộ nhớ, điều này có thể làm cho việc theo dõi nhiều cạnh xung quanh đồ thị nhanh hơn.
Cách tiếp cận thứ ba có lẽ là hiệu quả về không gian nhất đối với hầu hết các trường hợp - O (e) - nhưng sẽ làm cho việc tìm tất cả các cạnh của một nút nhất định trở thành một việc vặt của O (e). Tôi không thể nghĩ ra một trường hợp mà điều này sẽ rất hữu ích.