Sắp Xếp Tôpô


đã đăng vào 1 tháng 4 năm 2025, 12:11 a.m.

🧮 Cheatsheet: Sắp Xếp Tôpô (Topological Sort)

📘 Giới thiệu

Sắp xếp tôpô (topological sort) là một kỹ thuật duyệt đồ thị có hướng (DAG) sao cho nếu tồn tại cạnh từ u → v thì u sẽ xuất hiện trước v trong thứ tự sắp xếp.


🧠 Ứng dụng

  • Sắp xếp thứ tự thực hiện công việc có phụ thuộc.
  • Lập lịch bài học, xây dựng module hệ thống.
  • Phân tích biểu thức, trình biên dịch.
  • Bài toán kiểm tra chu trình trong đồ thị có hướng.

🔁 Code C++ (BFS - Kahn’s Algorithm)

#include <bits/stdc++.h>
using namespace std;

vector<int> topo_sort(int n, vector<vector<int>>& adj) {
    vector<int> in_degree(n + 1, 0);
    for (int u = 1; u <= n; ++u)
        for (int v : adj[u])
            in_degree[v]++;

    queue<int> q;
    for (int i = 1; i <= n; ++i)
        if (in_degree[i] == 0)
            q.push(i);

    vector<int> topo;
    while (!q.empty()) {
        int u = q.front(); q.pop();
        topo.push_back(u);
        for (int v : adj[u]) {
            if (--in_degree[v] == 0)
                q.push(v);
        }
    }

    if (topo.size() < n)
        throw runtime_error("Graph has a cycle");

    return topo;
}

🔁 Code C++ (DFS)

void dfs(int u, vector<vector<int>>& adj, vector<bool>& visited, stack<int>& st) {
    visited[u] = true;
    for (int v : adj[u])
        if (!visited[v])
            dfs(v, adj, visited, st);
    st.push(u);
}

vector<int> topo_sort_dfs(int n, vector<vector<int>>& adj) {
    vector<bool> visited(n + 1, false);
    stack<int> st;
    for (int i = 1; i <= n; ++i)
        if (!visited[i])
            dfs(i, adj, visited, st);

    vector<int> topo;
    while (!st.empty()) {
        topo.push_back(st.top());
        st.pop();
    }
    return topo;
}

📊 So sánh BFS và DFS

Tiêu chí BFS (Kahn's) DFS-Based
Phát hiện chu trình Có (qua số lượng đỉnh) Không trực tiếp
Dễ debug
Dễ cài đặt
Hiệu suất Ngang nhau Ngang nhau

⏱️ Độ phức tạp

  • Thời gian: O(V + E)
  • Không gian: O(V + E)

✅ Ưu điểm

  • Hiệu quả với đồ thị DAG.
  • Cài đặt đơn giản.
  • Có thể dùng phát hiện chu trình (Kahn’s Algorithm).

❌ Nhược điểm

  • Chỉ dùng được với đồ thị có hướng không chu trình (DAG).
  • Với đồ thị có chu trình sẽ không tồn tại thứ tự topo.

🔧 Tối ưu

  • Dùng priority_queue thay vì queue để tìm topo theo thứ tự từ điển nhỏ nhất.
  • Gộp visited + in_degree thành 1 mảng nếu tiết kiệm bộ nhớ.

🤔 Khi nào dùng?

Tình huống Có nên dùng?
Đồ thị có hướng, không chu trình (DAG)
Bài toán lập lịch, sắp xếp có phụ thuộc
Đồ thị có chu trình ❌ (không áp dụng)
Tìm chu trình trong đồ thị Dùng biến thể của Kahn ✅

📚 Tham khảo


Nhận xét

Không có ý kiến tại thời điểm này.