一次性看懂10种排序算法(附代码)

常见的排序算法可以根据其实现原理分为以下几类,每种算法都有其特定的应用场景和性能特点:


1. 比较排序(基于元素比较)

  • 冒泡排序(Bubble Sort)

    • 原理:通过相邻元素交换,逐步将最大值“冒泡”到数组末尾。
    • 时间复杂度:平均和最坏情况 (O(n^2)),最好情况 (O(n))(已排序时)。
    • 特点:简单但效率低,稳定排序。
  • 选择排序(Selection Sort)

    • 原理:每次选择最小元素放到已排序区间的末尾。
    • 时间复杂度:始终 (O(n^2))。
    • 特点:不稳定,适合小规模数据。
  • 插入排序(Insertion Sort)

    • 原理:逐个将元素插入已排序区间的正确位置。
    • 时间复杂度:平均和最坏 (O(n^2)),最好 (O(n))(已排序时)。
    • 特点:稳定,适合小规模或部分有序数据。
  • 快速排序(Quick Sort)

    • 原理:分治法,选择一个基准元素,将数组分为两部分递归排序。
    • 时间复杂度:平均 (O(n \log n)),最坏 (O(n^2))(如已排序且基准选择不当)。
    • 特点:高效且原地排序,不稳定,实际应用广泛。
  • 归并排序(Merge Sort)

    • 原理:分治法,将数组分为两半分别排序后合并。
    • 时间复杂度:始终 (O(n \log n))。
    • 特点:稳定,但需要额外空间,适合链表或外部排序。
  • 堆排序(Heap Sort)

    • 原理:利用堆结构(完全二叉树)实现选择排序。
    • 时间复杂度:始终 (O(n \log n))。
    • 特点:原地排序,不稳定,适合大数据量。
  • 希尔排序(Shell Sort)

    • 原理:改进的插入排序,通过分组逐步缩小间隔排序。
    • 时间复杂度:(O(n \log n)) 到 (O(n^2)),取决于增量序列。
    • 特点:不稳定,适合中等规模数据。

2. 非比较排序(基于元素分布特性)

  • 计数排序(Counting Sort)

    • 原理:统计元素出现次数,适用于整数且范围较小的情况。
    • 时间复杂度:(O(n + k))((k) 为数据范围)。
    • 特点:稳定,需额外空间。
  • 桶排序(Bucket Sort)

    • 原理:将元素分到多个桶中,分别排序后合并。
    • 时间复杂度:平均 (O(n + k)),最坏 (O(n^2))。
    • 特点:适合均匀分布的数据。
  • 基数排序(Radix Sort)

    • 原理:按位数从低位到高位依次排序(通常基于计数排序)。
    • 时间复杂度:(O(n \times k))((k) 为最大位数)。
    • 特点:稳定,适合整数或字符串排序。

 3. 代码(10种排序)

#include "include/header.h"
using namespace std;

// random_shuffle
void random_shuffle(vector<int> &vec) {
    srand(time(NULL));
    for (int i = 0; i < vec.size(); i++) {
        int j = rand() % vec.size();
        swap(vec[i], vec[j]);
    }
}

void print(const vector<int> &vec) {
    for (int i = 0; i < vec.size(); i++) {
        cout << vec[i] << " ";
    }
    cout << endl;
}

// 冒泡排序
void bubble_sort(vector<int> &vec) {
    Timer t("bubble_sort");
    int len = vec.size();
    for (int i = 0; i < len; i++) {
        for (int j = 0; j < len - i - 1; j++) {
            if (vec[j] > vec[j + 1]) {
                swap(vec[j], vec[j + 1]);
            }
        }
    }
}

// 选择排序
void select_sort(vector<int> &vec) {
    Timer t("select_sort");
    int len = vec.size();
    for (int i = 0; i < len; i++) {
        int min_index = i;
        for (int j = i + 1; j < len; j++) {
            if (vec[j] < vec[min_index]) {
                min_index = j;
            }
        }
        swap(vec[i], vec[min_index]);
    }
}

// 插入排序
void insert_sort(vector<int> &vec) {
    Timer t("insert_sort");
    int len = vec.size();
    for (int i = 1; i < len; i++) {
        int j = i;
        int temp = vec[i];
        while (j > 0 && temp < vec[j - 1]) {
            vec[j] = vec[j - 1];
            j--;
        }
        vec[j] = temp;
    }
}

// 希尔排序
void shell_sort(vector<int> &vec) {
    Timer t("shell_sort");
    int len = vec.size();
    for (int gap = len / 2; gap > 0; gap /= 2) {
        for (int i = gap; i < len; i++) {
            int j = i;
            int temp = vec[i];
            while (j >= gap && temp < vec[j - gap]) {
                vec[j] = vec[j - gap];
                j -= gap;
            }
            vec[j] = temp;
        }
    }
}

// 归并排序
void merge_sort(vector<int> &vec) {
    Timer t("merge_sort");
    int len = vec.size();
    vector<int> temp(len);
    function<void(int, int)> merge_sort_range = [&](int left, int right) {
        if (left >= right)
            return;
        int mid = left + (right - left) / 2;
        merge_sort_range(left, mid);
        merge_sort_range(mid + 1, right);
        int i = left, j = mid + 1, k = 0;
        while (i <= mid && j <= right) {
            if (vec[i] <= vec[j]) {
                temp[k++] = vec[i++];
            } else {
                temp[k++] = vec[j++];
            }
        }
        while (i <= mid) {
            temp[k++] = vec[i++];
        }
        while (j <= right) {
            temp[k++] = vec[j++];
        }
        for (int i = 0; i < k; i++) {
            vec[left + i] = temp[i];
        }
    };
    merge_sort_range(0, len - 1);
}

// 快速排序
void quick_sort(vector<int> &vec) {
    Timer t("quick_sort");
    int len = vec.size();
    function<void(int, int)> quick_sort_range = [&](int left, int right) {
        if (left >= right)
            return;
        int i = left, j = right, pivot = vec[left + (right - left) / 2];
        while (i <= j) {
            while (vec[i] < pivot)
                i++;
            while (vec[j] > pivot)
                j--;
            if (i < j) {
                swap(vec[i++], vec[j--]);
            } else if (i == j) {
                i++;
            }
        }
        quick_sort_range(left, j);
        quick_sort_range(i, right);
    };
    quick_sort_range(0, len - 1);
}

// 堆排序
void heap_sort(vector<int> &vec) {
    Timer t("heap_sort");
    int len = vec.size();
    function<void(int, int)> heapify = [&](int start, int end) {
        int dad = start;
        int son = dad * 2 + 1;
        while (son <= end) {
            if (son + 1 <= end && vec[son] < vec[son + 1]) {
                son++;
            }
            if (vec[dad] > vec[son]) {
                return;
            } else {
                swap(vec[dad], vec[son]);
                dad = son;
                son = dad * 2 + 1;
            }
        }
    };
    for (int i = len / 2 - 1; i >= 0; i--) {
        heapify(i, len - 1);
    }
    for (int i = len - 1; i > 0; i--) {
        swap(vec[0], vec[i]);
        heapify(0, i - 1);
    }
}

// 计数排序
void count_sort(vector<int> &vec) {
    Timer t("count_sort");
    int len = vec.size();
    int max_val = *max_element(vec.begin(), vec.end());
    int min_val = *min_element(vec.begin(), vec.end());
    vector<int> count(max_val - min_val + 1, 0);
    for (int i = 0; i < len; i++) {
        count[vec[i] - min_val]++;
    }
    int index = 0;
    for (int i = 0; i < count.size(); i++) {
        while (count[i]-- > 0) {
            vec[index++] = i + min_val;
        }
    }
}

// 桶排序
void bucket_sort(vector<int> &vec) {
    Timer t("bucket_sort");
    int len = vec.size();
    int max_val = *max_element(vec.begin(), vec.end());
    int min_val = *min_element(vec.begin(), vec.end());
    int bucket_size = 5;
    int bucket_num = (max_val - min_val) / bucket_size + 1;
    vector<vector<int>> buckets(bucket_num);
    for (int i = 0; i < len; i++) {
        int index = (vec[i] - min_val) / bucket_size;
        buckets[index].push_back(vec[i]);
    }
    for (int i = 0; i < bucket_num; i++) {
        sort(buckets[i].begin(), buckets[i].end());
    }
    int index = 0;
    for (int i = 0; i < bucket_num; i++) {
        for (int j = 0; j < buckets[i].size(); j++) {
            vec[index++] = buckets[i][j];
        }
    }
}

// 获取某个数字在特定位数上的值
int getDigit(int number, int digit) {
    return (abs(number) / static_cast<int>(pow(10, digit))) % 10;
}

// 基数排序函数
void radix_sort(vector<int> &arr) {
    Timer t("radix_sort");

    if (arr.empty())
        return;

    // 找到最大绝对值
    int maxAbsValue = *max_element(arr.begin(), arr.end(), [](int a, int b) {
        return abs(a) < abs(b);
    });

    // 计算最大位数
    int maxDigits = 0;
    while (maxAbsValue > 0) {
        maxAbsValue /= 10;
        maxDigits++;
    }

    // 进行基数排序
    for (int digit = 0; digit < maxDigits; digit++) {
        vector<vector<int>> buckets(20); // 20个桶,-9到9的数字

        // 将数字放入相应的桶中
        for (int number : arr) {
            int d = getDigit(number, digit);
            if (number < 0) {
                buckets[9 + d].push_back(number); // 负数放在前面
            } else {
                buckets[d].push_back(number); // 正数放在后面
            }
        }

        // 清空原数组并按桶的顺序重新填充
        arr.clear();
        for (const auto &bucket : buckets) {
            for (int number : bucket) {
                arr.push_back(number);
            }
        }
    }
}

int main(int argc, char const *argv[]) {
    vector<int> vec = ReadBigArrayFromFile(10000);

    // bubble_sort(vec);
    random_shuffle(vec);
    bubble_sort(vec);

    // select_sort(vec);
    random_shuffle(vec);
    select_sort(vec);

    // insert_sort(vec);
    random_shuffle(vec);
    insert_sort(vec);

    // shell_sort(vec);
    random_shuffle(vec);
    shell_sort(vec);

    // radix_sort(vec);
    random_shuffle(vec);
    radix_sort(vec);

    // merge_sort(vec);
    random_shuffle(vec);
    merge_sort(vec);

    // quick_sort(vec);
    random_shuffle(vec);
    quick_sort(vec);

    // heap_sort(vec);
    random_shuffle(vec);
    heap_sort(vec);

    // count_sort(vec);
    random_shuffle(vec);
    count_sort(vec);

    // bucket_sort(vec);
    random_shuffle(vec);
    bucket_sort(vec);

    return 0;
}

 运行结果:

Read vector size: 10000
函数 bubble_sort 执行时间: 674464 微秒
函数 select_sort 执行时间: 222103 微秒
函数 insert_sort 执行时间: 151351 微秒
函数 shell_sort 执行时间: 2780 微秒
函数 radix_sort 执行时间: 125 微秒
函数 merge_sort 执行时间: 3115 微秒
函数 quick_sort 执行时间: 2148 微秒
函数 heap_sort 执行时间: 4681 微秒
函数 count_sort 执行时间: 2563 微秒
函数 bucket_sort 执行时间: 7571 微秒

4. 其他或混合排序

  • TimSort(Python、Java 默认排序算法):结合归并排序和插入排序,优化了实际数据的有序性。
  • 内省排序(Introsort):结合快速排序、堆排序和插入排序,避免快速排序的最坏情况。

5. 选择排序算法的考虑因素

  • 数据规模:小数据用简单排序(如插入排序),大数据用 (O(n \log n)) 算法(如快排、归并)。
  • 内存限制:原地排序算法(如快排、堆排序)适合内存紧张场景。
  • 稳定性需求:如归并排序、计数排序适合需要保持相等元素顺序的场景。
  • 数据特性:非比较排序在特定数据分布下效率更高(如整数、范围有限)。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

There Is No Code

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

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

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

打赏作者

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

抵扣说明:

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

余额充值