C/C++编程中的算法实现技巧与案例分析

news2024/9/29 17:35:39

C/C++编程语言因其高效、灵活和底层的特性,被广大开发者用于实现各种复杂算法。本文将通过10个具体的算法案例,详细探讨C/C++在算法实现中的技巧和应用。

在这里插入图片描述

一、冒泡排序(Bubble Sort)

冒泡排序(Bubble Sort)是一种简单的排序算法。它重复地遍历要排序的数列,一次比较两个元素,如果他们的顺序错误就把他们交换过来。遍历数列的工作是重复地进行直到没有再需要交换,也就是说该数列已经排序完成。这个算法的名字由来是因为越小的元素会经由交换慢慢“浮”到数列的顶端。

以下是使用C++实现冒泡排序的代码:

#include<iostream>
using namespace std;

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

void printArray(int arr[], int size) {
    for (int i=0; i < size; i++) {
        cout << arr[i] << " ";
    }
    cout << endl;
}

int main() {
    int arr[] = {64, 34, 25, 12, 22, 11, 90};
    int n = sizeof(arr)/sizeof(arr[0]);
    bubbleSort(arr, n);
    cout<<"Sorted array: \n";
    printArray(arr, n);
    return 0;
}

这段代码首先定义了一个名为bubbleSort的函数,该函数接受一个整数数组和数组的长度作为输入。在函数内部,我们使用两个嵌套的for循环来进行排序。外层循环表示我们总共需要进行的排序轮数,内层循环表示每轮排序中我们需要进行的比较次数。如果当前元素大于下一个元素,我们就交换这两个元素的位置。这样,经过多轮排序后,最大的元素就会被"冒泡"到数组的末尾。然后,我们继续对剩下的元素进行同样的操作,直到所有元素都被排序。最后,我们在main函数中调用bubbleSort函数对数组进行排序,并打印出排序后的结果。

二、快速排序(Quick Sort)

快速排序(Quick Sort)是由C.A.R. Hoare在1960年提出的一种排序算法。快速排序的基本思想是,通过一趟排序将待排记录分隔成独立的两部分,其中一部分记录的关键字均比另一部分记录的关键字小,然后分别对这两部分继续进行排序,以达到整个序列有序。

以下是使用C++实现快速排序的代码:

#include<iostream>
using namespace std;

int partition(int arr[], int low, int high) {
    int pivot = arr[high]; 
    int i = (low - 1); 

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

void quickSort(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); 
    }
}

void printArray(int arr[], int size) {
    for (int i = 0; i < size; i++) {
        cout << arr[i] << " ";
    }
    cout << endl;
}

int main() {
    int arr[] = {10, 7, 8, 9, 1, 5};
    int n = sizeof(arr) / sizeof(arr[0]);
    quickSort(arr, 0, n - 1);
    cout << "Sorted array: \n";
    printArray(arr, n);
    return 0;
}

这段代码首先定义了一个名为partition的函数,该函数接受一个整数数组以及两个索引(low和high)作为输入。这个函数的主要目的是选取一个基准元素(这里我们选择了数组的最后一个元素),然后将数组分为两部分,一部分的元素都小于基准元素,另一部分的元素都大于基准元素。partition函数返回的是基准元素的最终位置。然后,我们定义了一个名为quickSort的函数,该函数递归地对基准元素左右两侧的子数组进行同样的操作,直到整个数组都被排序。最后,我们在main函数中调用quickSort函数对数组进行排序,并打印出排序后的结果。

三、插入排序(Insertion Sort)

插入排序(Insertion Sort)是一种简单直观的排序算法。它的工作原理是通过构建有序序列,对于未排序数据,在已排序序列中从后向前扫描,找到相应位置并插入。插入排序在实现上,通常采用in-place排序(即只需用到O(1)的额外空间的排序),因而在从后向前扫描过程中,需要反复把已排序元素逐步向后挪位,为最新元素提供插入空间。

以下是使用C++实现插入排序的代码:

#include<iostream>
using namespace std;

