You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
hello-algo/en/docs/chapter_graph/graph_operations.md

699 lines
26 KiB

8 months ago
---
comments: true
---
# 9.2   Basic operations on graphs
The basic operations on graphs can be divided into operations on "edges" and operations on "vertices". Under the two representation methods of "adjacency matrix" and "adjacency list", the implementation methods are different.
## 9.2.1   Implementation based on adjacency matrix
7 months ago
Given an undirected graph with $n$ vertices, the various operations are implemented as shown in Figure 9-7.
8 months ago
- **Adding or removing an edge**: Directly modify the specified edge in the adjacency matrix, using $O(1)$ time. Since it is an undirected graph, it is necessary to update the edges in both directions simultaneously.
- **Adding a vertex**: Add a row and a column at the end of the adjacency matrix and fill them all with $0$s, using $O(n)$ time.
- **Removing a vertex**: Delete a row and a column in the adjacency matrix. The worst case is when the first row and column are removed, requiring $(n-1)^2$ elements to be "moved up and to the left", thus using $O(n^2)$ time.
- **Initialization**: Pass in $n$ vertices, initialize a vertex list `vertices` of length $n$, using $O(n)$ time; initialize an $n \times n$ size adjacency matrix `adjMat`, using $O(n^2)$ time.
=== "Initialize adjacency matrix"
![Initialization, adding and removing edges, adding and removing vertices in adjacency matrix](graph_operations.assets/adjacency_matrix_step1_initialization.png){ class="animation-figure" }
=== "Add an edge"
![adjacency_matrix_add_edge](graph_operations.assets/adjacency_matrix_step2_add_edge.png){ class="animation-figure" }
=== "Remove an edge"
![adjacency_matrix_remove_edge](graph_operations.assets/adjacency_matrix_step3_remove_edge.png){ class="animation-figure" }
=== "Add a vertex"
![adjacency_matrix_add_vertex](graph_operations.assets/adjacency_matrix_step4_add_vertex.png){ class="animation-figure" }
=== "Remove a vertex"
![adjacency_matrix_remove_vertex](graph_operations.assets/adjacency_matrix_step5_remove_vertex.png){ class="animation-figure" }
<p align="center"> Figure 9-7 &nbsp; Initialization, adding and removing edges, adding and removing vertices in adjacency matrix </p>
Below is the implementation code for graphs represented using an adjacency matrix:
=== "Python"
```python title="graph_adjacency_matrix.py"
class GraphAdjMat:
7 months ago
"""Undirected graph class based on adjacency matrix"""
8 months ago
def __init__(self, vertices: list[int], edges: list[list[int]]):
7 months ago
"""Constructor"""
# Vertex list, elements represent "vertex value", index represents "vertex index"
8 months ago
self.vertices: list[int] = []
7 months ago
# Adjacency matrix, row and column indices correspond to "vertex index"
8 months ago
self.adj_mat: list[list[int]] = []
7 months ago
# Add vertex
8 months ago
for val in vertices:
self.add_vertex(val)
7 months ago
# Add edge
6 months ago
# Edges elements represent vertex indices
8 months ago
for e in edges:
self.add_edge(e[0], e[1])
def size(self) -> int:
7 months ago
"""Get the number of vertices"""
8 months ago
return len(self.vertices)
def add_vertex(self, val: int):
7 months ago
"""Add vertex"""
8 months ago
n = self.size()
7 months ago
# Add new vertex value to the vertex list
8 months ago
self.vertices.append(val)
7 months ago
# Add a row to the adjacency matrix
8 months ago
new_row = [0] * n
self.adj_mat.append(new_row)
7 months ago
# Add a column to the adjacency matrix
8 months ago
for row in self.adj_mat:
row.append(0)
def remove_vertex(self, index: int):
7 months ago
"""Remove vertex"""
8 months ago
if index >= self.size():
raise IndexError()
7 months ago
# Remove vertex at `index` from the vertex list
8 months ago
self.vertices.pop(index)
7 months ago
# Remove the row at `index` from the adjacency matrix
8 months ago
self.adj_mat.pop(index)
7 months ago
# Remove the column at `index` from the adjacency matrix
8 months ago
for row in self.adj_mat:
row.pop(index)
def add_edge(self, i: int, j: int):
7 months ago
"""Add edge"""
# Parameters i, j correspond to vertices element indices
# Handle index out of bounds and equality
8 months ago
if i < 0 or j < 0 or i >= self.size() or j >= self.size() or i == j:
raise IndexError()
7 months ago
# In an undirected graph, the adjacency matrix is symmetric about the main diagonal, i.e., satisfies (i, j) == (j, i)
8 months ago
self.adj_mat[i][j] = 1
self.adj_mat[j][i] = 1
def remove_edge(self, i: int, j: int):
7 months ago
"""Remove edge"""
# Parameters i, j correspond to vertices element indices
# Handle index out of bounds and equality
8 months ago
if i < 0 or j < 0 or i >= self.size() or j >= self.size() or i == j:
raise IndexError()
self.adj_mat[i][j] = 0
self.adj_mat[j][i] = 0
def print(self):
7 months ago
"""Print adjacency matrix"""
print("Vertex list =", self.vertices)
print("Adjacency matrix =")
8 months ago
print_matrix(self.adj_mat)
```
=== "C++"
```cpp title="graph_adjacency_matrix.cpp"
6 months ago
/* Undirected graph class based on adjacency matrix */
class GraphAdjMat {
vector<int> vertices; // Vertex list, elements represent "vertex value", index represents "vertex index"
vector<vector<int>> adjMat; // Adjacency matrix, row and column indices correspond to "vertex index"
public:
/* Constructor */
GraphAdjMat(const vector<int> &vertices, const vector<vector<int>> &edges) {
// Add vertex
for (int val : vertices) {
addVertex(val);
}
// Add edge
// Edges elements represent vertex indices
for (const vector<int> &edge : edges) {
addEdge(edge[0], edge[1]);
}
}
/* Get the number of vertices */
int size() const {
return vertices.size();
}
/* Add vertex */
void addVertex(int val) {
int n = size();
// Add new vertex value to the vertex list
vertices.push_back(val);
// Add a row to the adjacency matrix
adjMat.emplace_back(vector<int>(n, 0));
// Add a column to the adjacency matrix
for (vector<int> &row : adjMat) {
row.push_back(0);
}
}
/* Remove vertex */
void removeVertex(int index) {
if (index >= size()) {
throw out_of_range("Vertex does not exist");
}
// Remove vertex at `index` from the vertex list
vertices.erase(vertices.begin() + index);
// Remove the row at `index` from the adjacency matrix
adjMat.erase(adjMat.begin() + index);
// Remove the column at `index` from the adjacency matrix
for (vector<int> &row : adjMat) {
row.erase(row.begin() + index);
}
}
/* Add edge */
// Parameters i, j correspond to vertices element indices
void addEdge(int i, int j) {
// Handle index out of bounds and equality
if (i < 0 || j < 0 || i >= size() || j >= size() || i == j) {
throw out_of_range("Vertex does not exist");
}
// In an undirected graph, the adjacency matrix is symmetric about the main diagonal, i.e., satisfies (i, j) == (j, i)
adjMat[i][j] = 1;
adjMat[j][i] = 1;
}
/* Remove edge */
// Parameters i, j correspond to vertices element indices
void removeEdge(int i, int j) {
// Handle index out of bounds and equality
if (i < 0 || j < 0 || i >= size() || j >= size() || i == j) {
throw out_of_range("Vertex does not exist");
}
adjMat[i][j] = 0;
adjMat[j][i] = 0;
}
/* Print adjacency matrix */
void print() {
cout << "Vertex list = ";
printVector(vertices);
cout << "Adjacency matrix =" << endl;
printVectorMatrix(adjMat);
}
};
8 months ago
```
=== "Java"
```java title="graph_adjacency_matrix.java"
7 months ago
/* Undirected graph class based on adjacency matrix */
8 months ago
class GraphAdjMat {
7 months ago
List<Integer> vertices; // Vertex list, elements represent "vertex value", index represents "vertex index"
List<List<Integer>> adjMat; // Adjacency matrix, row and column indices correspond to "vertex index"
8 months ago
7 months ago
/* Constructor */
8 months ago
public GraphAdjMat(int[] vertices, int[][] edges) {
this.vertices = new ArrayList<>();
this.adjMat = new ArrayList<>();
7 months ago
// Add vertex
8 months ago
for (int val : vertices) {
addVertex(val);
}
7 months ago
// Add edge
6 months ago
// Edges elements represent vertex indices
8 months ago
for (int[] e : edges) {
addEdge(e[0], e[1]);
}
}
7 months ago
/* Get the number of vertices */
8 months ago
public int size() {
return vertices.size();
}
7 months ago
/* Add vertex */
8 months ago
public void addVertex(int val) {
int n = size();
7 months ago
// Add new vertex value to the vertex list
8 months ago
vertices.add(val);
7 months ago
// Add a row to the adjacency matrix
8 months ago
List<Integer> newRow = new ArrayList<>(n);
for (int j = 0; j < n; j++) {
newRow.add(0);
}
adjMat.add(newRow);
7 months ago
// Add a column to the adjacency matrix
8 months ago
for (List<Integer> row : adjMat) {
row.add(0);
}
}
7 months ago
/* Remove vertex */
8 months ago
public void removeVertex(int index) {
if (index >= size())
throw new IndexOutOfBoundsException();
7 months ago
// Remove vertex at `index` from the vertex list
8 months ago
vertices.remove(index);
7 months ago
// Remove the row at `index` from the adjacency matrix
8 months ago
adjMat.remove(index);
7 months ago
// Remove the column at `index` from the adjacency matrix
8 months ago
for (List<Integer> row : adjMat) {
row.remove(index);
}
}
7 months ago
/* Add edge */
// Parameters i, j correspond to vertices element indices
8 months ago
public void addEdge(int i, int j) {
7 months ago
// Handle index out of bounds and equality
8 months ago
if (i < 0 || j < 0 || i >= size() || j >= size() || i == j)
throw new IndexOutOfBoundsException();
7 months ago
// In an undirected graph, the adjacency matrix is symmetric about the main diagonal, i.e., satisfies (i, j) == (j, i)
8 months ago
adjMat.get(i).set(j, 1);
adjMat.get(j).set(i, 1);
}
7 months ago
/* Remove edge */
// Parameters i, j correspond to vertices element indices
8 months ago
public void removeEdge(int i, int j) {
7 months ago
// Handle index out of bounds and equality
8 months ago
if (i < 0 || j < 0 || i >= size() || j >= size() || i == j)
throw new IndexOutOfBoundsException();
adjMat.get(i).set(j, 0);
adjMat.get(j).set(i, 0);
}
7 months ago
/* Print adjacency matrix */
8 months ago
public void print() {
7 months ago
System.out.print("Vertex list = ");
8 months ago
System.out.println(vertices);
7 months ago
System.out.println("Adjacency matrix =");
8 months ago
PrintUtil.printMatrix(adjMat);
}
}
```
=== "C#"
```csharp title="graph_adjacency_matrix.cs"
7 months ago
[class]{GraphAdjMat}-[func]{}
8 months ago
```
=== "Go"
```go title="graph_adjacency_matrix.go"
7 months ago
[class]{graphAdjMat}-[func]{}
8 months ago
```
=== "Swift"
```swift title="graph_adjacency_matrix.swift"
7 months ago
[class]{GraphAdjMat}-[func]{}
8 months ago
```
=== "JS"
```javascript title="graph_adjacency_matrix.js"
7 months ago
[class]{GraphAdjMat}-[func]{}
8 months ago
```
=== "TS"
```typescript title="graph_adjacency_matrix.ts"
7 months ago
[class]{GraphAdjMat}-[func]{}
8 months ago
```
=== "Dart"
```dart title="graph_adjacency_matrix.dart"
7 months ago
[class]{GraphAdjMat}-[func]{}
8 months ago
```
=== "Rust"
```rust title="graph_adjacency_matrix.rs"
7 months ago
[class]{GraphAdjMat}-[func]{}
8 months ago
```
=== "C"
```c title="graph_adjacency_matrix.c"
7 months ago
[class]{GraphAdjMat}-[func]{}
8 months ago
```
=== "Kotlin"
```kotlin title="graph_adjacency_matrix.kt"
7 months ago
[class]{GraphAdjMat}-[func]{}
8 months ago
```
=== "Ruby"
```ruby title="graph_adjacency_matrix.rb"
7 months ago
[class]{GraphAdjMat}-[func]{}
8 months ago
```
=== "Zig"
```zig title="graph_adjacency_matrix.zig"
[class]{GraphAdjMat}-[func]{}
```
## 9.2.2 &nbsp; Implementation based on adjacency list
7 months ago
Given an undirected graph with a total of $n$ vertices and $m$ edges, the various operations can be implemented as shown in Figure 9-8.
8 months ago
- **Adding an edge**: Simply add the edge at the end of the corresponding vertex's linked list, using $O(1)$ time. Because it is an undirected graph, it is necessary to add edges in both directions simultaneously.
- **Removing an edge**: Find and remove the specified edge in the corresponding vertex's linked list, using $O(m)$ time. In an undirected graph, it is necessary to remove edges in both directions simultaneously.
- **Adding a vertex**: Add a linked list in the adjacency list and make the new vertex the head node of the list, using $O(1)$ time.
- **Removing a vertex**: It is necessary to traverse the entire adjacency list, removing all edges that include the specified vertex, using $O(n + m)$ time.
- **Initialization**: Create $n$ vertices and $2m$ edges in the adjacency list, using $O(n + m)$ time.
=== "Initialize adjacency list"
![Initialization, adding and removing edges, adding and removing vertices in adjacency list](graph_operations.assets/adjacency_list_step1_initialization.png){ class="animation-figure" }
=== "Add an edge"
![adjacency_list_add_edge](graph_operations.assets/adjacency_list_step2_add_edge.png){ class="animation-figure" }
=== "Remove an edge"
![adjacency_list_remove_edge](graph_operations.assets/adjacency_list_step3_remove_edge.png){ class="animation-figure" }
=== "Add a vertex"
![adjacency_list_add_vertex](graph_operations.assets/adjacency_list_step4_add_vertex.png){ class="animation-figure" }
=== "Remove a vertex"
![adjacency_list_remove_vertex](graph_operations.assets/adjacency_list_step5_remove_vertex.png){ class="animation-figure" }
<p align="center"> Figure 9-8 &nbsp; Initialization, adding and removing edges, adding and removing vertices in adjacency list </p>
6 months ago
Below is the adjacency list code implementation. Compared to Figure 9-8, the actual code has the following differences.
8 months ago
- For convenience in adding and removing vertices, and to simplify the code, we use lists (dynamic arrays) instead of linked lists.
- Use a hash table to store the adjacency list, `key` being the vertex instance, `value` being the list (linked list) of adjacent vertices of that vertex.
Additionally, we use the `Vertex` class to represent vertices in the adjacency list. The reason for this is: if, like with the adjacency matrix, list indexes were used to distinguish different vertices, then suppose you want to delete the vertex at index $i$, you would need to traverse the entire adjacency list and decrement all indexes greater than $i$ by $1$, which is very inefficient. However, if each vertex is a unique `Vertex` instance, then deleting a vertex does not require any changes to other vertices.
=== "Python"
```python title="graph_adjacency_list.py"
class GraphAdjList:
7 months ago
"""Undirected graph class based on adjacency list"""
8 months ago
def __init__(self, edges: list[list[Vertex]]):
7 months ago
"""Constructor"""
# Adjacency list, key: vertex, value: all adjacent vertices of that vertex
8 months ago
self.adj_list = dict[Vertex, list[Vertex]]()
7 months ago
# Add all vertices and edges
8 months ago
for edge in edges:
self.add_vertex(edge[0])
self.add_vertex(edge[1])
self.add_edge(edge[0], edge[1])
def size(self) -> int:
7 months ago
"""Get the number of vertices"""
8 months ago
return len(self.adj_list)
def add_edge(self, vet1: Vertex, vet2: Vertex):
7 months ago
"""Add edge"""
8 months ago
if vet1 not in self.adj_list or vet2 not in self.adj_list or vet1 == vet2:
raise ValueError()
7 months ago
# Add edge vet1 - vet2
8 months ago
self.adj_list[vet1].append(vet2)
self.adj_list[vet2].append(vet1)
def remove_edge(self, vet1: Vertex, vet2: Vertex):
7 months ago
"""Remove edge"""
8 months ago
if vet1 not in self.adj_list or vet2 not in self.adj_list or vet1 == vet2:
raise ValueError()
7 months ago
# Remove edge vet1 - vet2
8 months ago
self.adj_list[vet1].remove(vet2)
self.adj_list[vet2].remove(vet1)
def add_vertex(self, vet: Vertex):
7 months ago
"""Add vertex"""
8 months ago
if vet in self.adj_list:
return
7 months ago
# Add a new linked list to the adjacency list
8 months ago
self.adj_list[vet] = []
def remove_vertex(self, vet: Vertex):
7 months ago
"""Remove vertex"""
8 months ago
if vet not in self.adj_list:
raise ValueError()
7 months ago
# Remove the vertex vet's corresponding linked list from the adjacency list
8 months ago
self.adj_list.pop(vet)
7 months ago
# Traverse other vertices' linked lists, removing all edges containing vet
8 months ago
for vertex in self.adj_list:
if vet in self.adj_list[vertex]:
self.adj_list[vertex].remove(vet)
def print(self):
7 months ago
"""Print the adjacency list"""
print("Adjacency list =")
8 months ago
for vertex in self.adj_list:
tmp = [v.val for v in self.adj_list[vertex]]
print(f"{vertex.val}: {tmp},")
```
=== "C++"
```cpp title="graph_adjacency_list.cpp"
6 months ago
/* Undirected graph class based on adjacency list */
class GraphAdjList {
public:
// Adjacency list, key: vertex, value: all adjacent vertices of that vertex
unordered_map<Vertex *, vector<Vertex *>> adjList;
/* Remove a specified node from vector */
void remove(vector<Vertex *> &vec, Vertex *vet) {
for (int i = 0; i < vec.size(); i++) {
if (vec[i] == vet) {
vec.erase(vec.begin() + i);
break;
}
}
}
/* Constructor */
GraphAdjList(const vector<vector<Vertex *>> &edges) {
// Add all vertices and edges
for (const vector<Vertex *> &edge : edges) {
addVertex(edge[0]);
addVertex(edge[1]);
addEdge(edge[0], edge[1]);
}
}
/* Get the number of vertices */
int size() {
return adjList.size();
}
/* Add edge */
void addEdge(Vertex *vet1, Vertex *vet2) {
if (!adjList.count(vet1) || !adjList.count(vet2) || vet1 == vet2)
throw invalid_argument("Vertex does not exist");
// Add edge vet1 - vet2
adjList[vet1].push_back(vet2);
adjList[vet2].push_back(vet1);
}
/* Remove edge */
void removeEdge(Vertex *vet1, Vertex *vet2) {
if (!adjList.count(vet1) || !adjList.count(vet2) || vet1 == vet2)
throw invalid_argument("Vertex does not exist");
// Remove edge vet1 - vet2
remove(adjList[vet1], vet2);
remove(adjList[vet2], vet1);
}
/* Add vertex */
void addVertex(Vertex *vet) {
if (adjList.count(vet))
return;
// Add a new linked list to the adjacency list
adjList[vet] = vector<Vertex *>();
}
/* Remove vertex */
void removeVertex(Vertex *vet) {
if (!adjList.count(vet))
throw invalid_argument("Vertex does not exist");
// Remove the vertex vet's corresponding linked list from the adjacency list
adjList.erase(vet);
// Traverse other vertices' linked lists, removing all edges containing vet
for (auto &adj : adjList) {
remove(adj.second, vet);
}
}
/* Print the adjacency list */
void print() {
cout << "Adjacency list =" << endl;
for (auto &adj : adjList) {
const auto &key = adj.first;
const auto &vec = adj.second;
cout << key->val << ": ";
printVector(vetsToVals(vec));
}
}
};
8 months ago
```
=== "Java"
```java title="graph_adjacency_list.java"
7 months ago
/* Undirected graph class based on adjacency list */
8 months ago
class GraphAdjList {
7 months ago
// Adjacency list, key: vertex, value: all adjacent vertices of that vertex
8 months ago
Map<Vertex, List<Vertex>> adjList;
7 months ago
/* Constructor */
8 months ago
public GraphAdjList(Vertex[][] edges) {
this.adjList = new HashMap<>();
7 months ago
// Add all vertices and edges
8 months ago
for (Vertex[] edge : edges) {
addVertex(edge[0]);
addVertex(edge[1]);
addEdge(edge[0], edge[1]);
}
}
7 months ago
/* Get the number of vertices */
8 months ago
public int size() {
return adjList.size();
}
7 months ago
/* Add edge */
8 months ago
public void addEdge(Vertex vet1, Vertex vet2) {
if (!adjList.containsKey(vet1) || !adjList.containsKey(vet2) || vet1 == vet2)
throw new IllegalArgumentException();
7 months ago
// Add edge vet1 - vet2
8 months ago
adjList.get(vet1).add(vet2);
adjList.get(vet2).add(vet1);
}
7 months ago
/* Remove edge */
8 months ago
public void removeEdge(Vertex vet1, Vertex vet2) {
if (!adjList.containsKey(vet1) || !adjList.containsKey(vet2) || vet1 == vet2)
throw new IllegalArgumentException();
7 months ago
// Remove edge vet1 - vet2
8 months ago
adjList.get(vet1).remove(vet2);
adjList.get(vet2).remove(vet1);
}
7 months ago
/* Add vertex */
8 months ago
public void addVertex(Vertex vet) {
if (adjList.containsKey(vet))
return;
7 months ago
// Add a new linked list to the adjacency list
8 months ago
adjList.put(vet, new ArrayList<>());
}
7 months ago
/* Remove vertex */
8 months ago
public void removeVertex(Vertex vet) {
if (!adjList.containsKey(vet))
throw new IllegalArgumentException();
7 months ago
// Remove the vertex vet's corresponding linked list from the adjacency list
8 months ago
adjList.remove(vet);
7 months ago
// Traverse other vertices' linked lists, removing all edges containing vet
8 months ago
for (List<Vertex> list : adjList.values()) {
list.remove(vet);
}
}
7 months ago
/* Print the adjacency list */
8 months ago
public void print() {
7 months ago
System.out.println("Adjacency list =");
8 months ago
for (Map.Entry<Vertex, List<Vertex>> pair : adjList.entrySet()) {
List<Integer> tmp = new ArrayList<>();
for (Vertex vertex : pair.getValue())
tmp.add(vertex.val);
System.out.println(pair.getKey().val + ": " + tmp + ",");
}
}
}
```
=== "C#"
```csharp title="graph_adjacency_list.cs"
7 months ago
[class]{GraphAdjList}-[func]{}
8 months ago
```
=== "Go"
```go title="graph_adjacency_list.go"
7 months ago
[class]{graphAdjList}-[func]{}
8 months ago
```
=== "Swift"
```swift title="graph_adjacency_list.swift"
7 months ago
[class]{GraphAdjList}-[func]{}
8 months ago
```
=== "JS"
```javascript title="graph_adjacency_list.js"
7 months ago
[class]{GraphAdjList}-[func]{}
8 months ago
```
=== "TS"
```typescript title="graph_adjacency_list.ts"
7 months ago
[class]{GraphAdjList}-[func]{}
8 months ago
```
=== "Dart"
```dart title="graph_adjacency_list.dart"
7 months ago
[class]{GraphAdjList}-[func]{}
8 months ago
```
=== "Rust"
```rust title="graph_adjacency_list.rs"
7 months ago
[class]{GraphAdjList}-[func]{}
8 months ago
```
=== "C"
```c title="graph_adjacency_list.c"
7 months ago
[class]{AdjListNode}-[func]{}
8 months ago
7 months ago
[class]{GraphAdjList}-[func]{}
8 months ago
```
=== "Kotlin"
```kotlin title="graph_adjacency_list.kt"
7 months ago
[class]{GraphAdjList}-[func]{}
8 months ago
```
=== "Ruby"
```ruby title="graph_adjacency_list.rb"
7 months ago
[class]{GraphAdjList}-[func]{}
8 months ago
```
=== "Zig"
```zig title="graph_adjacency_list.zig"
[class]{GraphAdjList}-[func]{}
```
## 9.2.3 &nbsp; Efficiency comparison
7 months ago
Assuming there are $n$ vertices and $m$ edges in the graph, Table 9-2 compares the time efficiency and space efficiency of the adjacency matrix and adjacency list.
8 months ago
<p align="center"> Table 9-2 &nbsp; Comparison of adjacency matrix and adjacency list </p>
<div class="center-table" markdown>
| | Adjacency matrix | Adjacency list (Linked list) | Adjacency list (Hash table) |
| ------------------- | ---------------- | ---------------------------- | --------------------------- |
| Determine adjacency | $O(1)$ | $O(m)$ | $O(1)$ |
| Add an edge | $O(1)$ | $O(1)$ | $O(1)$ |
| Remove an edge | $O(1)$ | $O(m)$ | $O(1)$ |
| Add a vertex | $O(n)$ | $O(1)$ | $O(1)$ |
| Remove a vertex | $O(n^2)$ | $O(n + m)$ | $O(n)$ |
| Memory space usage | $O(n^2)$ | $O(n + m)$ | $O(n + m)$ |
</div>
7 months ago
Observing Table 9-2, it seems that the adjacency list (hash table) has the best time efficiency and space efficiency. However, in practice, operating on edges in the adjacency matrix is more efficient, requiring only a single array access or assignment operation. Overall, the adjacency matrix exemplifies the principle of "space for time", while the adjacency list exemplifies "time for space".