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

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

前言


这篇文章将会介绍常见的排序算法(使用 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



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

目录
相关文章
|
2月前
|
存储 人工智能 算法
数据结构与算法细节篇之最短路径问题:Dijkstra和Floyd算法详细描述,java语言实现。
这篇文章详细介绍了Dijkstra和Floyd算法,这两种算法分别用于解决单源和多源最短路径问题,并且提供了Java语言的实现代码。
83 3
数据结构与算法细节篇之最短路径问题:Dijkstra和Floyd算法详细描述,java语言实现。
|
2月前
|
机器学习/深度学习 存储 缓存
数据结构与算法学习十:排序算法介绍、时间频度、时间复杂度、常用时间复杂度介绍
文章主要介绍了排序算法的分类、时间复杂度的概念和计算方法,以及常见的时间复杂度级别,并简单提及了空间复杂度。
33 1
数据结构与算法学习十:排序算法介绍、时间频度、时间复杂度、常用时间复杂度介绍
|
2月前
|
存储 算法 Java
Set接口及其主要实现类(如HashSet、TreeSet)如何通过特定数据结构和算法确保元素唯一性
Java Set因其“无重复”特性在集合框架中独树一帜。本文解析了Set接口及其主要实现类(如HashSet、TreeSet)如何通过特定数据结构和算法确保元素唯一性,并提供了最佳实践建议,包括选择合适的Set实现类和正确实现自定义对象的hashCode()与equals()方法。
35 4
|
2月前
|
搜索推荐 算法
数据结构与算法学习十四:常用排序算法总结和对比
关于常用排序算法的总结和对比,包括稳定性、内排序、外排序、时间复杂度和空间复杂度等术语的解释。
22 0
数据结构与算法学习十四:常用排序算法总结和对比
|
2月前
|
存储 缓存 分布式计算
数据结构与算法学习一:学习前的准备,数据结构的分类,数据结构与算法的关系,实际编程中遇到的问题,几个经典算法问题
这篇文章是关于数据结构与算法的学习指南,涵盖了数据结构的分类、数据结构与算法的关系、实际编程中遇到的问题以及几个经典的算法面试题。
36 0
数据结构与算法学习一:学习前的准备,数据结构的分类,数据结构与算法的关系,实际编程中遇到的问题,几个经典算法问题
|
2月前
|
机器学习/深度学习 搜索推荐 算法
探索数据结构:初入算法之经典排序算法
探索数据结构:初入算法之经典排序算法
|
2月前
|
算法 Java 索引
数据结构与算法学习十五:常用查找算法介绍,线性排序、二分查找(折半查找)算法、差值查找算法、斐波那契(黄金分割法)查找算法
四种常用的查找算法:顺序查找、二分查找(折半查找)、插值查找和斐波那契查找,并提供了Java语言的实现代码和测试结果。
25 0
|
26天前
|
C语言
【数据结构】栈和队列(c语言实现)(附源码)
本文介绍了栈和队列两种数据结构。栈是一种只能在一端进行插入和删除操作的线性表,遵循“先进后出”原则;队列则在一端插入、另一端删除,遵循“先进先出”原则。文章详细讲解了栈和队列的结构定义、方法声明及实现,并提供了完整的代码示例。栈和队列在实际应用中非常广泛,如二叉树的层序遍历和快速排序的非递归实现等。
122 9
|
17天前
|
存储 算法
非递归实现后序遍历时,如何避免栈溢出?
后序遍历的递归实现和非递归实现各有优缺点,在实际应用中需要根据具体的问题需求、二叉树的特点以及性能和空间的限制等因素来选择合适的实现方式。
22 1
|
4天前
|
存储 缓存 算法
在C语言中,数据结构是构建高效程序的基石。本文探讨了数组、链表、栈、队列、树和图等常见数据结构的特点、应用及实现方式
在C语言中,数据结构是构建高效程序的基石。本文探讨了数组、链表、栈、队列、树和图等常见数据结构的特点、应用及实现方式,强调了合理选择数据结构的重要性,并通过案例分析展示了其在实际项目中的应用,旨在帮助读者提升编程能力。
25 5