void insertionSort(int arr[], int n) {
    int i, key, j;
    for (i = 1; i < n; i++) {
        key = arr[i];
        j = i - 1;

        /* Move elements of arr[0..i-1], that are greater than key, to one position ahead of their current position */
        while (j >= 0 && arr[j] > key) {
            arr[j + 1] = arr[j];
            j = j - 1;
        }
        arr[j + 1] = key;
    }
}

void printArray(int arr[], int size) {
    for (int i = 0; i < size; i++) {
        cout << arr[i] << " ";
    }
    cout << endl;
}

int main() {
    int arr[] = {12, 11, 13, 5, 6};
    int n = sizeof(arr) / sizeof(arr[0]);
    insertionSort(arr, n);
    cout << "Sorted array: \n";
    printArray(arr, n);
    return 0;
}

这段代码首先定义了一个名为insertionSort的函数,该函数接受一个整数数组以及数组的长度作为输入。在函数内部,我们使用一个for循环来遍历数组中的每个元素。对于每个元素,我们都将其保存到一个名为key的变量中,然后将其与前面已经排序好的元素进行比较。如果前面的元素大于key,我们就将前面的元素向后移动一位,为key腾出位置。我们一直这样操作,直到找到key应该插入的位置,然后将key插入到该位置。最后,我们在main函数中调用insertionSort函数对数组进行排序,并打印出排序后的结果。

四、选择排序(Selection Sort)

选择排序算法详解

选择排序是一种简单且直观的排序算法,它的基本思想是:遍历数组,找到最小(或最大)的元素,将其放到排序序列的起始位置。然后,从剩余未排序元素中继续寻找最小(或最大)元素,放到已排序序列的末尾。如此重复,直到所有元素均排序完毕。

算法步骤

  1. 在未排序序列中找到最小(或最大)元素,存放到排序序列的起始位置。
  2. 从剩余未排序元素中继续寻找最小(或最大)元素,然后放到已排序序列的末尾。
  3. 重复第二步,直到所有元素均排序完毕。

时间复杂度

  • 最好情况:O(n^2)
  • 最坏情况:O(n^2)
  • 平均情况:O(n^2)

空间复杂度:O(1)

稳定性:不稳定(考虑[3, 3, 2]这个例子,第一个3会被移动到2的后面,从而两个3的顺序颠倒了)。

C/C++代码实现

下面是一个使用C++实现的选择排序的例子:

#include <iostream>
using namespace std;

void selectionSort(int arr[], int n) {
    for (int i = 0; i < n - 1; i++) {
        // 找到未排序部分中的最小元素的位置
        int minIndex = i;
        for (int j = i + 1; j < n; j++) {
            if (arr[j] < arr[minIndex]) {
                minIndex = j; // 更新最小元素的位置
            }
        }
        // 将找到的最小元素与第一个未排序的元素交换位置
        if (minIndex != i) {
            swap(arr[i], arr[minIndex]);
        }
    }
}

int main() {
    int arr[] = {64, 25, 12, 22, 11};
    int n = sizeof(arr) / sizeof(arr[0]);
    selectionSort(arr, n);
    cout << "Sorted array: \n";
    for (int i = 0; i < n; i++) {
        cout << arr[i] << " ";
    }
    return 0;
}

在这个例子中,selectionSort函数实现了选择排序算法。它接受一个整数数组和数组的长度作为输入,并按升序对数组进行排序。main函数创建了一个待排序的数组,并调用selectionSort函数对其进行排序。最后,它打印出排序后的数组。

五、归并排序(Merge Sort)

归并排序(Merge Sort)是建立在归并操作上的一种有效的排序算法。该算法是采用分治法(Divide and Conquer)的一个非常典型的应用。将已有序的子序列合并,得到完全有序的序列;即先使每个子序列有序,再使子序列段间有序。若将两个有序表合并成一个有序表,称为2-路归并。

以下是使用C++实现归并排序的代码:

#include<iostream>
#include<vector>
using namespace std;

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

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

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

    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(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);
    }
}

void printArray(vector<int>& arr) {
    int arr_size = arr.size();
    for (int i = 0; i < arr_size; i++) {
        cout << arr[i] << " ";
    }
    cout << endl;
}

