Алгоритм сортировки сегментов (Java, Python, С /C++ Code Примеры)

⚡ Умное резюме

Сортировка по корзинам распределяет входные элементы по нескольким корзинам, сортирует каждую корзину независимо и объединяет их для получения итогового отсортированного массива.

  • 🪣 Основная идея: Сортировка по корзинам распределяет значения по корзинам, сортирует каждую из них, а затем объединяет их в порядке возрастания.
  • 📊 Лучше всего подходит: Сортировка по корзинам лучше всего работает с равномерно распределенными числами с плавающей запятой в диапазоне [0.0, 1.0] или равномерно распределенными целыми числами.
  • Сложность времени: В среднем и наилучшем случаях время выполнения достигает O(n+k) линейного времени; в наихудшем случае оно снижается до O(n²).
  • Преимущества: Обработка данных по группам может осуществляться параллельно, что подходит для внешней сортировки больших наборов данных.
  • 🧪 Реализация: Code в C, C++, Python и Java демонстрирует как варианты с плавающей запятой, так и целочисленные варианты.

Что такое групповая сортировка?

Сортировка по корзинам, часто называемая сортировкой по контейнерам, — это метод сортировки распределения на основе сравнения, который принимает на вход несортированный массив и выдает на выходе отсортированный массив. Этот метод распределяет элементы по нескольким корзинам и сортирует каждую корзину по отдельности, используя другой алгоритм сортировки, например, сортировку вставками. Затем все корзины объединяются, образуя окончательный отсортированный массив.

Сортировка по корзинам обычно используется, когда элементами являются:

  1. Значения с плавающей запятой
  2. Равномерно распределен в известном диапазоне

Временная сложность алгоритма сортировки по корзинам зависит от количества используемых корзин и равномерности распределения входных данных. В то время как другие алгоритмы сортировки, такие как… сортировка по скорлупе, сортировка слиянием, пирамидальная сортировка и быстрая сортировка Для достижения наилучшей временной сложности O(n*logn) алгоритм сортировки по корзинам может достичь линейной временной сложности O(n) при благоприятных условиях.

Сортировка по корзинам использует подход «рассеивание-сбор». Элементы распределяются по соответствующим корзинам, сортируются внутри каждой корзины и на заключительном этапе собираются в отсортированный массив. Этот подход «рассеивание-сбор» обсуждается в следующем разделе.

Метод рассеяния-сбора

Крупномасштабные и сложные задачи порой бывает трудно решить напрямую. Метод «рассеянного сбора данных» решает такие проблемы, разделяя весь набор данных на кластеры. Каждый кластер обрабатывается отдельно, а результаты объединяются для получения окончательного ответа.

Вот как алгоритм сортировки по корзинам реализует метод рассеяния-сбора:

Метод рассеяния-сбора

Как работает сегментная сортировка

Основной принцип работы сортировки по корзинам следующий:

  1. Создается набор пустых контейнеров. В зависимости от выбранной политики количество контейнеров может варьироваться.
  2. Из входного массива каждый элемент помещается в соответствующую ему ячейку.
  3. Каждый сегмент сортируется индивидуально с использованием вторичного алгоритма сортировки.
  4. Отсортированные сегменты объединяются для получения единого выходного массива.

Прозвище Code

Start
Create N empty buckets
For each array element:
    Calculate bucket index
    Put that element into the corresponding bucket
For each bucket:
    Sort elements within each bucket
Merge all the elements from each bucket
Output the sorted array
End

Метод 1. Алгоритм сортировки сегментов для чисел с плавающей запятой Numbers

Алгоритм сортировки по корзинам для чисел с плавающей запятой в диапазоне [0.0, 1.0]:

Шаг 1) Создайте десять (10) пустых корзин. Первая корзина содержит числа в диапазоне [0.0, 0.1], вторая корзина содержит [0.1, 0.2) и так далее.

Шаг 2) Для каждого элемента массива:

  • а. Рассчитайте индекс корзины, используя формулу:
    bucket_index = no_of_buckets * array_element
  • b. Вставьте элемент в контейнер bucket[bucket_index]

Шаг 3) Отсортируйте каждую корзину по отдельности, используя сортировку вставками.

Шаг 4) Объедините все корзины в один отсортированный массив.

Рассмотрим пример сортировки по корзинам. В этом примере мы отсортируем следующий массив:

Алгоритм сортировки сегментов для чисел с плавающей запятой Numbers

