C++排序算法全解析

常见排序算法详解(C++实现)

排序算法是计算机科学中的基础技术,用于将数据序列按特定顺序(如升序或降序)排列。常见算法包括冒泡排序、选择排序、插入排序、快速排序、归并排序和堆排序等。每种算法都有其原理、时间复杂度和适用场景。本文将逐一介绍这些算法,并提供C++代码实现,帮助你直观理解。

1. 冒泡排序(Bubble Sort)

冒泡排序通过重复比较相邻元素并交换顺序错误的元素,将最大元素逐渐"冒泡"到末尾。

  • 原理:从数组开头开始,比较相邻元素,如果顺序错误则交换。重复此过程直到数组有序。
  • 时间复杂度:平均和最坏情况为O(n\^2),最好情况(已有序)为O(n)
  • C++代码
cpp 复制代码
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]) {
                std::swap(arr[j], arr[j+1]);
            }
        }
    }
}
2. 选择排序(Selection Sort)

选择排序通过重复选择未排序部分的最小元素,并将其放到已排序部分的末尾。

  • 原理:遍历数组,找到最小元素,与当前位置交换。重复此过程直到数组有序。
  • 时间复杂度:平均、最坏和最好情况均为O(n\^2)
  • C++代码
cpp 复制代码
void selectionSort(int arr[], int n) {
    for (int i = 0; i < n-1; i++) {
        int min_idx = i;
        for (int j = i+1; j < n; j++) {
            if (arr[j] < arr[min_idx]) {
                min_idx = j;
            }
        }
        std::swap(arr[i], arr[min_idx]);
    }
}
3. 插入排序(Insertion Sort)

插入排序通过构建有序序列,对未排序元素逐个插入到正确位置。

  • 原理:从第二个元素开始,将其与已排序部分比较,插入到合适位置。
  • 时间复杂度:平均和最坏情况为O(n\^2),最好情况(已有序)为O(n)
  • C++代码
cpp 复制代码
void insertionSort(int arr[], int n) {
    for (int i = 1; i < n; i++) {
        int key = arr[i];
        int j = i-1;
        while (j >= 0 && arr[j] > key) {
            arr[j+1] = arr[j];
            j--;
        }
        arr[j+1] = key;
    }
}
4. 快速排序(Quick Sort)

快速排序通过分治法选择基准元素,将数组分为小于基准和大于基准的两部分,递归排序。

  • 原理:选择基准(如第一个元素),分区后递归排序子数组。
  • 时间复杂度:平均和最好情况为O(n \\log n),最坏情况(已有序)为O(n\^2)
  • C++代码
cpp 复制代码
int partition(int arr[], int low, int high) {
    int pivot = arr[low];
    int i = low, j = high;
    while (i < j) {
        while (i < j && arr[j] >= pivot) j--;
        if (i < j) arr[i++] = arr[j];
        while (i < j && arr[i] <= pivot) i++;
        if (i < j) arr[j--] = arr[i];
    }
    arr[i] = pivot;
    return i;
}

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);
    }
}
5. 归并排序(Merge Sort)

归并排序使用分治法将数组分成两半,递归排序后合并。

  • 原理:递归分割数组到最小单位,然后合并两个有序数组。
  • 时间复杂度:平均、最坏和最好情况均为O(n \\log n)
  • C++代码
cpp 复制代码
void merge(int arr[], int left, int mid, int right) {
    int n1 = mid - left + 1;
    int n2 = right - mid;
    int L[n1], R[n2];
    for (int i = 0; i < n1; i++) L[i] = arr[left+i];
    for (int j = 0; j < n2; j++) R[j] = arr[mid+1+j];
    int i = 0, j = 0, k = left;
    while (i < n1 && j < n2) {
        if (L[i] <= R[j]) arr[k++] = L[i++];
        else arr[k++] = R[j++];
    }
    while (i < n1) arr[k++] = L[i++];
    while (j < n2) arr[k++] = R[j++];
}

void mergeSort(int arr[], int left, int right) {
    if (left < right) {
        int mid = left + (right - left) / 2;
        mergeSort(arr, left, mid);
        mergeSort(arr, mid+1, right);
        merge(arr, left, mid, right);
    }
}
6. 堆排序(Heap Sort)

堆排序利用堆数据结构,将数组视为最大堆,重复提取最大元素并调整堆。

  • 原理:构建最大堆,交换根节点与末尾元素,调整堆大小并重复。
  • 时间复杂度:平均、最坏和最好情况均为O(n \\log n)
  • C++代码
cpp 复制代码
void heapify(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(int arr[], int n) {
    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);
    }
}

总结

常见排序算法各有特点:

  • 时间复杂度比较
    • O(n\^2)算法:冒泡、选择、插入排序,简单但效率低,适合小规模数据。
    • O(n \\log n)算法:快速、归并、堆排序,高效,适合大规模数据。
  • 稳定性:冒泡、插入、归并排序是稳定的(相等元素顺序不变);选择、快速、堆排序不稳定。
  • 空间复杂度:冒泡、选择、插入、堆排序为O(1);快速排序平均O(\\log n)(递归栈);归并排序为O(n)

在实际应用中,选择算法需考虑数据规模、内存限制和稳定性需求。例如,快速排序在平均情况下性能优异,而归并排序适合外部排序。通过以上C++代码,你可以动手实现并加深理解。

相关推荐
码路飞40 分钟前
GPT-5.3 Instant 终于学会好好说话了,顺手对比了下同天发布的 Gemini 3.1 Flash-Lite
java·javascript
qianpeng8971 小时前
水声匹配场定位原理及实验
算法
SimonKing1 小时前
OpenCode AI编程助手如何添加Skills,优化项目!
java·后端·程序员
Seven973 小时前
剑指offer-80、⼆叉树中和为某⼀值的路径(二)
java
董董灿是个攻城狮12 小时前
AI视觉连载8:传统 CV 之边缘检测
算法
怒放吧德德14 小时前
Netty 4.2 入门指南:从概念到第一个程序
java·后端·netty
雨中飘荡的记忆16 小时前
大流量下库存扣减的数据库瓶颈:Redis分片缓存解决方案
java·redis·后端
心之语歌18 小时前
基于注解+拦截器的API动态路由实现方案
java·后端
华仔啊19 小时前
Stream 代码越写越难看?JDFrame 让 Java 逻辑回归优雅
java·后端
ray_liang19 小时前
用六边形架构与整洁架构对比是伪命题?
java·架构