你知道的C++经典算法有哪些

C++作为一门功能强大且广泛应用的编程语言,其在算法领域的应用十分广泛。掌握一些经典的算法不仅能够提高程序的效率,还能增强解决复杂问题的能力。本文将介绍一些在C++中广泛应用的经典算法,包括排序算法、搜索算法、图算法、动态规划等。

1. 排序算法

1.1 快速排序(Quick Sort)

快速排序是一种基于分治思想的排序算法,其基本思想是通过一个基准元素将数组分为两部分,使得一部分元素小于基准元素,另一部分元素大于基准元素,然后递归地对两部分分别进行快速排序。其平均时间复杂度为O(n log n)。

#include <iostream>
#include <vector>

int partition(std::vector<int>& arr, int low, int high) {
    int pivot = arr[high];
    int i = low - 1;

    for (int j = low; j < high; ++j) {
        if (arr[j] < pivot) {
            ++i;
            std::swap(arr[i], arr[j]);
        }
    }
    std::swap(arr[i + 1], arr[high]);
    return i + 1;
}

void quickSort(std::vector<int>& arr, int low, int high) {
    if (low < high) {
        int pi = partition(arr, low, high);
        quickSort(arr, low, pi - 1);
        quickSort(arr, pi + 1, high);
    }
}

int main() {
    std::vector<int> arr = {10, 7, 8, 9, 1, 5};
    quickSort(arr, 0, arr.size() - 1);
    for (int i : arr) {
        std::cout << i << " ";
    }
    return 0;
}

1.2 归并排序(Merge Sort)

归并排序同样是一种分治算法,其基本思想是将数组递归地分成两半,分别进行排序,然后再将两个有序的数组合并成一个有序数组。归并排序的时间复杂度为O(n log n),但其空间复杂度较高。

#include <iostream>
#include <vector>

void merge(std::vector<int>& arr, int l, int m, int r) {
    int n1 = m - l + 1;
    int n2 = r - m;

    std::vector<int> L(n1), R(n2);

    for (int i = 0; i < n1; ++i)
        L[i] = arr[l + i];
    for (int j = 0; j < n2; ++j)
        R[j] = arr[m + 1 + j];

    int i = 0, j = 0, k = l;

    while (i < n1 && j < n2) {
        if (L[i] <= R[j]) {
            arr[k] = L[i];
            ++i;
        } else {
            arr[k] = R[j];
            ++j;
        }
        ++k;
    }

    while (i < n1) {
        arr[k] = L[i];
        ++i;
        ++k;
    }

    while (j < n2) {
        arr[k] = R[j];
        ++j;
        ++k;
    }
}

void mergeSort(std::vector<int>& arr, int l, int r) {
    if (l < r) {
        int m = l + (r - l) / 2;
        mergeSort(arr, l, m);
        mergeSort(arr, m + 1, r);
        merge(arr, l, m, r);
    }
}

int main() {
    std::vector<int> arr = {12, 11, 13, 5, 6, 7};
    mergeSort(arr, 0, arr.size() - 1);
    for (int i : arr) {
        std::cout << i << " ";
    }
    return 0;
}

1.3 堆排序(Heap Sort)

堆排序是一种基于二叉堆数据结构的排序算法。它将待排序的序列构造成一个大顶堆(或小顶堆),然后依次取出堆顶元素并调整堆以保证其有序。堆排序的时间复杂度为O(n log n),且不需要额外的内存空间。

#include <iostream>
#include <vector>

void heapify(std::vector<int>& arr, int n, int i) {
    int largest = i;
    int left = 2 * i + 1;
    int right = 2 * i + 2;

    if (left < n && arr[left] > arr[largest])
        largest = left;

    if (right < n && arr[right] > arr[largest])
        largest = right;

    if (largest != i) {
        std::swap(arr[i], arr[largest]);
        heapify(arr, n, largest);
    }
}

void heapSort(std::vector<int>& arr) {
    int n = arr.size();

    for (int i = n / 2 - 1; i >= 0; --i)
        heapify(arr, n, i);

    for (int i = n - 1; i > 0; --i) {
        std::swap(arr[0], arr[i]);
        heapify(arr, i, 0);
    }
}