int main() {
    vector<int> arr = {12, 11, 13, 5, 6, 7};
    int arr_size = arr.size();
    cout << "Given array is \n";
    printArray(arr);
    mergeSort(arr, 0, arr_size - 1);
    cout << "\nSorted array is \n";
    printArray(arr);
    return 0;
}

这段代码首先定义了一个名为merge的函数,该函数用于合并两个已经排序好的子数组。然后定义了一个名为mergeSort的函数,该函数使用递归的方式将数组不断地拆分为更小的子数组,直到每个子数组只包含一个元素,然后将这些子数组合并起来。在main函数中,我们创建了一个整数数组,然后调用mergeSort函数对数组进行排序,并打印出排序后的结果。

六、堆排序(Heap Sort)

堆排序算法详解

堆排序(Heap Sort)是一种基于二叉堆(Binary Heap)的排序算法。它利用堆这种数据结构所设计的一种排序算法。堆是一个近似完全二叉树的结构,并同时满足堆积的性质:即子节点的键值或索引总是小于(或者大于)它的父节点。

算法步骤

  1. 创建一个最大堆(或最小堆)。最大堆的父节点大于或等于其子节点,最小堆则相反。
  2. 将堆顶元素与末尾元素互换,这样最大元素(或最小元素)就被移到了数组末尾。
  3. 减小堆的大小,并重新调整堆结构,使其保持最大堆(或最小堆)的性质。
  4. 重复步骤2和3,直到整个数组排序完成。

时间复杂度

  • 最好情况:O(nlogn)
  • 最坏情况:O(nlogn)
  • 平均情况:O(nlogn)

空间复杂度:O(1)

稳定性:不稳定(考虑[3, 3, 2]这个例子,第一个3会被移动到2的后面,从而两个3的顺序颠倒了)。

C/C++代码实现

以下是一个使用C++实现堆排序的例子:

#include <iostream>
#include <vector>
#include <algorithm>
using namespace std;

// 调整堆结构,使其保持最大堆的性质
void maxHeapify(vector<int>& nums, int i, int heapSize) {
    int largest = i; // 初始化最大值为当前节点i
    int left = 2 * i + 1; // 左子节点索引
    int right = 2 * i + 2; // 右子节点索引

    // 如果左子节点大于当前最大值,则更新最大值索引
    if (left < heapSize && nums[left] > nums[largest]) {
        largest = left;
    }
    // 如果右子节点大于当前最大值,则更新最大值索引
    if (right < heapSize && nums[right] > nums[largest]) {
        largest = right;
    }
    // 如果最大值不是当前节点i,则交换它们的值,并递归调整子堆结构
    if (largest != i) {
        swap(nums[i], nums[largest]);
        maxHeapify(nums, largest, heapSize);
    }
}

// 构建最大堆
void buildMaxHeap(vector<int>& nums) {
    int heapSize = nums.size();
    // 从最后一个非叶子节点开始,逐个向上调整堆结构
    for (int i = heapSize / 2 - 1; i >= 0; i--) {
        maxHeapify(nums, i, heapSize);
    }
}

// 堆排序函数
void heapSort(vector<int>& nums) {
    int heapSize = nums.size();
    // 构建最大堆
    buildMaxHeap(nums);
    // 将堆顶元素与末尾元素交换,并重新调整堆结构,直到整个数组排序完成
    for (int i = nums.size() - 1; i > 0; i--) {
        swap(nums[0], nums[i]); // 将堆顶元素与末尾元素交换
        heapSize--; // 减小堆的大小
        maxHeapify(nums, 0, heapSize); // 重新调整堆结构,使其保持最大堆的性质
    }
}

int main() {
    vector<int> nums = {3, 7, 1, 9, 2, 8, 5, 6, 4}; // 待排序数组
    heapSort(nums); // 使用堆排序对数组进行排序
    cout << "Sorted array: "; // 输出排序后的数组
    for (int num : nums) {
        cout << num << " ";
    }
    cout << endl; // 换行符,使输出更美观
    return 0; // 程序正常结束,返回0作为状态码
}

七、二分查找(Binary Search)

二分查找算法详解

二分查找(Binary Search)是一种在有序数组中查找特定元素的搜索算法。它的工作原理是,首先将数组的中间元素与目标值进行比较,如果两者相等,则查找成功;如果目标值小于中间元素,则在数组的左半部分继续查找;如果目标值大于中间元素,则在数组的右半部分继续查找。如此重复,每次都将搜索范围缩小一半,直到找到目标值,或者搜索范围为空(即找不到目标值)。

算法步骤

  1. 确定数组的中间元素的下标 mid = (left + right) / 2。
  2. 如果数组为空或 left > right,则返回 -1 或抛出异常(表示未找到目标值)。
  3. 如果中间元素等于目标值,则返回 mid。
  4. 如果目标值小于中间元素,则在左半部分(left, mid - 1)继续查找。
  5. 如果目标值大于中间元素,则在右半部分(mid + 1, right)继续查找。
  6. 重复步骤 1-5,直到找到目标值或确定目标值不存在于数组中。

时间复杂度:O(log n),其中 n 是数组的长度。

C/C++代码实现

以下是使用C++实现二分查找算法的一个例子:

#include <iostream>
#include <vector>
using namespace std;

int binarySearch(vector<int>& nums, int target) {
    int left = 0;
    int right = nums.size() - 1;
    while (left <= right) {
        int mid = left + (right - left) / 2; // 防止溢出
        if (nums[mid] == target) {
            return mid; // 找到目标值,返回其下标
        } else if (nums[mid] < target) {
            left = mid + 1; // 在右半部分继续查找
        } else {
            right = mid - 1; // 在左半部分继续查找
        }
    }
    return -1; // 未找到目标值,返回 -1
}

int main() {
    vector<int> nums = {1, 3, 5, 7, 9}; // 有序数组
    int target = 5; // 要查找的目标值
    int result = binarySearch(nums, target); // 调用二分查找函数
    if (result != -1) {
        cout << "Target found at index: " << result << endl; // 输出找到目标值的下标
    } else {
        cout << "Target not found in the array." << endl; // 输出未找到目标值的消息
    }
    return 0;
}

在这个例子中,我们定义了一个名为 binarySearch 的函数,它接受一个有序整数数组 nums 和一个目标值 target 作为输入,并返回目标值在数组中的下标(如果找到的话),否则返回 -1。在主函数 main 中,我们创建了一个有序数组 nums 和一个目标值 target,然后调用 binarySearch 函数进行查找。最后,根据函数的返回值输出相应的消息。

八、动态规划(Dynamic Programming)

动态规划算法详解

动态规划(Dynamic Programming,简称DP)是一种在数学、计算机科学和经济学中使用的,通过把原问题分解为相对简单的子问题的方式来求解复杂问题的方法。动态规划常常适用于有重叠子问题和最优子结构性质的问题。

动态规划的基本思想是将待求解问题分解成若干个子问题,先求解子问题,然后从这些子问题的解得到原问题的解。

基本步骤

  1. 描述问题的最优解的结构:这一步通常是通过递归关系式来描述原问题的最优解是如何由子问题的最优解构成的。
  2. 定义状态:这一步是定义一个或多个状态变量来刻画子问题的解。
  3. 状态转移方程:根据上一步定义的状态,写出状态转移方程,描述如何从子问题的解构造出原问题的解。
  4. 边界条件:明确问题的边界条件,也就是最小的子问题的解。
  5. 计算最优解:根据状态转移方程和边界条件,从最小的子问题开始,逐步计算原问题的最优解。

举例说明:0-1背包问题

问题描述:给定一组物品,每种物品都有自己的重量和价值,在限定的总重量内,我们如何选择,才能使得物品的总价值最大。

假设物品数量为n,每种物品i的重量为w[i],价值为v[i],背包的总容量为W。定义dp[i][j]为考虑前i个物品且背包容量为j时的最大价值。

状态转移方程为:dp[i][j] = max(dp[i-1][j], dp[i-1][j-w[i]] + v[i]) (当j >= w[i])

边界条件为:dp[0][j] = 0 (0 <= j <= W) 和 dp[i][0] = 0 (0 <= i <= n)

C++代码实现如下:

#include<iostream>
#include<vector>
#include<algorithm>
using namespace std;

