Jednym z najprostszych sposobów porządkowania jest technika stosowana przy sortowaniu listów: Listy rozkładane są do różnych przegródek. O tym, do której z nich trafi koperta, decydują różne fragmenty adresu. Na przykład dla listów zagranicznych są przeznaczone przegródki oznaczone nazwami państw. Przy obecnie obowiązującym systemie oznaczania adresów kodami, ten sposób sortowania przesyłek krajowych jest bardzo uciążliwy - liczba różnych kodów jest tak duża, że nie można pozwolić sobie na sortowanie tą metodą, przyjmując za "nazwę przegródki" numer kodowy odbiorcy. Naszkicowana metoda nazywa się porządkowaniem kubełkowym lub koszykowym, w zależności od tego, jak są nazwane pojemniki, do których wrzuca się porządkowane elementy (obiekty). By zbiór został całkowicie uporządkowany, kubełki wypełnione w pierwszym etapie, muszą być opróżniane w następnym według kolejności przypisanych im nazw, dając kolejność elementów rozważanego zbioru. 1
Zastosujemy teraz algorytm kubełkowy do uporządkowania liter tworzących słowo ABRAKADABRA. To słowo ma pięć różnych liter: A, B, D, K i R. Zakładamy więc pięć kubełków, oznaczamy je tymi literami i ustawiamy w takiej kolejności, w jakiej te litery występują w alfabecie. W pierwszym kroku algorytmu przeglądamy to słowo i rozdzielamy jego litery do kubełków. W drugim kroku tworzymy już uporządkowany ciąg, opróżniając kubełki w kolejności ich ustawienia. Kolejne wystąpienia tej samej litery są oznaczone kolejnymi indeksami, by można było łatwo odnaleźć poszczególne litery w kubełkach, a później w uporządkowanym ciągu. Litery są umieszczane w kubełkach w kolejności występowania w słowie. Kubełki nie są domknięte od dołu - są one opróżniane od dołu. Dzięki temu litery opuszczają kubełki w takiej samej kolejności, w jakiej do nich trafiają. Przypomina to znaną z życia kolejkę, w której nie obowiązują żadne przywileje. 2
Kolejka jest jedną z podstawowych struktur danych występujących w algorytmach. Jest to struktura FIFO: First Input First Output. Ten sposób opróżniania kubełków gwarantuje, że poszczególne wystąpienia danej litery są w takiej samej kolejności w słowie ABRAKADABRA i w uporządkowanym ciągu liter. A 1 B 1 R 1 A 2 K 1 A 3 D 1 A 4 B 2 R 2 A 5 A 1 A 2 A 3 A 4 A 5 B 1 B 2 D 1 K 1 R 1 R 2 A 5 A 4 A 3 A 2 B 2 R 2 A 1 B 1 D 1 K 1 R 1 A B D K R 3
Porządkowanie pozycyjne Czy można rozszerzyć kubełkowe porządkowanie liter na porządkowanie całych słów? Aby porządkować słowa, należy najpierw określić, które z dwóch danych słów powinno wystąpić wcześniej. Najprościej jest przyjąć naturalny porządek między słowami, nazywamy porządkiem leksykograficznym lub słownikowym, czyli taki, jaki jest w słownikach i w encyklopediach. Można go zdefiniować następująco: jeśli dwa słowa mają jednakową długość, to szukamy w nich pierwszej pozycji, na której się różnią i wcześniejsze jest to słowo, które ma na tej pozycji wcześniejszą literę - np. ARAB jest wcześniejsze od ARAK, gdyż B występuje w alfabecie przed K, a DRAB jest wcześniejsze niż KRAB, gdyż D poprzedza K w alfabecie; jeśli słowa mają nierówną długość, to albo szukamy pierwszej pozycji, na której się różnią i litera na tej pozycji decyduje o miejscu ustawienia słowa (podobnie jak w przypadku słów o równej długości) - np. słowo BAR jest wcześniejsze od BRDA, gdyż A poprzedza R, albo jedno słowo jest częścią drugiego, wtedy występuje w słowniku przed każdym słowem, w którym jest zawarte na początku np. BAR poprzedza BARD i BARK. 4
Porządkowanie słów o jednakowej długości Jeśli słowa są jednakowej długości i różnią się jedynie na ostatniej pozycji to ich pozycja w słowniku jest wyznaczona przez kolejność ostatnich liter. Kolejność słów różniących się na dwóch ostatnich pozycjach jest wyznaczona przez kolejność par liter na tych pozycjach. Porządkowanie słów o jednakowej długości polega na porządkowaniu ich od końca, pozycja po pozycji, z zastosowaniem do każdej pozycji algorytmu kubełkowego. Takie postępowanie nosi nazwę algorytmu porządkowania pozycyjnego: porządkowane obiekty występują w postaci pozycyjnej i porządkowanie odbywa się względem każdej pozycji. Ideę porządkowania pozycyjnego wprowadził Herman Hollerith, który pod koniec XIX wieku budował maszyny do automatyzacji przetwarzania wyników spisu ludności. Założona wtedy firma przekształciła się w koncern IBM (International Business Machines). 5
Porządkowanie słów nierównej długości W tym przypadku słowa należy także przeglądać od ostatnich liter. Należy jedynie rozstrzygnąć, gdzie względem dłuższych słów należy umieścić krótsze. W algorytmie najpierw powinny być zrównane pierwsze litery wszystkich słów - wszystkie słowa należy jakby dosunąć do lewej strony. W przypadku krótszego słowa, gdy porządkujemy względem pozycji, która wykracza poza jego prawą skrajną literę dopisujemy to słowo do tworzonego w danej iteracji ciągu wszystkich słów. Krótsze słowa, czyli takie, które nie zawierają litery na analizowanej pozycji w danej iteracji są cyklicznie przepisywane na koniec ciągu słów podczas jego przeglądania. 6
niebieski: litery, według których będzie przebiegać następna iteracja. czerwony: te same litery (w następnej kolumnie!!!) po uporządkowaniu względem nich. BAR BAR BAR PO BAR BAR PO PO PO BAR BARD BARD RADAR BARD RADAR BARD RADAR PO BARD RADAR BARD RADAR PO RADAR 7
Algorytm porządkowania pozycyjnego Dane: Ciąg elementów, z których każdy jest układem pozycji wypełnionych znakami, dozwolonymi dla poszczególnych pozycji. Wynik: Uporządkowanie danego ciągu zgodnie z leksykograficzna relacją, zdefiniowaną odpowiednio do kolejności pozycji i porządku znaków, które mogą wypełniać poszczególne pozycje. Krok 1: Dla kolejnych pozycji w elementach, w kolejności od najmniej znaczącej do najbardziej znaczącej, wykonaj kroki 2, 3 i 4. Krok 2: Załóż kubełki dla każdego możliwego znaku, jaki może wystąpić na bieżącej pozycji w porządkowanych elementach. Ustaw te kubełki zgodnie z porządkiem tych znaków. Krok 3: Dla wszystkich elementów z porządkowanego ciągu wykonaj: jeśli rozważana pozycja w elemencie jest pusta, to dopisz ten element do końca porządkowanego ciągu, w przeciwnym razie - włóż ten element do kubełka oznaczonego znakiem stojącym na rozważanej pozycji. Krok 4: Dla kolejnych kubełków: przenieść elementy z kubełka na koniec porządkowanego ciągu w takiej samej kolejności, w jakiej były w nim umieszczane. 8
Złożoność porządkowania pozycyjnego Zarówno w algorytmach porządkowania kilku liczb, jak i w algorytmach porządkowania bąbelkowego i przez wybór, podstawową operacją wykonywaną na elementach jest ich porównywanie parami. Dlatego ocenę efektywności tych algorytmów pod względem liczby wykonywanych operacji podajemy w zależności od liczby porównań. W algorytmach porządkowania kubełkowego i pozycyjnego nie są wykonywane żadne operacje porównywania między porządkowanymi elementami. Podstawową operacją jest natomiast przemieszczenie elementu, z porządkowanego ciągu do kubełka (w kroku 3) lub na koniec ciągu (w krokach 3 i 4). 9
Oznaczmy przez l maksymalną długość porządkowanych elementów, przez m liczbę różnych znaków, jakie mogą wystąpić na pozycji i w porządkowanych elementach (i=1, 2,..., l), przez n - liczbą porządkowanych elementów, a przez k j - liczbę znaków w j-tym elemencie (j=1, 2,..., n). Z dyskusji powyżej wynika, że w algorytmie porządkowania pozycyjnego wykonujemy: K=k 1 +k 2 +...+k n umieszczeń porządkowanych elementów; M=2(m 1 +m 2 +...+m l ) operacji na kubełkach: otwierania kubełków w kroku 2 i dołączania kubełków do ciągu porządkowanych elementów w kroku 4. Załóżmy, ze porządkujemy słowa języka polskiego. Wtedy złożoność algorytmu porządkowania pozycyjnego wynosi K+2*32l wszystkich działań, gdzie K jest sumaryczną długością słów, a l jest maksymalną długością słowa. Dla uproszczenia przyjęliśmy tutaj, że na każdej pozycji w słowie może wystąpić każda z 32 liter alfabetu polskiego. Algorytm pozycyjnego porządkowania jest optymalny w tym sensie, że każda pozycja w każdym elemencie jest sprawdzana tylko raz. 10
11
12