基础算法实现(C++)

464 阅读14分钟

排序算法

基础排序

选择排序

template<typename T>
void selectionSort(T arr[], int n) {
    int minIndex = 0;
    for (int i = 0; i < n - 1; ++i) {
       // 寻找[i, n)区间里的最小值
        minIndex = i;
        for (int j = i + 1; j < n; ++j)
            if (arr[j] < arr[minIndex]) minIndex = j;
        swap(arr[i], arr[minIndex]);
    }
}

插入排序

template<typename T>
void insertionSort(T arr[], int n) {
    for (int i = 1; i < n; ++i) {
        T e = arr[i];
        int j; // j保存e应该插入的位置
        for (j = i; j >= 1 && arr[j - 1] > e; --j)
            arr[j] = arr[j - 1];
        arr[j] = e;
    }
}

插入排序(2)

template<typename T>
void insertionSort(T arr[], int l, int r) {
    for (int i = l + 1; i <= r; ++i) {
        T e = arr[i];
        int j; // j保存e应该插入的位置
        for (j = i; j > l && arr[j - 1] > e; --j)
            arr[j] = arr[j - 1];
        arr[j] = e;
    }
}

冒泡排序

template<typename T>
void bubbleSort(T arr[], int n) {
    for (int i = 0; i < n - 1; i++)
        for (int j = 0; j < n - 1 - i; j++)
            if (arr[j] > arr[j + 1])
                swap(arr[j], arr[j + 1]);
}

冒泡排序(2)

template<typename T>
void bubbleSort2(T arr[], int n) {
    bool swapped;
    do {
        swapped = false;
        for (int i = 1; i < n; i++)
            if (arr[i - 1 ] > arr[i]) {
                swap(arr[i - 1], arr[i]);
                swapped = true;
            }
        n--;
    } while (swapped);
}

希尔排序

template<typename T>
void shellSort(T arr[], int n) {
    int h = 1;
    while (h < n / 3)
        h = 3 * h + 1;
    // 计算increment sequence:1,4,13,40,121,364,1093...
    while (h >= 1) {
        // h-sort the array
        for (int i = h; i < n; i++) {
            // 对arr[i],arr[i-h],arr[i-2*h],arr[i-3*h]...使用插入排序
            T e = arr[i];
            int j;
            for (j = i; j >= h && e < arr[j - h]; j -= h)
                arr[j] = arr[j - h];
            arr[j] = e;
        }
        h /= 3;
    }
}

高级排序

归并排序

template<typename T>
void mergeSort(T arr[], int n) {
    __mergeSort(arr, 0, n - 1);
}

// [l...r]
template<typename T>
void __mergeSort(T arr[], int l, int r) {
    if (l >= r) return;
    /*
    if (r - l <= 15) {
        insertionSort(arr, l, r);
        return;
    }
    */
    int mid = l + (r - l) / 2;
    __mergeSort(arr, l, mid);
    __mergeSort(arr, mid + 1, r);
    if (arr[mid] > arr[mid + 1])
        __merge(arr, l, mid, r);
}

// 将arr[l...mid]和arr[mid+1...r]两部分归并
template<typename T>
void __merge(T arr[], int l, int mid, int r) {
    T aux[r - l + 1];
    for (int i = l; i <= r; ++i)
        aux[i - l] = arr[i];
    int i = l, j = mid + 1;
    for (int k = l; k <= r; ++k) {
        if (i > mid) {
            arr[k] = aux[j - l];
            j++;
        } else if (j > r) {
            arr[k] = aux[i - l];
            i++;
        } else if (aux[i - l] < aux[j - l]) {
            arr[k] = aux[i - l];
            i++;
        } else {
            arr[k] = aux[j - l];
            j++;
        }
    }
}

归并排序(2)——自底向上

template<typename T>
void mergeSortBU(T arr[], int n) {
    for (int sz = 1; sz <= n; sz += sz)
        for (int i = 0; i + sz < n; i += sz + sz)
            // 对 arr[i...i+sz-1] 和 arr[i+sz...i+2*sz-1] 进行归并
            __merge(arr, i, i+sz-1, min(i+sz+sz-1, n-1));
}