int knapsack(int W, vector<int>& wt, vector<int>& val, int n) {
    vector<vector<int>> dp(n + 1, 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] = 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() {
    int W = 50; // 背包容量
    vector<int> wt = {10, 20, 30}; // 物品重量
    vector<int> val = {60, 100, 120}; // 物品价值
    int n = wt.size(); // 物品数量
    cout << "最大价值为:" << knapsack(W, wt, val, n) << endl;
    return 0;
}

这段代码通过动态规划解决了0-1背包问题,输出了在背包容量为50时可以获得的最大价值。

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

深度优先搜索是一种用于遍历或搜索树或图的算法。这个算法会尽可能深地搜索树的分支。当节点v的所在边都已被探寻过,搜索将回溯到发现节点v的那条边的起始节点。这一过程一直进行到已发现从源节点可达的所有节点为止。如果还存在未被发现的节点,则选择其中一个作为源节点并重复以上过程,整个进程反复进行直到所有节点都被访问为止。

基本步骤

  1. 访问初始节点v。
  2. 标记节点v为已访问。
  3. 对于v的每一个相邻节点n,如果n没有被访问过,则递归地深度优先搜索n。

适用场景
深度优先搜索通常用于遍历树或图,寻找路径,解决迷宫问题等。

C++代码示例:使用DFS遍历图

下面是一个简单的C++代码示例,用于通过深度优先搜索遍历一个图:

#include<iostream>
#include<list>
using namespace std;

class Graph {
    int numVertices;
    list<int>* adjLists;
    bool* visited;

public:
    Graph(int vertices);  
    void addEdge(int src, int dest);
    void DFS(int vertex);
};

Graph::Graph(int vertices) {
    numVertices = vertices;
    adjLists = new list<int>[vertices];
    visited = new bool[vertices];
}

void Graph::addEdge(int src, int dest) {
    adjLists[src].push_back(dest);
}

void Graph::DFS(int vertex) {
    visited[vertex] = true;
    cout << "Visited " << vertex << endl;

    list<int>::iterator i;
    for(i = adjLists[vertex].begin(); i != adjLists[vertex].end(); ++i) {
        if(!visited[*i]) {
            DFS(*i);
        }
    }
}

int main() {
    Graph g(5);  // 创建一个有5个顶点的图
    g.addEdge(0, 1);  // 添加边 (0, 1)
    g.addEdge(0, 2);  // 添加边 (0, 2)
    g.addEdge(1, 3);  // 添加边 (1, 3)
    g.addEdge(2, 4);  // 添加边 (2, 4)
    g.addEdge(3, 4);  // 添加边 (3, 4)
    g.DFS(0);  // 从顶点0开始深度优先搜索
    return 0;
}

这个代码示例创建了一个有5个顶点的图,并添加了一些边。然后它从顶点0开始进行深度优先搜索,并打印出访问的顶点。注意,这个示例仅用于教学目的,实际应用中可能需要更复杂的错误处理和优化。

十、分治算法(Divide and Conquer)

分治算法(Divide and Conquer)详解

分治算法是一种处理大型问题的有效方法。它的核心思想是将一个难以直接解决的大问题,分解成两个或更多的规模较小的相同问题,直到最后子问题可以简单的直接求解,然后将这些子问题的解合并得到原问题的解。

基本步骤

  1. 分解:将原问题分解为若干个规模较小,相互独立,与原问题形式相同的子问题。
  2. 解决:若子问题规模较小而容易被解决则直接解,否则递归地解各个子问题。
  3. 合并:将各个子问题的解合并为原问题的解。

适用场景
分治算法可以解决的问题一般具有以下几个特征:

  • 该问题的规模缩小到一定的程度就可以容易地解决。
  • 该问题可以分解为若干个规模较小的相同问题,即该问题具有最优子结构性质。
  • 利用该问题分解出的子问题的解可以合并为该问题的解;
  • 该问题所分解出的各个子问题是相互独立的,即子问题之间不包含公共的子问题。

C++代码示例:归并排序

归并排序是分治算法的典型应用。其基本原理是将两个(或更多)已排序的数据序列合并成一个新的有序序列。

以下是使用C++实现归并排序的代码:

#include<iostream>
#include<vector>
using namespace std;

void merge(vector<int>& arr, int l, int m, int r) {
    int i, j, k;
    int n1 = m - l + 1;
    int n2 = r - m;
 
    // 创建临时数组
    vector<int> L(n1), R(n2);
 
    // 拷贝数据到临时数组 L[] 和 R[]
    for (i = 0; i < n1; i++)
        L[i] = arr[l + i];
    for (j = 0; j < n2; j++)
        R[j] = arr[m + 1 + j];
 
    // 合并临时数组到 arr[l..r]
    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++;
    }
 
    // 将 L[] 的剩余元素复制到 arr
    while (i < n1) {
        arr[k] = L[i];
        i++;
        k++;
    }
 
    // 将 R[] 的剩余元素复制到 arr
    while (j < n2) {
        arr[k] = R[j];
        j++;
        k++;
    }
}
 
