Algoritmus řazení segmentů (Java, Python, C/C++ Příklady kódu)

Co je bucket Sort?

Bucket sort, často nazývaný bin sort, je metoda srovnávacího třídění, která přijímá nesetříděné pole jako vstup a jako výsledek vytváří setříděné pole. Tato metoda funguje tak, že se prvky rozdělí do několika segmentů a každý z těchto segmentů se seřadí jednotlivě podle libovolného třídícího algoritmu, jako je vkládání. Poté se všechny segmenty sloučí a vytvoří setříděné pole.

Třídění segmentů se běžně používá, když jsou prvky-

  1. Hodnoty s pohyblivou řádovou čárkou
  2. Rovnoměrně distribuováno v rozsahu

Časová složitost třídění segmentů závisí na počtu použitých segmentů a rovnoměrnosti rozložení vstupů. Zatímco různé třídící algoritmy jako např shell sort, sloučit řazení, hromadné řazení a rychlé řazení může dosáhnout časové složitosti v nejlepším případě O(n*logn), algoritmus pro třídění segmentů může dosáhnout stejného v lineární časové složitosti nebo O(n).

Řazení segmentů se řídí metodou rozptylu a sběru. Při použití tohoto přístupu jsou prvky rozmístěny do odpovídajících segmentů, roztříděny v segmentech a jako poslední krok shromážděny do seřazeného pole. Tento přístup s rozptylem je diskutován v následující části

Scatter-Gather-Approach

Rozsáhlé a složité problémy mohou být občas náročné na řešení. Rozptylový přístup se pokouší vyřešit takové problémy rozdělením celé datové sady do shluků. Poté je každý shluk adresován samostatně a vše se znovu spojí, aby se získala konečná odpověď.

Takto algoritmus třídění segmentu implementuje metodu rozptylu:

Scatter-Gather-Approach

Jak funguje třídění kbelíků

Základní pracovní princip třídění lopatek je následující:

  1. Vytvoří se sada prázdných kbelíků. Na základě různých zásad se počet segmentů může lišit.
  2. Ze vstupního pole vložte každý prvek do příslušného segmentu.
  3. Roztřiďte ty kbelíky jednotlivě.
  4. Spojte setříděné segmenty a vytvořte jediné výstupní pole.

Podrobné pracovní kroky jsou uvedeny v následujících částech.

Pseudo kód

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

Metoda 1: Algoritmus třídění segmentů pro plovoucí desetinnou čárku Numbers

Algoritmus třídění segmentu pro čísla s plovoucí desetinnou čárkou v rozsahu od 0.0 do 1.0:

Krok 1) Vytvořte deset (10) prázdných segmentů tak, že první segment bude obsahovat čísla v rozsahu [0.0, 0.1). Druhý segment pak bude obsahovat [0.1, 0.2) a tak dále.

Krok 2) Pro každý prvek pole:

      A. Vypočítejte index segmentu pomocí vzorce:
      index segmentu= no_of_buckets *prvek_pole
      b. Vložte prvek do bucketu[bucket_index]

Krok 3) Seřaďte každý segment jednotlivě pomocí řazení vložení.

Krok 4) Spojte všechny segmenty do jednoho pole.

Podívejme se na příklad třídění kbelíku. V tomto příkladu seřadíme následující pole pomocí algoritmu třídění bucket-

Algoritmus třídění segmentů pro plovoucí desetinnou čárku Numbers

Krok 1) Nejprve si vytvoříme 10 prázdných kbelíků. První segment bude obsahovat čísla mezi [0.0, 0.1). Potom bude druhý segment obsahovat čísla mezi [0.1, 0.2) a tak dále.

Algoritmus třídění segmentů pro plovoucí desetinnou čárku Numbers

Krok 2) Pro každý prvek pole vypočítáme index bucketu a umístíme prvek do tohoto bucketu.

Index segmentu lze vypočítat pomocí vzorce:
              bucket_index= no_of_buckets*array_element

Výpočet indexu segmentu:
a) 0.78
      bucket_index = no_of_buckets*array_element
                   = 10 * 0.78
                   = 7.8
Proto bude prvek 0.78 uložen na kbelíku[podlaha(7.8)] nebo kbelíku[7].

Algoritmus třídění segmentů pro plovoucí desetinnou čárku Numbers

b) 0.17
      bucket_index = no_of_buckets * prvek pole
                   = 10 * 0.17
                   = 1.7

Prvek pole 0.17 bude uložen na bucket[floor(1.7)] nebo bucket[1].

Algoritmus třídění segmentů pro plovoucí desetinnou čárku Numbers

c) 0.39
      bucket_index = no_of_buckets * prvek pole
                   = 10 * 0.39
                   = 3.9
   0.39 bude uloženo na bucket[floor(3.9)] nebo bucket[3].

Algoritmus třídění segmentů pro plovoucí desetinnou čárku Numbers

Po iteraci přes všechny prvky pole budou segmenty následující:

Algoritmus třídění segmentů pro plovoucí desetinnou čárku Numbers

Krok 3) Poté bude každý segment setříděn pomocí řazení vložení. Po operaci třídění by výstup byl:

Algoritmus třídění segmentů pro plovoucí desetinnou čárku Numbers

Krok 4) V posledním kroku budou segmenty zřetězeny do jednoho pole. Toto pole bude seřazeným výsledkem vstupu.

Každý segment bude zřetězen k výstupnímu poli. Například zřetězení prvků druhého kbelíku:

Algoritmus třídění segmentů pro plovoucí desetinnou čárku Numbers

Zřetězení posledních prvků segmentu bude následující:

Algoritmus třídění segmentů pro plovoucí desetinnou čárku Numbers