快速排序—-单路快排

template<typename T>
void quickSort(T arr[], int n) {
    srand((unsigned int) time(NULL));
    __quickSort(arr, 0, n - 1);
}

template<typename T>
void __quickSort(T arr[], int l, int r) {
//    if (l >= r)return;
    if (r - l <= 15) { // <=16个元素时使用插入排序
        insertionSort(arr, l, r);
        return;
    }
    int p = __partition(arr, l, r);
    __quickSort(arr, l, p - 1);
    __quickSort(arr, p + 1, r);
}

// [l...r]
// 返回p,使得arr[l...p-1] < arr[p] ; arr[p+1...r] > arr[p]
template<typename T>
int __partition(T arr[], int l, int r) {
    swap(arr[l], arr[rand() % (r - l + 1) + l]); // 防止数组近乎有序
    T v = arr[l];

    // arr[l+1...j] < v ; arr[j+1...i) > v
    int j = l;
    for (int i = l + 1; i <= r; ++i) {
        if (arr[i] < v) {
            swap(arr[j + 1], arr[i]);
            j++;
        }
    }
    swap(arr[l], arr[j]);
    return j;
}

快速排序—-双路快排

template<typename T>
void quickSort2Ways(T arr[], int n) {
    srand((unsigned int) time(NULL));
    __quickSort2Ways(arr, 0, n - 1);
}

template<typename T>
void __quickSort2Ways(T arr[], int l, int r) {
//    if (l >= r)return;
    if (r - l <= 15) {
        insertionSort(arr, l, r);
        return;
    }
    int p = __partition2Ways(arr, l, r);
    __quickSort2Ways(arr, l, p - 1);
    __quickSort2Ways(arr, p + 1, r);
}

// [l...r]
// 返回p,使得arr[l...p-1] < arr[p] ; arr[p+1...r] > arr[p]
template<typename T>
int __partition2Ways(T arr[], int l, int r) {
    swap(arr[l], arr[rand() % (r - l + 1) + l]); // 防止数组近乎有序
    T v = arr[l];

    // 对有大量重复元素的情况进行优化
    // arr[l+1…i) <= v; arr(j…r] >= v
    int i = l + 1, j = r;
    while (true) {
        while (i <= r && arr[i] < v) i++;
        while (j >= l + 1 && arr[j] > v) j--;
        if (i > j) break;
        swap(arr[i], arr[j]);
        i++;
        j--;
    }
    swap(arr[l], arr[j]);
    return j;
}

快速排序—-三路快排

template<typename T>
void quickSort3Ways(T arr[], int n) {
    srand((unsigned int) time(NULL));
    __quickSort3Ways(arr, 0, n - 1);
}

template<typename T>
void __quickSort3Ways(T arr[], int l, int r) {
//    if (l >= r)return;
    if (r - l <= 15) {
        insertionSort(arr, l, r);
        return;
    }

    // partition
    swap(arr[l], arr[rand() % (r - l + 1) + l]);
    T v = arr[l];
    int lt = l; // arr[l+1...lt] < v
    int gt = r + 1; // arr[gt...r] > v
    int i = l + 1; // arr[lt+1...i) == v
    while (i < gt)
        if (arr[i] < v) {
            swap(arr[i], arr[lt + 1]);
            lt++;
            i++;
        } else if (arr[i] > v) {
            swap(arr[i], arr[gt - 1]);
            gt--;
        } else // arr[i] == v
            i++;

    swap(arr[l], arr[lt]);

    __quickSort3Ways(arr, l, lt - 1);
    __quickSort3Ways(arr, gt, r);
}

计数排序

void countingSort(int arr[], int ret[], int n, int upperBound) {
    int len = upperBound + 1;
    int *C = new int[len];

    for (int i = 0; i < len; ++i)
        C[i] = 0;

    for (int i = 0; i < n; ++i)
        C[arr[i]]++;

    for (int i = 1; i < len; ++i)
        C[i] += C[i - 1];

    for (int i = n - 1; i >= 0; --i) {
        ret[C[arr[i]] - 1] = arr[i];
        C[arr[i]]--;
    }
    delete[] C;
}