Шаг 1) Сначала создадим 10 пустых корзин. В первой корзине будут храниться числа в диапазоне [0.0, 0.1], во второй — [0.1, 0.2], и так далее.

Алгоритм сортировки сегментов для чисел с плавающей запятой Numbers

Шаг 2) Для каждого элемента массива вычислите индекс корзины и поместите элемент в эту корзину.

Индекс корзины рассчитывается по формуле:
        bucket_index = no_of_buckets * array_element

Расчет индекса ковша:
а) 0.78
      bucket_index = no_of_buckets * array_element
              = 10 * 0.78
              = 7.8
Следовательно, элемент 0.78 хранится в bucket[floor(7.8)] или bucket[7].

Алгоритм сортировки сегментов для чисел с плавающей запятой Numbers

б) 0.17
      bucket_index = no_of_buckets * array_element
              = 10 * 0.17
              = 1.7

Элемент массива 0.17 хранится в bucket[floor(1.7)] или bucket[1].

Алгоритм сортировки сегментов для чисел с плавающей запятой Numbers

в) 0.39
      bucket_index = no_of_buckets * array_element
              = 10 * 0.39
              = 3.9
0.39 хранится в bucket[floor(3.9)] или bucket[3].

Алгоритм сортировки сегментов для чисел с плавающей запятой Numbers

После перебора всех элементов массива, содержимое сегментов будет выглядеть следующим образом:

Алгоритм сортировки сегментов для чисел с плавающей запятой Numbers

Шаг 3) Затем каждая ячейка сортируется с помощью сортировки вставками. После операции сортировки получается следующий результат:

Алгоритм сортировки сегментов для чисел с плавающей запятой Numbers

Шаг 4) На заключительном этапе все элементы объединяются в один массив. Этот массив представляет собой отсортированный результат обработки входных данных.

Каждый сегмент добавляется к выходному массиву. Например, конкатенация элементов второго сегмента:

Алгоритм сортировки сегментов для чисел с плавающей запятой Numbers

Ниже показано соединение последних элементов корзины:

Алгоритм сортировки сегментов для чисел с плавающей запятой Numbers

После конкатенации полученный массив представляет собой желаемый отсортированный массив.

Алгоритм сортировки сегментов для чисел с плавающей запятой Numbers

Программа сортировки сегментов на C/C++

Входной сигнал:

//Bucket Sort Program in C/C++
//For values without integer parts
#include <bits/stdc++.h>
#define BUCKET_SIZE 10
using namespace std;
void bucketSort(float input[], int array_size)
{
  vector <float>bucket[BUCKET_SIZE];
  for (int i = 0; i < array_size; i++) {
    int index = BUCKET_SIZE*input[i];
    bucket[index].push_back(input[i]);
  }
  for (int i = 0; i < BUCKET_SIZE; i++)
    sort(bucket[i].begin(), bucket[i].end());
  int out_index = 0;
  for (int i = 0; i < BUCKET_SIZE; i++)
    for (int j = 0; j < bucket[i].size(); j++)
      input[out_index++] = bucket[i][j];
}
int main()
{
  float input[]={0.78,0.17,0.39,0.26,0.72,0.94,0.21,0.12,0.23,0.69};
  int array_size = sizeof(input)/sizeof(input[0]);

  bucketSort(input, array_size);
  cout <<"Sorted Output: 
";
  for (int i = 0; i< array_size; i++)
    cout<<input[i]<<" ";
  return 0;
}

Выход:

Sorted Output:
0.12 0.17 0.21 0.23 0.26 0.39 0.69 0.72 0.78 0.94

Программа сортировки сегментов в Python

Входной сигнал:

# Bucket Sort Program in Python
# For values without integer parts
def bucketSort(input):
    output = []
    bucket_size = 10
    for bucket in range(bucket_size):
        output.append([])
    for element in input:
        index = int(bucket_size * element)
        output[index].append(element)
    for bucket in range(bucket_size):
        output[bucket] = sorted(output[bucket])
    out_index = 0
    for bucket in range(bucket_size):
        for element in range(len(output[bucket])):
            input[out_index] = output[bucket][element]
            out_index += 1
    return input

input = [0.78, 0.17, 0.39, 0.26, 0.72, 0.94, 0.21, 0.12, 0.23, 0.69]
print("Sorted Output:")
print(bucketSort(input))

Выход:

Sorted Output:
[0.12, 0.17, 0.21, 0.23, 0.26, 0.39, 0.69, 0.72, 0.78, 0.94]

Ведро сортировки Java

Входной сигнал:

import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
public class BucketSort {
    private static final int BUCKET_SIZE = 10;
    public static void bucketSort(float[] input, int arraySize) {
        List<Float>[] bucket = new ArrayList[BUCKET_SIZE];
        for (int i = 0; i < arraySize; i++) {
            int index = (int)(BUCKET_SIZE * input[i]);
            if (bucket[index] == null) {
                bucket[index] = new ArrayList<>();
            }
            bucket[index].add(input[i]);
        }
        for (int i = 0; i < BUCKET_SIZE; i++) {
            if (bucket[i] != null) {
                Collections.sort(bucket[i]);
            }
        }
        int outIndex = 0;
        for (int i = 0; i < BUCKET_SIZE; i++) {
            if (bucket[i] != null) {
                for (float value: bucket[i]) {
                    input[outIndex++] = value;
                }
            }
        }
    }
    public static void main(String[] args) {
        float[] input = {0.78f,0.17f,0.39f,0.26f,0.72f,0.94f,0.21f,0.12f,0.23f,0.69f};
        int arraySize = input.length;
        bucketSort(input, arraySize);
        System.out.println("Sorted Output:");
        for (int i = 0; i < arraySize; i++) {
            System.out.print(input[i]+" ");
        }
    }
}

Выход:

Sorted Output:
0.12 0.17 0.21 0.23 0.26 0.39 0.69 0.72 0.78 0.94

Метод 2. Алгоритм групповой сортировки для целочисленных элементов

Алгоритм сортировки по корзинам для входных данных, содержащих числа, выходящие за пределы диапазона [0.0, 1.0], немного отличается от предыдущего. алгоритмДля решения данной задачи необходимы следующие шаги:

Шаг 1) Найдите максимальный и минимальный элементы в массиве.

Шаг 2) Выберите количество корзин n и инициализируйте их пустыми.

Шаг 3) Рассчитайте диапазон или диапазон каждого сегмента, используя формулу:
        span = (maximum - minimum) / n

Шаг 4) Для каждого элемента массива:

  • 1. Рассчитайте индекс корзины:
            bucket_index = (element - minimum) / span
  • 2. Вставьте элемент в контейнер bucket[bucket_index]

Шаг 5) Отсортируйте каждый сегмент, используя сортировку вставками.

Шаг 6) Объедините все сегменты в один массив.

Рассмотрим пример алгоритма сортировки по корзинам. В этом примере мы отсортируем следующий массив:

Алгоритм сортировки сегментов для целочисленных элементов

Шаг 1) На первом шаге мы находим максимальный и минимальный элементы заданного массива. В этом примере максимум равен 24, а минимум — 1.

Шаг 2) Далее мы выбираем количество пустых ячеек, n. В этом примере мы используем 5 ячеек и инициализируем их как пустые.

Шаг 3) Размер каждого контейнера рассчитывается по формуле:
        span = (maximum - minimum) / n = (24 - 1) / 5 = 4

Таким образом, в первом контейнере находятся числа в диапазоне [0, 5], во втором — [5, 10), и так далее.

Алгоритм сортировки сегментов для целочисленных элементов

Шаг 4) Для каждого элемента массива вычислите индекс корзины и поместите элемент в эту корзину. Индекс корзины вычисляется по формуле:
        bucket_index = (element - minimum) / span

Расчет индекса ковша:

а) 11
bucket_index = (element – ​​minimum) / span
        = (11-1) / 4
        = 2

Таким образом, элемент 11 хранится в корзине[2].

Алгоритм сортировки сегментов для целочисленных элементов

б) 9
bucket_index = (element – ​​minimum) / span
        = (9-1) / 4
        = 2

Примечание: Поскольку 9 является граничным элементом для bucket[1], он добавляется к bucket[1], а не помещается в тот же bucket, что и предыдущий элемент.

Алгоритм сортировки сегментов для целочисленных элементов

После выполнения операций для каждого элемента, корзины выглядят следующим образом:

Алгоритм сортировки сегментов для целочисленных элементов

Шаг 5) Теперь каждая группа сортируется с помощью сортировки вставками. Группы после сортировки:

Алгоритм сортировки сегментов для целочисленных элементов

Шаг 6) На заключительном этапе корзины объединяются в один массив. массив — это отсортированный результат входных данных.

