数据结构与算法复习(一) 排序算法

简介: 数据结构与算法复习(一) 排序算法

前言


这篇文章将会介绍常见的排序算法(使用 C++ 实现)


正文


1、冒泡排序


将数组分为有序区(左边)和无序区(右边),在初始化时有序区为空,无序区包含数组所有元素

每次从无序区的最后一个元素开始,一直向前冒泡到无序区的第一个位置,使其变成有序

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


2、选择排序


将数组分为有序区(左边)和无序区(右边),在初始化时有序区为空,无序区包含数组所有元素

每次从无序区中选择一个合适的元素,并将其交换到无序区的第一个位置,使其变成有序

template<typename E>
void swap(E A[], int i, int j) {
    E temp = A[i];
    A[i] = A[j];
    A[j] = temp;
}
template<typename E>
void selectionSort(E A[], int n) {
    for (int i = 0; i < n - 1; i++) {
        int minIdx = i;
        for (int j = i; j <= n - 1; j++) {
            if (A[j] < A[minIdx]) minIdx = j;
        }
        swap(A, i, minIdx);
    }
}


3、插入排序


将数组分为有序区(左边)和无序区(右边),在初始化时有序区包含数组的第一个元素,无序区包含其余的元素

每次将无序区中的第一个元素,一直向前交换到有序区中的合适位置,使其变成有序

template<typename E>
void swap(E A[], int i, int j) {
    E temp = A[i];
    A[i] = A[j];
    A[j] = temp;
}
template<typename E>
void insertionSort(E A[], int n) {
    for (int i = 1; i < n; i++) {
    for (int j = i; j > 0; j--) {
            if (A[j] < A[j - 1]) {
                swap(A, j, j - 1);
            }
        }
  }
}


4、归并排序


递归进行,每次将数组一分为二,然后对两个数组分别排序后,合并两个数组

template<typename E>
void mergeSort(E A[], E T[], int l, int r) {
    if (l == r) return;
    int m = (l + r) / 2;
    mergeSort<E>(A, T, l, m);
    mergeSort<E>(A, T, m + 1, r);
    // merge
    for (int k = l; k <= r; k++) T[k] = A[k];
    int i = l, j = m + 1;
    for (int c = l; c <= r; c++) {
        if (i > m) A[c] = T[j++];
        else if (j > r) A[c] = T[i++];
        else if (T[i] < T[j]) A[c] = T[i++];
        else A[c] = T[j++];
    }
}


优化:临时数组后半部分反向插入,这样可以不用检测边界情况

template<typename E>
void mergeSort(E A[], E T[], int l, int r) {
    if (l == r) return;
    int m = (l + r) / 2;
    mergeSort<E>(A, T, l, m);
    mergeSort<E>(A, T, m + 1, r);
    // merge
    for (int k = l; k <= m; k++) T[k] = A[k];
    for (int k = 1; k <= r - m; k++) T[r - k + 1] = A[k + m];
    int i = l, j = r;
    for (int c = l; c <= r; c++) {
        if (T[i] < T[j]) A[c] = T[i++];
        else A[c] = T[j--];
    }
}


5、快速排序


递归进行,每次在数组中选择一个基准,根据基准将数组一分为二,然后对两个数组分别排序后,拼接两个数组

template<typename E>
void swap(E A[], int i, int j) {
    E temp = A[i];
    A[i] = A[j];
    A[j] = temp;
}
template<typename E>
void quickSort(E A[], int l, int r) {
    if (r <= l) return;
    // find pivot
    int pivotIndex = (l + r) / 2;
    E pivot = A[pivotIndex];
    // put pivot at last
    swap(A, pivotIndex, r);
    // partition
    int i = l - 1;
    int j = r;
    do {
        while (A[++i] < pivot) {}
        while (i < j && pivot < A[--j]) {}
        swap(A, i, j);
    } while (i < j);
    // put pivot in place
    swap(A, r, i);
    // recursive
    quickSort(A, l, i - 1);
    quickSort(A, i + 1, r);
}