void mergeSort(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); //合并结果。																																																	                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                       > 对于每个数组段,先排序然后合并,这就实现了归并排序。这也是典型的分治策略应用。将大问题划分为小问题来解决,然后将结果合并起来解决整个问题。在归并排序中,我们将数组分成两半,对每一半进行排序,然后将两个排序好的数组合并成一个大的有序数组。这个过程一直递归进行下去,直到我们得到一个完全有序的数组。递归发生在“mergeSort()”函数中,而“merge()”函数是用来合并两个已经排序好的数组段。在上面的代码中,“mergeSort()”函数递归地将数组分割成更小的数组,直到数组的大小为1(这意味着它已经排序好了)。然后“merge()”函数被调用来将这些小数组两两合并成更大的有序数组。这个过程一直进行下去,直到我们得到原始数组的一个完全有序的版本。在这个实现中,“merge()”函数用了一个非常简单的技巧来避免额外的空间复杂度——它使用了两个临时的数组L和R来存储分割的数组段,然后将它们合并回原始数组中。这意味着归并排序的空间复杂度是O(n),其中n是输入数组的大小。这是因为在任何时候,我们都需要有足够的空间来存储原始数组的两个分割段。总的来说,归并排序是一个非常有效且易于理解的排序算法,它的时间复杂度是O(n log n),其中n是输入数组的大小。虽然它的空间复杂度比一些其他排序算法高(例如堆排序和快速排序),但是在许多情况下,它的稳定性和简单性使得它成为了一个非常实用的选择。此外,由于它的并行性(即它可以很容易地分解成独立的子任务),它在某些应用中(例如多核处理器或多线程环境中)可能会比其他排序算法更加高效。所以归并排序是分治算法的一个很好的例子,展示了如何将一个大问题分解成小问题来解决,然后将结果合并起来解决整个问题。它也是一个在实践中广泛使用的算法,特别是在需要处理大量数据的情况下。它的时间复杂度和空间复杂度都是可预测的,并且它的稳定性和简单性使得它在许多情况下都是一个非常实用的选择。最后,需要注意的是,虽然归并排序在理论上是一个非常优秀的算法,但是在实际应用中,它的性能可能会受到一些因素的影响,例如数据的分布、内存访问模式等。因此,在选择使用哪种排序算法时,需要综合考虑这些因素以及具体的应用场景和需求。以上代码就是使用C++实现归并排序的示例代码,并且包含了对于分治策略应用的详细解释和代码注释说明。" << endl; // 输出提示信息以帮助理解代码运行过程
}
int main() {
vector<int> arr = {12, 11, 13, 5, 6, 7};
int arr_size = arr.size();
cout << "给定的数组是:\n";
for (int i = 0; i < arr_size; i++) {
cout << arr[i] << " ";} cout << "\n\n";
mergeSort(arr, 0, arr_size - 1);
cout << "排序后的数组是:\n";
for (int i = 0; i < arr_size; i++) {
cout << arr[i] << " ";} cout << endl;
return 0;
} //主函数结束

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1323022.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

单片机应用实例:LED显示电脑电子钟

本例介绍一种用LED制作的电脑电子钟&#xff08;电脑万年历&#xff09;。其制作完成装潢后的照片如下图&#xff1a; 上图中&#xff0c;年、月、日及时间选用的是1.2寸共阳数码管&#xff0c;星期选用的是2.3寸数码管&#xff0c;温度选用的是0.5寸数码管&#xff0c;也可根据…

人工智能中不可预测的潜在错误可能是灾难性的——数学解释

一、说明 有没有人研究评估AI的错误产生的后果有多么严重&#xff0c;是否存在AI分险评估机制&#xff1f;更高维度上&#xff0c;人工智能的未来是反乌托邦还是乌托邦&#xff1f;这个问题一直是争论的话题&#xff0c;各大阵营都支持。我相信我们无法准确预测这两种结果。这是…

画图之C4架构图idea和vscode环境搭建篇

VS Code 下C4-PlantUML安装 安装VS Code 直接官网下载安装即可,过程略去。 安装PlantUML插件 在VS Code的Extensions窗口中搜索PlantUML,安装PlantUML插件。 配置VS Code代码片段 安装完PlantUML之后,为了提高效率,我们最好安装PlantUML相关的代码片段。 打开VS Cod…

React心理健康测试网站系统源码

帮助需要的人更好地了解自己的心理健康状态和人格特征。本模板提供了一个最小的配置&#xff0c;使得React可以在Vite中启用HMR&#xff0c;并且包含了几个ESLint规则。只需要使用react antd-mobile即可轻松部署完成。 源码下载&#xff1a;https://download.csdn.net/downlo…

操作系统系列:Unix进程系统调用fork,wait,exec

操作系统系列&#xff1a;Unix进程系统调用 fork系统调用fork()运用的小练习 wait系统调用Zombiesexec 系列系统调用 开发者可以查看创建新进程的系统调用&#xff0c;这个模块会讨论与进程相关的Unix系统调用&#xff0c;下一个模块会讨论Win32 APIs相关的进程。 fork系统调用…

智能优化算法应用:基于学生心理学算法3D无线传感器网络(WSN)覆盖优化 - 附代码

智能优化算法应用&#xff1a;基于学生心理学算法3D无线传感器网络(WSN)覆盖优化 - 附代码 文章目录 智能优化算法应用&#xff1a;基于学生心理学算法3D无线传感器网络(WSN)覆盖优化 - 附代码1.无线传感网络节点模型2.覆盖数学模型及分析3.学生心理学算法4.实验参数设定5.算法…

VS+Qt 打包Python程序

书接上回&#xff0c;调用C调用python&#xff0c;下面来谈谈随exe文件打包。 先说下环境vs2019Qt5.12.11python3.8&#xff0c;这里需要注意如果你要适配Win7的系统&#xff0c;python最好是9以下&#xff0c;以上不兼容&#xff0c;也没时间找方法&#xff0c;找到评论说下 如…

实现个人日志命令行工具(C语言)

〇、前言 中午上课的时候&#xff0c;打开 github 看了一下个人主页&#xff0c;虽然最近很忙&#xff0c;但是这个活动记录有点过于冷清&#xff1a; 于是我就想着写一个日志命令行工具&#xff0c;输入以下命令就能将我的日志立即同步到 github 上&#xff1a; mylog toda…

Jenkins+Docker+Gitee搭建自动化部署平台

目录 服务器准备 Docker安装 yum 包更新到最新 设置yum源 安装docker 启动和开机启动 验证安装是否成功 Jenkins安装 拉取镜像 创建映射目录 运行镜像 运行出错 修正权限 重新运行镜像 新建安全组&#xff0c;放通8080端口 激活Jenkins Jenkins插件 Jenkins全…

el-form与el-upload结合上传带附件的表单数据(前端篇)

1.写在之前 本文前端采用Vue element-plus技术栈&#xff0c;前端项目参考yudao-ui-admin-vue3项目与Geeker-Admin项目。 这篇文章是el-form与el-upload结合上传带附件的表单数据&#xff08;后端篇&#xff09;-CSDN博客姐妹篇&#xff0c;后端篇文章主要讲的是后端的实现逻…

限流原理与实践:固定窗口、滑动窗口、漏桶与令牌桶解析

