桶排序 基数排序 希尔排序

本文详细介绍了桶排序、基数排序和希尔排序的过程、稳定性、时间复杂度以及适用场景,特别强调了基数排序在大数据和字符串排序中的优势。
摘要由CSDN通过智能技术生成

首先, 让我们了解一下,Let go

桶排序

目录

桶排序

桶排序的过程

稳定性

时间复杂度

适合场景

Code

基数排序

基数排序的流程

稳定性

时间复杂度

适合场景

Code 

希尔排序

希尔排序的流程

稳定性 

时间复杂度

使用场景

Code

总结


桶排序的过程

1. 设置一个定量的数组作为空桶

2.遍历序列, 并将元素一一对应到相应的桶中

3.对每一个不是空的桶进行排序

4.从不是空的桶的讲元素放回原来的序列

稳定性

如果使用较稳定的内定排序,同时,也不会改变相应的顺序,我们就可以桶排序是一个稳定的排序算法。

时间复杂度

它的平均时间复杂度处于k \approx n是为 O(n) 最坏的情况处于O(n^2) 将值域平均分成 n块 + 排序 + 重新合并元素

适合场景

 如果元素不多,那么桶排序就成为了YYDS,数据分布均匀的情况。

我们直接上代码

Code

#include<bits/stdc++.h>
using namespace std;
const int N = 100010;

int n, w, a[N];
vector<int> bucket[N];

void insertion_sort(vector<int>& A) {
  for (int i = 1; i < A.size(); ++i) {
    int key = A[i];
    int j = i - 1;
    while (j >= 0 && A[j] > key) {
      A[j + 1] = A[j];
      --j;
    }
    A[j + 1] = key;
  }
}

void bucket_sort() {
  int bucket_size = w / n + 1;
  for (int i = 0; i < n; ++i) {
    bucket[i].clear();
  }
  for (int i = 1; i <= n; ++i) {
    bucket[a[i] / bucket_size].push_back(a[i]);
  }
  int p = 0;
  for (int i = 0; i < n; ++i) {
    insertion_sort(bucket[i]);
    for (int j = 0; j < bucket[i].size(); ++j) {
      a[++p] = bucket[i][j];
    }
  }
}

#include <iostream>  

#include <algorithm>  

using namespace std;  

void bucketSort(int arr[], int n, int k) {  

    int max_val = *max_element(arr, arr+n); // 找到数组中的最大值  

    int bucket[k]; // 创建桶数组  

    for (int i = 0; i < k; i++) {  

        bucket[i] = 0; // 将桶数组初始化为0  

    }  

    for (int i = 0; i < n; i++) {  

        int index = (arr[i] * k) / max_val; // 根据最大值和当前值计算出应该放在哪个桶中  

        bucket[index]++; // 在对应的桶中计数  

    }  

    for (int i = 0, j = 0; i < k; i++) {  

        while (bucket[i] > 0) { // 将桶中的数据按顺序放回原数组中  

            arr[j++] = i; // 将当前桶中的数据赋值给原数组  

            bucket[i]--; // 将桶中的计数减1  

        }  

    }  

}  

int main() {  

    int arr[] = {3, 1, 4, 1, 5, 9, 2, 6, 5, 3}; // 待排序的数组  

    int n = sizeof(arr) / sizeof(arr[0]); // 数组长度  

    int k = 5; // 桶的大小  

    bucketSort(arr, n, k); // 桶排序  

    for (int i = 0; i < n; i++) {  

        cout << arr[i] << " "; // 输出排好序的数组  

    }  

    return 0;  

}

基数排序

基数排序的流程

1.先找出原始数组arr最大值,求出最大值有多少个位数digitLen

2.对原始数组每个位(个位、十位、百位、千位、...)分别进行计数排序,即digitLen次最外层循环

3.每个位计数排序完成后,将结果复制到原始数组arr中,并且清除原始计数countArr数组后,再进行下一个位的计数排序,直到完成所有位的排序,则完成整个数组排序

稳定性

它按照低位先排序,然后收集;再按照高位排序,然后再收集;依次类推,直到最高位。基数排序法是属于稳定性的排序。在某些时候,基数排序法的效率高于其它的稳定性排序法。

时间复杂度