优化:使用栈替代递归

template<typename E>
void swap(E A[], int i, int j) {
    E temp = A[i];
    A[i] = A[j];
    A[j] = temp;
}
template<typename E>
void quickSort(E A[], int l, int r) {
    int stack[200];
    int top = -1;
    stack[++top] = l;
    stack[++top] = r;
    while (top > 0) {
        // pop the stack
        r = stack[top--];
        l = stack[top--];
        // find pivot
        int pivotIndex = (l + r) / 2;
        E pivot = A[pivotIndex];
        // put pivot at last
        swap(A, pivotIndex, r);
        // partition
        int i = l - 1;
        int j = r;
        do {
            while (A[++i] < pivot) {}
            while (i < j && pivot < A[--j]) {}
            swap(A, i, j);
        } while (i < j);
        // undo the last swap
        swap(A, i, j);
        // put pivot in place
        swap(A, r, i);
        // load up stack
        if (i - 1 > l) {
            stack[++top] = l;
            stack[++top] = i - 1;
        }
        if (r > i + 1) {
            stack[++top] = i + 1;
            stack[++top] = r;
        }
    }
}


6、测试


测试程序

#include <iostream>
#include <time.h>
using namespace std;
int main() {
    const int num = 1000;
    const int minVal = 0;
    const int maxVal = 1000;
    int* arr = new int[num];
    for (int i = 0; i < num; i++)
        arr[i] = rand() % (maxVal - minVal + 1) + minVal;
    int* a4b = new int[num];
    int* a4s = new int[num];
    int* a4i = new int[num];
    int* a4m = new int[num];
    int* a4q = new int[num];
    int* t = new int[num];
    for (int i = 0; i < num; i++) a4b[i] = arr[i];
    for (int i = 0; i < num; i++) a4s[i] = arr[i];
    for (int i = 0; i < num; i++) a4i[i] = arr[i];
    for (int i = 0; i < num; i++) a4m[i] = arr[i];
    for (int i = 0; i < num; i++) a4q[i] = arr[i];
    clock_t start, end;
    start = clock();
    bubbleSort(a4b, num);
    end = clock();
    cout << "bubbleSort: " << (double)(end-start)/CLOCKS_PER_SEC << endl;
    start = clock();
    selectionSort(a4s, num);
    end = clock();
    cout << "selectionSort: " << (double)(end-start)/CLOCKS_PER_SEC << endl;
    start = clock();
    insertionSort(a4i, num);
    end = clock();
    cout << "insertionSort: " << (double)(end-start)/CLOCKS_PER_SEC << endl;
    start = clock();
    mergeSort(a4m, t, 0, num - 1);
    end = clock();
    cout << "mergeSort: " << (double)(end-start)/CLOCKS_PER_SEC << endl;
    start = clock();
    quickSort(a4q, 0, num - 1);
    end = clock();
    cout << "quickSort: " << (double)(end-start)/CLOCKS_PER_SEC << endl;
    return 0;
}


测试结果

数据规模 1000 10000 100000 1000000 10000000 100000000
bubble sort 0.003 s 0.355 s 41.414 s / / /
selection sort 0.001 s 0.123 s 12.151 s / / /
insertion sort 0.002 s 0.224 s 22.881 s / /


merge sort 0 s 0.002 s 0.021 s 0.212 s 2.285 s


quick sort 0 s 0.002 s 0.017 s 0.175 s 1.826 s



文章知识点与官方知识档案匹配,可进一步学习相关知识

目录
相关文章
|
存储 人工智能 算法
数据结构与算法细节篇之最短路径问题:Dijkstra和Floyd算法详细描述,java语言实现。
这篇文章详细介绍了Dijkstra和Floyd算法,这两种算法分别用于解决单源和多源最短路径问题,并且提供了Java语言的实现代码。
1441 3
数据结构与算法细节篇之最短路径问题:Dijkstra和Floyd算法详细描述,java语言实现。
|
算法 数据处理 C语言
C语言中的位运算技巧,涵盖基本概念、应用场景、实用技巧及示例代码,并讨论了位运算的性能优势及其与其他数据结构和算法的结合
本文深入解析了C语言中的位运算技巧,涵盖基本概念、应用场景、实用技巧及示例代码,并讨论了位运算的性能优势及其与其他数据结构和算法的结合,旨在帮助读者掌握这一高效的数据处理方法。
862 1
|
存储 监控 安全
企业上网监控系统中红黑树数据结构的 Python 算法实现与应用研究
企业上网监控系统需高效处理海量数据,传统数据结构存在性能瓶颈。红黑树通过自平衡机制,确保查找、插入、删除操作的时间复杂度稳定在 O(log n),适用于网络记录存储、设备信息维护及安全事件排序等场景。本文分析红黑树的理论基础、应用场景及 Python 实现,并探讨其在企业监控系统中的实践价值,提升系统性能与稳定性。
793 1
|
存储 算法 搜索推荐
Python 中数据结构和算法的关系
数据结构是算法的载体,算法是对数据结构的操作和运用。它们共同构成了计算机程序的核心,对于提高程序的质量和性能具有至关重要的作用
606 153
|
存储 搜索推荐 算法
加密算法、排序算法、字符串处理及搜索算法详解
本文涵盖四大类核心技术知识。加密算法部分介绍了对称加密(如 AES)、非对称加密(如 RSA)、哈希摘要(如 SHA-2)、签名算法的特点及密码存储方案(加盐、BCrypt 等)。 排序算法部分分类讲解了比较排序(冒泡、选择、插入、归并、快排、堆排序)和非比较排序(计数、桶、基数排序)的时间复杂度、适用场景及实现思路,强调混合排序的工业应用。 字符串处理部分包括字符串反转的双指针法,及项目中用正则进行表单校验、网页爬取、日志处理的实例。 搜索算法部分详解了二分查找的实现(双指针与中间索引计算)和回溯算法的概念(递归 + 剪枝),以 N 皇后问题为例说明回溯应用。内容全面覆盖算法原理与实践
354 0
|
存储 监控 算法
基于跳表数据结构的企业局域网监控异常连接实时检测 C++ 算法研究
跳表(Skip List)是一种基于概率的数据结构,适用于企业局域网监控中海量连接记录的高效处理。其通过多层索引机制实现快速查找、插入和删除操作,时间复杂度为 $O(\log n)$,优于链表和平衡树。跳表在异常连接识别、黑名单管理和历史记录溯源等场景中表现出色,具备实现简单、支持范围查询等优势,是企业网络监控中动态数据管理的理想选择。
314 0
|
存储 搜索推荐 算法
算法系列之排序算法-堆排序
堆排序(Heap Sort)是一种基于堆数据结构的比较排序算法。它的时间复杂度为 $O(nlogn)$,并且是一种原地排序算法(即不需要额外的存储空间)。堆排序的核心思想是利用堆的性质来维护一个最大堆或最小堆,然后逐步将堆顶元素(最大值或最小值)取出,放到数组的末尾,最终得到一个有序的数组。
490 8
算法系列之排序算法-堆排序
|
存储 机器学习/深度学习 算法
C 408—《数据结构》算法题基础篇—链表(下)
408考研——《数据结构》算法题基础篇之链表(下)。
674 30
|
存储 算法 C语言
C 408—《数据结构》算法题基础篇—链表(上)
408考研——《数据结构》算法题基础篇之链表(上)。
962 25
|
存储 人工智能 算法
C 408—《数据结构》算法题基础篇—数组(通俗易懂)
408考研——《数据结构》算法题基础篇之数组。(408算法题的入门)
1047 23

热门文章

最新文章