int main() {
    std::vector<int> arr = {4, 10, 3, 5, 1};
    heapSort(arr);
    for (int i : arr) {
        std::cout << i << " ";
    }
    return 0;
}

2. 搜索算法

2.1 二分查找(Binary Search)

二分查找是一种高效的搜索算法,适用于在有序数组中查找特定元素。其基本思想是将数组从中间一分为二,与目标值比较后选择在左半部分或右半部分继续查找,直到找到目标值或范围缩小为空。二分查找的时间复杂度为O(log n)。

#include <iostream>
#include <vector>

int binarySearch(const std::vector<int>& arr, int l, int r, int x) {
    while (l <= r) {
        int m = l + (r - l) / 2;

        if (arr[m] == x)
            return m;

        if (arr[m] < x)
            l = m + 1;
        else
            r = m - 1;
    }
    return -1;
}

int main() {
    std::vector<int> arr = {2, 3, 4, 10, 40};
    int x = 10;
    int result = binarySearch(arr, 0, arr.size() - 1, x);
    if (result == -1)
        std::cout << "Element not present in array";
    else
        std::cout << "Element found at index " << result;
    return 0;
}

2.2 深度优先搜索(Depth-First Search, DFS)

深度优先搜索是一种图遍历算法,其基本思想是沿着一个分支不断向下搜索,直到无法继续为止,然后回溯并从其他分支继续搜索。DFS常用于解决连通性问题、生成迷宫、寻找路径等。时间复杂度为O(V + E),其中V是顶点数,E是边数。

#include <iostream>
#include <vector>

void DFSUtil(int v, std::vector<bool>& visited, const std::vector<std::vector<int>>& adj) {
    visited[v] = true;
    std::cout << v << " ";

    for (int i : adj[v])
        if (!visited[i])
            DFSUtil(i, visited, adj);
}

void DFS(int v, const std::vector<std::vector<int>>& adj) {
    std::vector<bool> visited(adj.size(), false);
    DFSUtil(v, visited, adj);
}

int main() {
    std::vector<std::vector<int>> adj = {
        {1, 2},
        {0, 3, 4},
        {0, 5},
        {1},
        {1},
        {2}
    };

    DFS(0, adj);
    return 0;
}

2.3 广度优先搜索(Breadth-First Search, BFS)

广度优先搜索是另一种图遍历算法,其基本思想是从一个起始顶点出发,依次访问其所有邻接顶点,然后再从这些顶点出发继续访问其未被访问的邻接顶点,直到所有顶点都被访问。BFS常用于求解最短路径问题。时间复杂度为O(V + E)。

#include <iostream>
#include <vector>
#include <queue>

void BFS(int v, const std::vector<std::vector<int>>& adj) {
    std::vector<bool> visited(adj.size(), false);
    std::queue<int> q;

    visited[v] = true;
    q.push(v);

    while (!q.empty()) {
        int u = q.front();
        q.pop();
        std::cout << u << " ";

        for (int i : adj[u]) {
            if (!visited[i]) {
                visited[i] = true;
                q.push(i);
            }
        }
    }
}

int main() {
    std::vector<std::vector<int>> adj = {
        {1, 2},
        {0, 3, 4},
        {0, 5},
        {1},
        {1},
        {2}
    };

    BFS(0, adj);
    return 0;
}

3. 动态规划(Dynamic Programming)

3.1 最长公共子序列(Longest Common Subsequence, LCS)

最长公共子序列问题是经典的动态规划问题,其目标是在两个序列中找到最长的公共子序列。通过构建一个二维DP表格,逐步填充每个子问题的最优解,从而得到整个问题的解。时间复杂度为O(n * m),其中n和m分别为两个序列的长度。

#include <iostream>
#include <vector>
#include <string>

int LCS(const std::string& X, const std::string& Y) {
    int n = X.size();
    int m = Y.size();
    std::vector<std::vector<int>> dp(n + 1, std::vector<int>(m + 1, 0));

    for (int i = 1; i <= n; ++i) {
        for (int j = 1; j <= m; ++j) {
            if (X[i - 1] == Y[j - 1])
                dp[i][j] = dp[i - 1][j - 1] + 1;
            else
                dp[i][j] = std::max(dp[i - 1][j], dp[i][j - 1]);
        }
    }

    return dp[n][m];
}