Po zřetězení bude výsledné pole požadované tříděné pole.

Algoritmus třídění segmentů pro plovoucí desetinnou čárku Numbers

Program třídění kbelíků v C/C++

Vstup:

//Bucket Sort Program in C/C++
//For not having 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: \n";
 for (int i = 0; i< array_size; i++)
 cout<<input[i]<<" ";
return 0;
}

Výstup:

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

Program třídění kbelíků v Python

Vstup:

# Bucket Sort Program in Python
# For not having 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))

Výstup:

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

Kbelík Seřadit Java

Vstup:

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]+" ");
        }
    }
}

Výstup:

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

Metoda 2: Algoritmus třídění segmentu pro celočíselné prvky

Algoritmus třídění segmentu pro vstup, který obsahuje čísla mimo rozsah [0.0, 1.0], se trochu liší od předchozího algoritmus. Kroky potřebné pro tento případ jsou následující -

Krok 1) Najděte maximální a minimální prvky.

Krok 2) Vyberte počet segmentů n a inicializujte tyto segmenty jako prázdné.

Krok 3) Vypočítejte rozsah nebo rozsah každého segmentu pomocí vzorce:
               span = (maximum - minimum)/n

Krok 4) Pro každý prvek pole:

    1. Vypočítejte index segmentu:
                   bucket_index = (element - minimum)/span
    2. Vložte prvek do bucket[bucket_index]

Krok 5) Seřaďte každý segment pomocí řazení vložení.

Krok 6) Spojte všechny segmenty do jednoho pole.

Podívejme se na příklad tohoto algoritmu řazení segmentů. V tomto příkladu seřadíme následující pole pomocí algoritmu třídění bucket-

Algoritmus třídění segmentu pro celočíselné prvky

Krok 1) V prvním kroku je potřeba najít maximum a minimum prvků daného pole. Pro tento příklad je maximum 24 a minimum 1.

Krok 2) Nyní musíme vybrat počet prázdných kbelíků, n. V tomto příkladu vezmeme 5 kbelíků. Poté je inicializujeme jako prázdné.

Krok 3) Rozpětí každého segmentu je třeba vypočítat podle následujícího vzorce:
               span = (maximum-minimum)/n = (24-1)/5 = 4;

První segment tedy bude obsahovat čísla v rozsahu [0, 5). Druhý segment bude obsahovat čísla v [5, 10) a tak dále.

Algoritmus třídění segmentu pro celočíselné prvky

Krok 4) Pro každý prvek pole vypočítáme index bucketu a umístíme prvek do tohoto bucketu. Index segmentu lze vypočítat pomocí vzorce:
               bucket_index = (element - minimum)/span

Výpočet indexu segmentu:

    a) 11bucket_index = (prvek – minimum)/rozpětí
                       =(11-1)/4
                       =2

Prvek 11 tak bude uložen v kbelíku[2].

Algoritmus třídění segmentu pro celočíselné prvky

    b) 9
    bucket_index = (prvek – minimum)/rozpětí
                       =(9-1)/4
                       =2

Poznámka: Protože 9 je hraniční prvek pro bucket[1], je třeba jej přidat do bucketu[1] namísto přidávání do stejného segmentu předchozího prvku.

Algoritmus třídění segmentu pro celočíselné prvky

Po provedení operací pro každý prvek budou kbelíky následující:

Algoritmus třídění segmentu pro celočíselné prvky

Krok 5) Nyní bude každý segment setříděn pomocí řazení vložení. Kbelíky po třídění-

Algoritmus třídění segmentu pro celočíselné prvky

Krok 6) V posledním kroku budou segmenty zřetězeny do jednoho pole. Že řada bude seřazeným výsledkem vstupu.

Algoritmus třídění segmentu pro celočíselné prvky

Program třídění kbelíků v C/C++

Vstup:

#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; i < input.size(); i++)
    cout <<input[i]<<" ";
  return 0;
}

Výstup:

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

Program třídění kbelíků v Python

Vstup:

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:\n", input)

Výstup:

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

Kbelík Seřadit Java

Vstup:

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 + " ");
        }
    }
}

Výstup:

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

Klady a zápory

Klady Nevýhody
Provádějte rychlejší výpočty Ve srovnání s jinými algoritmy zabírá více místa
Lze jej použít jako externí metodu třídění Funguje špatně, když data nejsou rovnoměrně distribuována
Kbelíky lze zpracovávat nezávisle

Analýza složitosti třídění segmentů

Časová složitost třídění bucket

  • Nejlepší složitost případu:Pokud jsou všechny prvky pole předem rovnoměrně rozmístěny a roztříděny, vyžadovalo by to čas O(n) k rozptýlení prvků do odpovídajících segmentů. Poté roztřiďte každý kbelík pomocí řazení řazení by stálo O(k). Celková složitost by tedy byla O(n+k).
  • Průměrná složitost případu:Pro průměrné případy předpokládáme, že vstupy jsou rovnoměrně rozděleny. Algoritmus bucket sorting tedy dosahuje lineární časové složitosti O(n+k). Zde je čas O(n) potřebný pro rozptýlení prvků a čas O(k) pro třídění těchto prvků pomocí vkládání.
  • Složitost nejhoršího případu:V nejhorším případě nebudou prvky rovnoměrně rozmístěny a soustředěny do jednoho nebo dvou konkrétních kbelíků. V takovém případě bude třídění segmentů fungovat jako a algoritmus pro třídění bublin. V nejhorším případě by tedy časová složitost třídění segmentů byla O(n^2).

Prostorová složitost třídění lopatek

Prostorová složitost třídění segmentu je O(n*k). Zde n je počet prvků a k je počet požadovaných segmentů.