时间复杂度为O(nlog(r)m),其中r为所采取的基数,而m为堆数。

适合场景

基数排序的适用场景包括:

  1. 大数据排序:随着大数据时代的到来,处理海量数据面临挑战。在这种情况下,传统的排序算法可能无法满足需求。基数排序通过将数据按照不同的位数进行排序,可以有效地处理大规模数据集。其时间复杂度为O(kn),其中k是数字的位数,n是数据集的大小。因此,基数排序在大数据排序场景中具有明显的优势。
  2. 字符串排序:除了对数字进行排序,基数排序也可以用于字符串排序。在某些应用中,例如字典排序、电话号码排序等,我们需要对字符串进行排序。基数排序可以按照字符串的每个字符进行排序,从而实现字符串的排序功能。这种应用场景在信息检索、数据分析等领域非常常见。

Code 

#include <algorithm>
#include <stack>
#include <tuple>
#include <vector>

using std::copy;  // from <algorithm>
using std::make_tuple;
using std::stack;
using std::tie;
using std::tuple;
using std::vector;

typedef unsigned int u32;
typedef unsigned int* u32ptr;

void MSD_radix_sort(u32ptr first, u32ptr last) {
  const size_t maxW = 0x100000000llu;
  const u32 maxlogW = 32;  // = log_2 W

  const u32 W = 256;  // 计数排序的值域
  const u32 logW = 8;
  const u32 mask = W - 1;  // 用位运算替代取模,详见下面的 key 函数

  u32ptr tmp =
      (u32ptr)calloc(last - first, sizeof(u32));  // 计数排序用的输出空间

  typedef tuple<u32ptr, u32ptr, u32> node;
  stack<node, vector<node>> s;
  s.push(make_tuple(first, last, maxlogW - logW));

  while (!s.empty()) {
    u32ptr begin, end;
    size_t shift, length;

    tie(begin, end, shift) = s.top();
    length = end - begin;
    s.pop();

    if (begin + 1 >= end) continue;  // elements <= 1

    // 计数排序
    u32 cnt[W] = {};
    auto key = [](const u32 x, const u32 shift) { return (x >> shift) & mask; };

    for (u32ptr it = begin; it != end; ++it) ++cnt[key(*it, shift)];
    for (u32 value = 1; value < W; ++value) cnt[value] += cnt[value - 1];

    // 求完前缀和后,计算相同关键字的元素范围
    if (shift >= logW) {
      s.push(make_tuple(begin, begin + cnt[0], shift - logW));
      for (u32 value = 1; value < W; ++value)
        s.push(make_tuple(begin + cnt[value - 1], begin + cnt[value],
                          shift - logW));
    }

    u32ptr it = end;
    do {
      --it;
      --cnt[key(*it, shift)];
      tmp[cnt[key(*it, shift)]] = *it;
    } while (it != begin);

    copy(tmp, tmp + length, begin);
  }
}

希尔排序

希尔排序的流程

  1. 将待排序序列分为若干子序列(每个子序列的元素在原始数组中间距相同);
  2. 对这些子序列进行插入排序;
  3. 减小每个子序列中元素之间的间距,重复上述过程直至间距减少为 

稳定性 

希尔排序是一种不稳定的排序算法。

时间复杂度

希尔排序的最优时间复杂度为O(n) 

使用场景

  1. 当数据规模较大,但数据量不均匀,且分布不平时,希尔排序的效果会比插入排序更好。
  2. 当数据量非常大,且需要快速排序时,希尔排序可以作为一种选择。

Code

template <typename T>
void shell_sort(T array[], int length) {
  int h = 1;
  while (h < length / 3) {
    h = 3 * h + 1;
  }
  while (h >= 1) {
    for (int i = h; i < length; i++) {
      for (int j = i; j >= h && array[j] < array[j - h]; j -= h) {
        std::swap(array[j], array[j - h]);
      }
    }
    h = h / 3;
  }
}

总结

排序算法(英语:Sorting algorithm)是一种将一组特定的数据按某种顺序进行排列的算法。排序算法多种多样,性质也大多不同。进制无论多少,都可以,不仅只有10进制,100 1000 10000都可以,合理利用排序,一起享受ac的快乐。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值