int main() {
    std::string X = "AGGTAB";
    std::string Y = "GXTXAYB";
    std::cout << "Length of LCS is " << LCS(X, Y);
    return 0;
}

3.2 背包问题(Knapsack Problem)

背包问题是另一个经典的动态规划问题,其目标是在给定物品的重量和价值的情况下,选择物品装入背包使得背包中的物品总价值最大化,而不超过背包的容量。使用动态规划可以有效解决这一问题,时间复杂度为O(n * W),其中n为物品数,W为背包容量。

#include <iostream>
#include <vector>

int knapSack(int W, const std::vector<int>& wt, const std::vector<int>& val, int n) {
    std::vector<std::vector<int>> dp(n + 1, std::vector<int>(W + 1, 0));

    for (int i = 1; i <= n; ++i) {
        for (int w = 1; w <= W; ++w) {
            if (wt[i - 1] <= w)
                dp[i][w] = std::max(val[i - 1] + dp[i - 1][w - wt[i - 1]], dp[i - 1][w]);
            else
                dp[i][w] = dp[i - 1][w];
        }
    }

    return dp[n][W];
}

int main() {
    std::vector<int> val = {60, 100, 120};
    std::vector<int> wt = {10, 20, 30};
    int W = 50;
    int n = val.size();
    std::cout << "Maximum value in Knapsack = " << knapSack(W, wt, val, n);
    return 0;
}

4. 图算法

4.1 Dijkstra算法

Dijkstra算法用于求解单源最短路径问题,特别是在图中不存在负权边的情况下。其基本思想是从起点开始,逐步找到到其他顶点的最短路径,直到所有顶点都被访问。时间复杂度为O(V^2)或O((V + E) log V)(使用优先队列时)。

#include <iostream>
#include <vector>
#include <queue>

const int INF = 1e9;

void dijkstra(int src, const std::vector<std::vector<std::pair<int, int>>>& adj) {
    int n = adj.size();
    std::vector<int> dist(n, INF);
    dist[src] = 0;

    std::priority_queue<std::pair<int, int>, std::vector<std::pair<int, int>>, std::greater<std::pair<int, int>>> pq;
    pq.push({0, src});

    while (!pq.empty()) {
        int u = pq.top().second;
        pq.pop();

        for (const auto& p : adj[u]) {
            int v = p.first;
            int weight = p.second;

            if (dist[v] > dist[u] + weight) {
                dist[v] = dist[u] + weight;
                pq.push({dist[v], v});
            }
        }
    }

    for (int i = 0; i < n; ++i) {
        std::cout << "Distance from " << src << " to " << i << " is " << dist[i] << "\n";
    }
}

int main() {
    std::vector<std::vector<std::pair<int, int>>> adj = {
        {{1, 4}, {2, 1}},
        {{3, 1}},
        {{1, 2}, {3, 5}},
        {}
    };

    dijkstra(0, adj);
    return 0;
}

4.2 Floyd-Warshall算法

Floyd-Warshall算法用于求解图中任意两点间的最短路径问题。其基本思想是通过动态规划逐步更新路径长度,直到所有顶点对之间的最短路径长度都被计算出来。时间复杂度为O(V^3)。

#include <iostream>
#include <vector>

const int INF = 1e9;

void floydWarshall(std::vector<std::vector<int>>& dist) {
    int n = dist.size();
    for (int k = 0; k < n; ++k) {
        for (int i = 0; i < n; ++i) {
            for (int j = 0; j < n; ++j) {
                if (dist[i][k] < INF && dist[k][j] < INF)
                    dist[i][j] = std::min(dist[i][j], dist[i][k] + dist[k][j]);
            }
        }
    }
}

int main() {
    std::vector<std::vector<int>> dist = {
        {0, 3, INF, INF},
        {2, 0, INF, INF},
        {INF, 7, 0, 1},
        {6, INF, INF, 0}
    };

    floydWarshall(dist);

    for (const auto& row : dist) {
        for (int d : row) {
            if (d == INF)
                std::cout << "INF ";
            else
                std::cout << d << " ";
        }
        std::cout << "\n";
    }

    return 0;
}

  • 21
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

老梁爱分享

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值