Алгоритм сортировки сегментов для целочисленных элементов

Программа сортировки сегментов на C/C++

Входной сигнал:

#include<bits/stdc++.h>
using namespace std;
void bucketSort(vector < double > & input, int No_Of_Buckets)
{
  double max_value = * max_element(input.begin(), input.end());
  double min_value = * min_element(input.begin(), input.end());
  double span = (max_value - min_value) / No_Of_Buckets;
  vector<vector <double>> output;
  for (int i = 0; i < No_Of_Buckets; i++)
    output.push_back(vector <double>());
  for (int i = 0; i < input.size(); i++)
  {
    double difference = (input[i] - min_value) / span
     - int((input[i] - min_value) / span);
    if (difference == 0 && input[i] != min_value)
      output[int((input[i] - min_value) / span) - 1].push_back(input[i]);
    else
      output[int((input[i] - min_value) / span)].push_back(input[i]);
  }
  for (int i = 0; i < output.size(); i++)
  {
    if (!output[i].empty())
      sort(output[i].begin(), output[i].end());
  }
  int index = 0;
  for (vector <double> & bucket: output)
  {
    if (!bucket.empty())
    {
      for (double i: bucket)
      {
        input[index] = i;
        index++;
      }
    }
  }
}
int main()
{
  vector <double> input ={11,9,21,8,17,19,13,1,24,12};
  int No_Of_Buckets = 5;
  bucketSort(input, No_Of_Buckets);
  cout<<"Sorted Output:";
  for (int i=0; i < input.size(); i++)
    cout <<input[i]<<" ";
  return 0;
}

Выход:

Sorted Output:1 8 9 11 12 13 17 19 21 24

Программа сортировки сегментов в Python

Входной сигнал:

def bucketSort(input, No_Of_Buckets):
    max_element = max(input)
    min_element = min(input)
    span = (max_element - min_element) / No_Of_Buckets
    output = []
    for bucket in range(No_Of_Buckets):
        output.append([])
    for element in range(len(input)):
        diff = (input[element] - min_element) / span - int(
            (input[element] - min_element) / span
        )
        if diff == 0 and input[element] != min_element:
            output[int((input[element] - min_element) / span) - 1].append(
                input[element]
            )
        else:
            output[int((input[element] - min_element) / span)].append(input[element])
    for bucket in range(len(output)):
        if len(output[bucket]) != 0:
            output[bucket].sort()
    index = 0
    for bucket in output:
        if bucket:
            for element in bucket:
                input[index] = element
                index = index + 1