方案一、固定窗口限流算法 这里我们通过一个 demo 来介绍固定窗口限流算法。 创建一个 FixWindowRateLimiterService 类。 Service public class FixWindowRateLimiterService {Resourceprivate StringRedisTemplate stringRedisTemplate;private static final DefaultRedisSc…

新手上路:自动驾驶行业快速上手指南

文章目录 1.自动驾驶技术的发展1.1 工业革命驱动自动驾驶技术发展1.2 想象中的未来&#xff1a;科幻作品中的自动驾驶汽车1.3 自动驾驶技术萌芽与尝试1.4 百花争鸣&#xff1a;自动驾驶科技巨头与创业公司并进 2.个人开发者&#xff0c;如何玩转自动驾驶&#xff1f;2.1 灵活易…

Opencv实验合集——实验六:模板匹配

1.概念 模板匹配旨在在图像中找到与给定模板最相似的部分。其核心思想是通过滑动模板&#xff0c;计算每个位置与模板的相似性&#xff0c;然后找到最匹配的位置。这一过程常涉及选择匹配度量方法&#xff0c;如平方差匹配、归一化平方差匹配、相关性匹配等。模板匹配在目标检…

git缓存区、本地仓库、远程仓库的同步问题(初始化库无法pull和push)

git新建库与本地库同步 gitee使用教程&#xff0c;git的下载与安装接不在叙述了。 新建远程仓库 新建远程仓库必须要使用仓库提供的api&#xff0c;也就是仓库门户网站&#xff0c;例如gitee&#xff0c;github&#xff0c;gitlab等。在上图中使用gitee网址中新建了一个test仓…

【无语】Microsoft Edge 浏览器不显示后台返回的数值数据

Microsoft Edge 禁用 JSON 视图 写在前面禁用 JSON 视图 写在前面 遇到一个有意思的事情&#xff0c;在用 Microsoft Edge 浏览器发送请求测试时发现&#xff0c;后端返回的数值数据没有正常展示&#xff0c;而是类似查看源码的结果&#xff0c;只显示了一个行号1&#xff0c;…

SpringMVC01

SpringMVC 1. 学习⽬标2. 什么叫MVC&#xff1f;3. SpringMVC 框架概念与特点4. SpringMVC 请求流程5. Spring MVC 环境搭建6. URL 地址映射配置7. 参数绑定8. JSON 数据开发JSON普通数组步骤1:pom.xml添加依赖步骤2&#xff1a; 修改配置⽂件步骤3. 注解使⽤ 1. 学习⽬标 2. 什…

Android Studio: 解决Gradle sync failed 错误

文章目录 1. 前言2. 错误情况3. 解决办法3.1 获取gradle下载地址3.2 获取gradle存放目录3.3 替换并删除临时文件3.4 触发Try Again 4. 执行成功 1. 前言 今天调试项目&#xff0c;发现新装的AS&#xff0c;在下载gradle的过程中&#xff0c;一直显示连接失败&#xff0c;Gradl…

Zookeeper-快速开始

Zookeeper介绍 简介&#xff1a;ZooKeeper 是一个开源的分布式协调框架&#xff0c;是Apache Hadoop 的一个子项目&#xff0c;主要用来解决分布式集群中应用系统的一致性问题。 设计目标&#xff1a;将那些复杂且容易出错的分布式一致性服务封装起来&#xff0c;构成一个高效…

数据可视化---饼图、环形图、雷达图

类别内容导航机器学习机器学习算法应用场景与评价指标机器学习算法—分类机器学习算法—回归机器学习算法—聚类机器学习算法—异常检测机器学习算法—时间序列数据可视化数据可视化—折线图数据可视化—箱线图数据可视化—柱状图数据可视化—饼图、环形图、雷达图统计学检验箱…

linux:掌握systemctl命令控制软件的启动和关闭、掌握使用ln命令创建软连接

掌握使用systemctl命令控制软件的启动和关闭 一&#xff1a;systemctl命令&#xff1a; Linux系统很多软件(内置或第三方)均支持使用systemctl命令控制:启动停止、开机自启 能够被systemctl管理的软件一般也称之为:服务 语法: systemctl | start | stop | status | enable …