堆排序(1)

// 堆的类定义
template<typename Item>
class MaxHeap {
private:
    Item *data;
    int count;
    int capacity;
    void siftUp(int k) {
        while (k > 1 && data[k / 2] < data[k]) {
            swap(data[k / 2], data[k]);
            k /= 2;
        }
    }
    void siftDown(int k) {
        while (2 * k <= count) {
            int j = 2 * k; // 在此轮循环中,data[k]和data[j]交换位置
            if (j + 1 <= count && data[j + 1] > data[j])
                j += 1;
            if (data[k] >= data[j]) break;
            swap(data[k], data[j]);
            k = j;
        }
    }
public:
    MaxHeap(int capacity) { 
        data = new Item[capacity + 1];
        count = 0;
        this->capacity = capacity;
    }
    MaxHeap(Item arr[], int n) {
        data = new Item[n + 1];
        capacity = n;
        copy(arr, arr + n, data + 1);
        count = n;
        for (int i = count / 2; i >= 1; --i) siftDown(i);
    }
    int size() { return count; }
    bool empty() { return count == 0; }
    void insert(Item item) {
        assert(count + 1 <= capacity);
        data[++count] = item;
        siftUp(count);
    }
    Item extractMax() {
        assert(count > 0);
        Item ret = data[1];
        swap(data[1], data[count--]);
        siftDown(1);
        return ret;
    }
    ~MaxHeap() { delete[] data; }
};
template<typename T>
void heapSort(T arr[], int n) {
    MaxHeap<T> maxHeap = MaxHeap<int>(arr, n);
//    for (int i = 0; i < n; ++i)
//        maxHeap.insert(arr[i]);
    for (int i = n - 1; i >= 0; --i)
        arr[i] = maxHeap.extractMax();
}

堆排序(2)—-原地堆排序

template<typename T>
void heapSort(T arr[], int n) {
    // heapify
    for (int i = (n - 1) / 2; i >= 0; --i)
        __siftDown(arr, n, i);
    for (int i = n - 1; i > 0; --i) {
        swap(arr[0], arr[i]);
        __siftDown(arr, i, 0);
    }
}

template<typename T>
void __siftDown(T arr[], int n, int k) {
    while (2 * k + 1 < n) {
        int j = 2 * k + 1;
        if (j + 1 < n && arr[j + 1] > arr[j])
            j += 1;
        if (arr[k] >= arr[j])break;
        swap(arr[k], arr[j]);
        k = j;
    }
}

二叉树遍历

// 二叉树节点
struct TreeNode {
    int val;
    TreeNode *left;
    TreeNode *right;
    TreeNode(int x) : val(x), left(NULL), right(NULL) {}
};

层序遍历

void levelOrderTraversal(TreeNode *root) {
    if (root == NULL)
        return;
    TreeNode *p = root;
    queue<TreeNode *> queue;
    queue.push(p);
    while (!queue.empty()) {
        p = queue.front();
        cout << p->val << endl;
        queue.pop();
        if (p->left)
            queue.push(p->left);
        if (p->right)
            queue.push(p->right);
    }
}

前序遍历(1)—-递归

void preorderTraversal(TreeNode *root) {
    if (root) {
        cout << root->val << endl;
        preorderTraversal(root->left);
        preorderTraversal(root->right);
    }
}

前序遍历(2)—-非递归经典

void preorderTraversal(TreeNode *root) {
    if (root == NULL)
        return;
    TreeNode *p = root;
    stack<TreeNode *> stack;
    while (p || !stack.empty()) {
        if (p) {
            stack.push(p);
            cout << p->val << endl;
            p = p->left;
        } else {
            p = stack.top();
            stack.pop();
            p = p->right;
        }
    }
}

中序遍历(1)—-递归

void inorderTraversal(TreeNode *root) {
    if (root) {
        inorderTraversal(root->left);
        cout << root->val << endl;
        inorderTraversal(root->right);
    }
}

中序遍历(2)—-非递归经典

void inorderTraversal(TreeNode *root) {
    if (root == NULL) 
        return;
    stack<TreeNode *> stack;
    TreeNode *p = root;
    while (p || !stack.empty()) {
        if (p) {
            stack.push(p);
            p = p->left;
        } else {
            p = stack.top();
            stack.pop();
            cout << p->val << endl;
            p = p->right;
        }
    }
}

后序遍历(1)—-递归

void postorderTraversal(TreeNode *root) {
    if (root) {
        inorderTraversal(root->left);
        inorderTraversal(root->right);
        cout << root->val << endl;
    }
}

后序遍历(2)—-非递归经典

void postorderTraversal(TreeNode *root) {
    if (root == NULL)
        return;
    stack<TreeNode *> stack;
    TreeNode *p = root;
    TreeNode *r = NULL;
    while (p || !stack.empty()) {
        if (p) {
            stack.push(p);
            p = p->left;
        } else {
            p = stack.top();
            if (p->right && p->right != r) {
                p = p->right;
                stack.push(p);
                p = p->left;
            } else {
                stack.pop();
                cout << p->val << endl;
                r = p;
                p = NULL;
            }
        }
    }
}

二分查找法

template<typename T>
int binarySearch(T arr[], int n, T target) {
    int l = 0, r = n - 1;

    // 在arr[l...r]中查找target
    while (l <= r) {
        int mid = l + (r - l) / 2; // int mid = (l + r) / 2;
        if (target == arr[mid])
            return mid;
        else if (target > arr[mid])
            l = mid + 1;
        else
            r = mid - 1;
    }
    return -1;
}

二分查找法(2)—-递归

template<typename T>
int binarySearch2(T arr[], int n, T target) {
    return __search(arr, 0, n - 1, target);
}

template<typename T>
int __search(T arr[], int l, int r, T target) {
    if (l > r) return -1;
    int mid = (l + r) / 2;
    if (arr[mid] == target)
        return mid;
    else if (target > arr[mid])
        return __search(arr, mid + 1, r, target);
    else
        return __search(arr, l, mid - 1, target);
}

二分搜索树

搜索

TreeNode *searchBST(TreeNode *root, int val) {
    if (root == NULL)
        return NULL;
    if (val > root->val)
        return searchBST(root->right, val);
    else if (val < root->val)
        return searchBST(root->left, val);
    return root;
}

### 查找最小节点

```cpp
TreeNode *minimum(TreeNode *node) {
    if (node == NULL)
        return NULL;
    if (!node->left)
        return node;
    return minimum(node->left);
}

最近公共祖先

TreeNode *lowestCommonAncestor(TreeNode *root, TreeNode *p,
                               TreeNode *q) {
    if (root == NULL)
        return NULL;
    if (p->val > root->val && q->val > root->val)
        return lowestCommonAncestor(root->right, p, q);
    if (p->val < root->val && q->val < root->val)
        return lowestCommonAncestor(root->left, p, q);
    return root;
}

插入

TreeNode *insertIntoBST(TreeNode *root, int val) {
    if (root == NULL)
        return new TreeNode(val);
    if (val > root->val)
        root->right = insertIntoBST(root->right, val);
    else if (val < root->val)
        root->left = insertIntoBST(root->left, val);
    return root;
}

删除最小节点

TreeNode *deleteMinNode(TreeNode *root) {
    if (root == NULL)
        return NULL;
    if (root->left == NULL) {
        TreeNode *delNode = root;
        root = root->right;
        delete delNode;
    } else
        root->left = deleteMinNode(root->left);
    return root;
}

删除任意节点

TreeNode *deleteNode(TreeNode *root, int key) {
    if (root == NULL)
        return NULL;
    if (key > root->val)
        root->right = deleteNode(root->right, key);
    else if (key < root->val)
        root->left = deleteNode(root->left, key);
    else {
        if (root->left && root->right) {
            TreeNode *minNode = minimum(root->right);
            root->val = minNode->val;
            root->right = deleteNode(root->right, root->val);
        } else {s
            TreeNode *delNode = root;
            if (!root->left)
                root = root->right;
            else
                root = root->left;
            delete delNode;
        }
    }
    return root;
}

并查集

class UnionFind {
private:
    int *parent;
    int *rank; // rank[i]表示以i为根的集合所表示的树的层数
    int count;
public:
    UnionFind(int count) {
        parent = new int[count];
        rank = new int[count];
        this->count = count;
        for (int i = 0; i < count; ++i) {
            parent[i] = i;
            rank[i] = 1;
        }
    }
    int find(int p) {
        assert(p >= 0 && p < count);
        // 路径压缩方法1
        while (p != parent[p]) {
            parent[p] = parent[parent[p]];
            p = parent[p];
        }
        return p;
        /**
         * 路径压缩方法2 (实际情况并不理想,递归需要成本)
         * if (p != parent[p])
         *    parent[p] = find(parent[p]);
         * return parent[p];
         */
    }
    bool isConnected(int p, int q) { return find(p) == find(q); }
    void unionElements(int p, int q) {
        int pRoot = find(p);
        int qRoot = find(q);
        if (pRoot == qRoot) return;
        if (rank[pRoot] < rank[qRoot]) parent[pRoot] = qRoot;
        else if (rank[qRoot] < rank[pRoot]) parent[qRoot] = pRoot;
        else {
            parent[pRoot] = qRoot;
            rank[qRoot] += 1;
        }
    }
    ~UnionFind() {
        delete[] parent;
        delete[] rank;
    }
};

const int MAX_N = 100;
int G[MAX_N][MAX_N];
bool visited[MAX_N];

深度优先搜索

void dfs() {
    fill(visited, visited + MAX_N, false);
    for (int u = 0; u < n; u++)
        if (!visited[u])
            dfs_visit(u); // 此处 dfs_visit 执行的次数为连通分量的数量
}

深度优先搜索(递归实现)

void dfs_visit(int u) {
    visited[u] = true;
    cout << u << " ";
    for (int v = 0; v < n; v++)
        if (G[u][v] && !visited[v])
            dfs_visit(v);
} // 0 1 3 2 

深度优先搜索(栈实现 1)

void dfs_visit(int u) {
    stack<int> S;
    S.push(u);
    visited[u] = true;
    while (!S.empty()) {
        u = S.top();
        cout << u << " ";
        // 查找是否存在相邻且未被访问过的顶点v
        int v;
        for (v = 0; v < n; ++v)
            if (G[u][v] && !visited[v])
                break;
        if (v < n) { // 存在
            S.push(v);
            visited[v] = true;
        } else // 不存在
            S.pop();
    }
} // 0 1 3 2 3 1 0 

深度优先搜索(栈实现 2)

void dfs_visit(int u) {
    stack<int> S;
    S.push(u);
    visited[u] = true;
    while (!S.empty()) {
        u = S.top();
        S.pop();
        cout << u << " ";
        for (int v = 0; v < n; ++v) {
            if (G[u][v] && !visited[v]) {
                S.push(v);
                visited[v] = true;
            }
        }
    }
} // 0 1 3 2 

广度优先搜索

void bfs() {
    fill(visited, visited + n, false);
    for (int u = 0; u < n; u++)
        if (!visited[u])
            bfs_visit(u); // 此处 bfs_visit 执行的次数为连通分量的数量
}

void bfs_visit(int u) {
    queue<int> q;
    q.push(u);
    visited[u] = true;
    cout << u << " ";
    while (!q.empty()) {
        u = q.front();
        q.pop();
        for (int v = 0; v < n; v++)
            if (G[u][v] && !visited[v]) {
                q.push(v);
                visited[v] = true;
                cout << v << " ";
            }
    }
} // 0 1 3 2 

最小生成树(Prim 算法)

int prim() {
    bool intree[MAX_N];
    int dist[MAX_N];
    int parent[MAX_N];
    fill(intree, intree + n, false);
    fill(dist, dist + n, INFINITY);
    fill(parent, parent + n, -1);

    dist[0] = 0;
    while (true) {
        /*
         * 找到距离这棵最小生成树最近的节点 u
         */
        int minv = INFINITY;
        int u = -1;
        for (int v = 0; v < n; v++)
            if (!intree[v] && dist[v] < minv) {
                minv = dist[v];
                u = v;
            }

        if (u == -1) break;
        /*
         * 将找到的节点 u 加入最小生成树
         */
        intree[u] = true;

        /*
         * 因为 u 节点的加入,使得某些点(与 u 相邻的点)跟最小生成树的
         * 最小距离改变了,所以需要修正它们,并记录他们的父节点
         */
        for (int v = 0; v < n; v++)
            if (!intree[v] && G[u][v] != INFINITY)
                if (G[u][v] < dist[v]) {
                    dist[v] = G[u][v];
                    parent[v] = u;
                }
    }

    int sum = 0;
    for (int v = 0; v < n; v++)
        if (parent[v] != -1)
            sum += G[v][parent[v]];
    // 返回最小生成树各边权值之和
    return sum;
}

最小生成树(Kruskal 算法)

typedef struct Edge {
    int s, t, w;

    Edge(int s, int t, int w) : s(s), t(t), w(w) {}

    bool operator>(const Edge &other) const {
        return w > other.w;
    }
} Edge;

struct cmp {
    bool operator()(const Edge &e1, const Edge &e2) {
        return e1.w > e2.w;
    }
};

class UnionFind {
    // 并查集实现
    ……
public:
    void unite(int p, int q);

    bool connected(int p, int q);
};

int kruskal(int n, vector<Edge> &edges) {
    // 优先级队列(最小堆)
     //或priority_queue<Edge,vector<Edge>,greater<Edge>>pq(edges.begin(),edges.end());
    priority_queue<Edge, vector<Edge>, cmp> pq(edges.begin(),
                                               edges.end());
    UnionFind uf(n); // 并查集
    int sum = 0;
    while (!pq.empty()) {
        Edge edge = pq.top();
        pq.pop();
        int s = edge.s;
        int t = edge.t;
        int w = edge.w;
        if (!uf.connected(s, t)) {
            sum += w;
            uf.unite(s, t);
        }
    }
    // 返回最小生成树的各边权值之和
    return sum;
}

无权图单源最短路径(广度优先搜索)

void shortest(int s) {
    fill(dist, dist + n, -1);

    queue<int> queue;
    queue.push(s);
    dist[s] = 0;
    while (!queue.empty()) {
        int u = queue.front();
        queue.pop();
        for (int v = 0; v < n; ++v) {
            if (dist[v] == -1 && G[u][v] != INFTY) {
                dist[v] = dist[u] + 1;
                parent[v] = u;
                queue.push(v);
            }
        }
    }
}

有权图单源最短路径(Dijkstra 算法)

void dijkstra() {
    bool intree[MAX_N];
    int dist[MAX_N];
    int parent[MAX_N];
    fill(intree, intree + n, false);
    fill(dist, dist + n, INFINITY);
    fill(parent, parent + n, -1);

    dist[0] = 0;
    while (true) {
        /*
         * 找到距离这颗最小生成树最近的节点 u
         */
        int minv = INFINITY;
        int u = -1;
        for (int v = 0; v < n; v++)
            if (!intree[v] && dist[v] < minv) {
                minv = dist[v];
                u = v;
            }

        if (u == -1) break;
        /*
         * 将找到的节点 u 加入最小生成树
         */
        intree[u] = true;

        /*
         * 因为 u 节点的加入,使得某些点(与 u 相邻的点)跟最短路径生成树的
         * 最小距离改变了,所以需要修正它们,并记录他们的父节点
         */
        for (int v = 0; v < n; v++)
            if (!intree[v] && G[u][v] != INFINITY)
                if (dist[u] + G[u][v] < dist[v]) {
                    dist[v] = dist[u] + G[u][v];
                    parent[v] = u;
                }
    }

    // 输出 0 到其他节点的最短路径距离
    for (int v = 0; v < n; v++)
        cout << v << " " << (dist[v] == INFINITY ? -1 : dist[v]) 
											<< endl;
}

有权图单源最短路径(Dijkstra 算法—-堆优化)

vector<pair<int, int> > G[MAX_N]; // pair<v, c>
void dijkstra() {
    // pair<dist, v>
    priority_queue<pair<int, int>, vector<pair<int, int> >, 
						      greater<pair<int, int> > > pq;

    bool intree[MAX_N];
    int dist[MAX_N];
    int parent[MAX_N];
    fill(intree, intree + n, false);
    fill(dist, dist + n, INFINITY);
    fill(parent, parent + n, -1);
    dist[0] = 0;
    pq.push(make_pair(0, 0));
    while (!pq.empty()) {
        /*
         * 找到距离这棵最小生成树最近的节点 u
         */
        pair<int, int> f = pq.top();
        pq.pop();
        int u = f.second;

        // 将找到的节点 u 加入最小生成树
        intree[u] = true;

        /*
         * 取出最小值,(由于同一个节点可能被添加多次)如果不是最短路径则忽略
         */
        if (dist[u] < f.first) continue;

        /*
         * 因为 u 节点的加入,使得某些点(与 u 相邻的点)跟最短路径生成树的
         * 最小距离改变了,所以需要修正它们,并记录他们的父节点
         */
        for (int i = 0; i < G[u].size(); ++i) {
            int v = G[u][i].first;
            if (!intree[v] && dist[u] + G[u][i].second < dist[v]){
                dist[v] = dist[u] + G[u][i].second;
                // 同一个节点可能被多次添加至 pq 中
                pq.push(make_pair(dist[v], v));
                parent[v] = u;
            }
        }
    }

    for (int v = 0; v < n; v++)
        cout << v << " " << (dist[v] == INFINITY ? -1 : dist[v]) 
											   << endl;
}

有权图多源最短路径(Floyd-Warshall 算法)

/*
 * dist[i][j] 初始化为G[i][j],若节点i和j不相邻,则为INFTY(i != j)
 * dist[i][i] 初始化为 0。
 */
void floyd() {
    for (int k = 0; k < n; k++) { // k 为中转节点
        for (int i = 0; i < n; i++) {
            if (d[i][k] == INFTY) continue;
            for (int j = 0; j < n; j++) {
                if (d[k][j] == INFTY) continue;
                d[i][j] = min(d[i][j], d[i][k] + d[k][j]);
            }
        }
    }
} // 最终如果d[i][i] < 0,则说明图中存在负环

拓扑排序(广度优先搜索实现)

void bfs(int u) {
    queue<int> q;
    q.push(u);
    visited[u] = true;
    while (!q.empty()) {
        u = q.front();
        q.pop();
        cout << u << endl;
        for (int i = 0; i < G[u].size(); ++i) {
            int v = G[u][i];
            indeg[v] -= 1;
            if (!visited[v] && indeg[v] == 0) {
                q.push(v);
                visited[v] = true;
            }
        }
    }
}

void top_sort() {
    fill(indeg, indeg + n, 0);
    fill(visited, visited + n, false);
    for (int u = 0; u < n; ++u)
        for (int i = 0; i < G[u].size(); ++i) {
            int v = G[u][i];
            indeg[v]++;
        }
    for (int u = 0; u < n; u++)
        if (!visited[u] && indeg[u] == 0)
            bfs(u);
}

拓扑排序(深度优先搜索实现)

void dfs(int u) {
    visited[u] = true;
    for (int i = 0; i < G[u].size(); ++i) {
        int v = G[u][i];
        if (!visited[v])
            dfs(v);
    }
    /*
     * res : list<int> res;
     * 深度优先搜索是逆向确定各顶点的拓扑顺序
     * 因此顶点是添加至链表"开头"的
     */
    res.push_front(u);
}

void top_sort() {
    fill(visited, visited + n, false);
    for (int u = 0; u < n; u++)
        if (!visited[u])
            dfs(u);
    for (int u : res)
        cout << u << endl;
}