input = [11, 9, 21, 8, 17, 19, 13, 1, 24, 12]
No_Of_Buckets = 5
bucketSort(input, No_Of_Buckets)
print("Sorted Output:
", input)

Выход:

Sorted Output:
[1, 8, 9, 11, 12, 13, 17, 19, 21, 24]

Ведро сортировки Java

Входной сигнал:

import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
public class BucketSort {
    public static void bucketSort(List < Double > input, int No_Of_Buckets) {
        double max_value = Collections.max(input);
        double min_value = Collections.min(input);
        double span =(max_value - min_value) / No_Of_Buckets;
        List<List<Double>> output = new ArrayList<>();
        for (int i = 0; i < No_Of_Buckets; i++) {
            output.add(new ArrayList<>());
        }
        for (Double value: input) {
            double difference = (value - min_value) / span - ((value - min_value) / span);
            if (difference == 0 && value != min_value) {
                output.get((int)((value - min_value) / span) - 1).add(value);
            } else {
                output.get((int)((value - min_value) / span)).add(value);
            }
        }
        for (List <Double> bucket: output) {
            if (!bucket.isEmpty()) {
                Collections.sort(bucket);
            }
        }
        int index = 0;
        for (List <Double> bucket: output) {
            if (!bucket.isEmpty()) {
                for (Double value: bucket) {
                    input.set(index,value);
                    index++;
                }
            }
        }
    }
    public static void main(String[] args) {
        List <Double> input = new ArrayList<>();
        input.add(11.0);
        input.add(9.0);
        input.add(21.0);
        input.add(8.0);
        input.add(17.0);
        input.add(19.0);
        input.add(13.0);
        input.add(1.0);
        input.add(24.0);
        input.add(12.0);
        int No_Of_Buckets = 5;
        bucketSort(input, No_Of_Buckets);
        System.out.println("Sorted Output:");
        for (Double value: input) {
            System.out.print(value + " ");
        }
    }
}

Выход:

Sorted Output:
1.0 8.0 9.0 11.0 12.0 13.0 17.0 19.0 21.0 24.0

Плюсы и минусы сортировки по категориям

Плюсы Минусы
Выполняет более быстрые вычисления на равномерно распределенных данных. Занимает больше места по сравнению с алгоритмами сортировки на месте.
Может использоваться в качестве внешнего метода сортировки для больших наборов данных. Плохо работает, когда данные распределены неравномерно.
Обработка отдельных блоков данных может осуществляться как независимо, так и параллельно. Требуется предварительное знание диапазона и распределения данных.

Анализ сложности сегментной сортировки

Сложность времени сортировки ведра

  • лучшая сложность дела: Если все элементы массива равномерно распределены и предварительно отсортированы внутри каждой ячейки, то для распределения элементов по соответствующим ячейкам потребуется время O(n). Затем сортировка каждой ячейки осуществляется с помощью сортировка вставок Стоимость составляет O(k). Таким образом, общая сложность равна O(n+k).
  • Средняя сложность дела: В усредненных случаях мы предполагаем, что входные данные распределены равномерно. Таким образом, алгоритм сортировки по корзинам достигает линейной временной сложности O(n+k). Здесь для распределения элементов требуется O(n) времени, а для их сортировки с помощью сортировки вставками — O(k) времени.
  • Наихудшая сложность случая: В худшем случае элементы распределены неравномерно и концентрируются в одном или двух сегментах. В этом случае сортировка сегментами (Bucket Sort) начинает вести себя аналогично... алгоритм пузырьковой сортировкиСледовательно, в худшем случае временная сложность сортировки по корзинам составляет O(n²).

Пространственная сложность сортировки ведром

Пространственная сложность сортировки по корзинам составляет O(n*k). Здесь n — количество элементов, а k — количество корзин, необходимых для их хранения во время сортировки.

Часто задаваемые вопросы (FAQ)

Сортировка по группам (Bucket Sort) полезна, когда входные значения равномерно распределены в известном диапазоне, особенно числа с плавающей запятой в интервале [0.0, 1.0]. Она обеспечивает линейное время обработки таких данных, но показывает низкую эффективность при работе с кластерными или неизвестными распределениями.

Сортировка по корзинам считается стабильной, если алгоритм внутренней сортировки, используемый внутри каждой корзины, также стабилен. Сортировка вставками сохраняет относительный порядок равных элементов, поэтому стандартная реализация сортировки по корзинам с использованием сортировки вставками считается стабильной.

Сортировка по корзинам группирует элементы по диапазону значений и сортирует каждую корзину с помощью другого алгоритма. Сортировка по разрядам группирует числа по разрядам и использует внутри себя сортировку подсчетом. Сортировка по корзинам отдает предпочтение равномерно распределенным числам с плавающей запятой; сортировка по разрядам отдает предпочтение целым числам фиксированной ширины или строкам.

Наихудшая временная сложность сортировки по корзинам составляет O(n²). Это происходит, когда все входные элементы попадают в одну корзину, что заставляет внутреннюю сортировку (обычно сортировку вставками) вести себя квадратично. Равномерное распределение позволяет избежать этого сценария.

Да. Для обработки отрицательных значений необходимо найти как минимум, так и максимум, а затем вычислить индекс корзины, используя формулу (элемент – минимум) / диапазон. Это смещает отрицательные значения в пространство неотрицательных индексов, и стандартная логика сортировки корзин продолжается без изменений.

Платформы на основе искусственного интеллекта, такие как VisuAlgo, Algorithm Visualizer и ChatGPT, генерируют пошаговые инструкции. tracЭти инструменты помогают учащимся визуализировать сортировку по корзинам. Они анимируют этапы рассеивания, сортировки и сбора, что упрощает понимание математических вычислений для индексации по корзинам и логики разделения.

Системы рекомендаций на основе искусственного интеллекта анализируют размер набора данных, распределение значений и ограничения памяти, чтобы предложить подходящий алгоритм. Для равномерно распределенных чисел с плавающей запятой такие системы отдают предпочтение сортировке по корзинам (Bucket Sort). Для диапазонов смешанных целых чисел они могут предложить вместо этого быструю сортировку (Quick Sort) или сортировку по разрядам (Radix Sort).

Подведем итог этой публикации следующим образом: