C++语言程序设计——12 排序算法-桶排序

目录

* for循环去重元素

for 循环去重的思路在于找出首次出现的唯一元素,然后按照顺序查找是否有重复。该方法适合小规模,大规模需要使用桶排序或哈希表。双重 for 循环如下代码:

cpp 复制代码
#include <iostream>
using namespace std;

int main()
{
    int a[] = {64,12,64,11,30,3,95,0,40,0,9};
    int n = sizeof(a) / sizeof(a[0]);      // 计算数组长度
    cout << a[0] << " ";         // 先输出第一个元素
    for(int i = 1; i < n; i++)   // 从第二个元素开始遍历,即 i = 1开始
    {
        int temp = a[i];    // temp 是当前要检查的元素
        for(int j = i-1; j >= 0; j--)    // 向左查找是否已经出现过相同的元素
        {
            if(temp==a[j]){
                break;     // 如果前面有相同的元素,则跳出循环
            }
            if(temp!=a[j] && j==0){       // 如果查找到最前面(j==0)都没找到相同的,则输出当前元素
                cout << temp << " ";
            }
        }
    }
    return 0;
}        

时间复杂度

(1)最坏时间复杂度:无重复元素,每次循环需要比较前 i - 1 个元素,例如数组:a[ ] = {1, 2, 3, 4, 5}:

i = 1,需要比较 a[1] = 2 和 a[0] = 1,即 1 次比较。

i = 2,需要比较 a[2] = 3 和 a[1] = 2、a[0] = 1,即 2 次比较。

......

比较次数 = 1 + 2 + ... + (n - 1) = (1 + (n - 1) )n / 2 = n (n - 1) / 2。

所以,最坏时间复杂度为 O(n2)。

(2)最好时间复杂度:

最坏时间复杂度:所有元素重复,每次循环 1 次比较就 break 退出循环。

比较次数 = n - 1 。

所以,最好时间复杂度为 O(n)。

(3)平均时间复杂度:

关注最高阶项,忽略常数和低阶项,所以平均时间复杂度为 O(n2)。
空间复杂度:O(1)

一、桶排序的效率

桶是一种空间换时间(占用更多内存,但速度快)的数据结构思想,通过下标映射元素值,一次访问即可完成检查。每个桶内的排序可以选择不同的算法,例如,插入排序、快速排序、归并排序等。最后,再将所有桶合并。

要注意,桶排序和堆排序不是一个概念,桶排序是 " 分桶排序合并 ",堆排序是 " 建堆取最值调整 "(完全二叉树)。另外,桶排序也不属于严格意义上的分治法,桶排序是" 分桶排序合并 ",而分治法是 "分治合"。

之前通过双层 for 循环去重元素,平均时间复杂度是 O(n2) ,效率低;而通过桶排序平均时间复杂度可以达到 O(n + k)(k为桶数量),效率高。

桶排序所需空间复杂度为 O(n+k),n 是每个桶内存储元素的平均时间, k 是桶所需空间。

桶排序不适合数据范围很大的情况,以免设置桶的数量过多。此外,如果数据元素分布不均匀,桶排序效率会下降,例如,当所有元素都集中在少数几个桶或集中在一个桶时,时间复杂度是 O(n2) 。

二、分桶过程

桶排序常结合数组、vector、链表等实现,桶数量由值域范围和桶大小决定。

复制代码
桶数量 = (最大值 - 最小值) / 桶大小 + 1

例如,通过桶排序方式:

cpp 复制代码
int a[] = {4,40,44,49,75,40,10,38,1,29};

最小值为 1 ,最大值为 75 ,假设每个桶大小为 10 ,则需要 8 个桶:

复制代码
桶数量 = (75-1)/10 + 1 = 8
cpp 复制代码
vector<vector<int>> buckets(8);

每个桶装的元素如下,进行分配:

然后,进行每个桶内排序,如果桶内元素较少可以使用【插入排序】,元素较多使用【快速排序】或【归并排序】:

最终合并结果:

复制代码
1, 4, 10, 29, 38, 40, 40, 44, 49, 75

示例代码如下,最后用 sortedArr 数组存储排序后的结果,遍历该数组输出:

cpp 复制代码
#include <iostream>
using namespace std;

int main() 
{
    int arr[] = {70,31,88,1,55,42,7,38,13,49,95,16,25,9,29,38,5,35,22,66};
    int n = sizeof(arr) / sizeof(arr[0]);    // 计算原数组元素个数

    for (int i = 0; i < n; i++) {
        cout << arr[i] << " ";
    }

    // 手动找出数组中的最大值(确定桶的遍历范围)
    int maxVal = arr[0];
    for (int i = 1; i < n; i++) {
        if (arr[i] > maxVal) {
            maxVal = arr[i];
        }
    }

    // 创建桶数组
    int bucket[1001] = {0};      // 初始化为0

    // 统计每个数字出现的次数
    for (int i = 0; i < n; i++) {
        bucket[arr[i]]++;
    }

    // 按顺序存入排序结果数组
    int sortedArr[100] = {0}; // 存储排序后的结果
    int sortedLen = 0;        // 记录排序后的元素个数
    for (int i = 0; i <= maxVal; i++) {
        // 按出现次数添加到结果数组
        while (bucket[i] > 0) {
            sortedArr[sortedLen] = i;
            sortedLen++;
            bucket[i]--;
        }
    }

    for (int i = 0; i < sortedLen; i++) {
        cout << sortedArr[i] << " ";
    }
    return 0;
}
相关推荐
MM_MS2 小时前
Halcon变量控制类型、数据类型转换、字符串格式化、元组操作
开发语言·人工智能·深度学习·算法·目标检测·计算机视觉·视觉检测
独自破碎E3 小时前
【二分法】寻找峰值
算法
mit6.8243 小时前
位运算|拆分贪心
算法
ghie90903 小时前
基于MATLAB的TLBO算法优化实现与改进
开发语言·算法·matlab
恋爱绝缘体13 小时前
2020重学C++重构你的C++知识体系
java·开发语言·c++·算法·junit
wuk9983 小时前
VSC优化算法MATLAB实现
开发语言·算法·matlab
Z1Jxxx4 小时前
加密算法加密算法
开发语言·c++·算法
乌萨奇也要立志学C++4 小时前
【洛谷】递归初阶 三道经典递归算法题(汉诺塔 / 占卜 DIY/FBI 树)详解
数据结构·c++·算法
vyuvyucd4 小时前
C++引用:高效编程的别名利器
算法
鱼跃鹰飞5 小时前
Leetcode1891:割绳子
数据结构·算法