Přihrádkové třídění řetězců

Transkript

Přihrádkové třídění řetězců
Přihrádkové třídění řetězců
Aleš Novák, ADS I., 30.6.2011
Ke třídění množiny prvků, které nabývají hodnot převoditelných na přirozená čísla v omezeném, „rozumnémÿ rozsahu, můžeme použít přihrádkové třídění – bucketsort. Bucketsort prochází
vstupní množinu a spočítá pro každou podmnožinu prvků stejné hodnoty „přihrádkuÿ ve výstupním, již setříděném poli.
Máme-li N prvků o rozsahu 0 . . . R ve vstupním poli „vstupÿ, algoritmus v pseudo-C kódu vypadá
takto:
1: vstup [1..N], vysledek [1..N], prihradky [0..R+1]
2: prihradky = [0,0,0..0]
3: for i in 1..N:
4:
prihradky [vstup [i] + 1] ++
5: prihradky [0] = 0
6: for r in 1..R:
7:
prihradky [r] += prihradky [r-1]
8: for i in 1..N:
9:
vysledek [prihradky [vstup [i]]++] = vstup [i]
Vidíme, že používáme ještě jedno pole velikosti N pro výstup a pole četností prvků dané hodnoty
o velikosti R. Podle limitů cyklů je vidět časová složitost O(N + R).
Cyklus na řádcích 3–4 počítá četnost jednotlivých hodnot prvků. Cyklus na řádcích 5–7 četnost
hodnoty prvku nahrazuje sumou četností prvků s menší hodnotou, tím se z údaje „kolikrát se prvek
s bezprostředně nižší hodnotou vyskytuje ve vstupním poliÿ stane údaj „kde začíná přihrádka
prvků s touto hodnotou ve výstupním poliÿ.
V posledním cyklu procházíme vstupní pole zepředu a přihrádky plníme také zepředu, takže vzájemné pořadí prvků stejné hodnoty se nemění – třídění je stabilní.
Poznámka: někde (např. ve zbytku tohoto textu a v ukázkovém C programu) je použita podoba
algoritmu, která místo začátků počítá konce přihrádek a plní je pak odzadu. Na složitost algoritmu
to nemá vliv.
Třídění řetězců
Pokud máme třídit množinu řetězců, složených z L prvků – znaků, jejichž hodnoty mají „rozumnýÿ rozsah, bychom mohli využít toho, že bucketsort je stabilní, a setřídit řetězce nejprve
podle nejméně významného, tj. L-tého znaku, pak podle (L − 1)-tého až nakonec podle 1. znaku,
který je nejvýznamnější. Každý znak by se prošel právě jednou, časová složitost je tedy jako při
provedení L samostatných bucketsortů - O(L · (N + R)).
Pokud ale řetězce nabývají délek 1 . . . L, je situace mírně komplikovanější. Pokud bychom všechny
řetězce zarovnali „mezeramiÿ na délku L a použili algoritmus z předchozího odstavce, může být
časová složitost až O(N 2 ) (pokud budememe mít N − 1 řetězců délky 1 a jeden délky N ). Tj.
většinu času strávíme počítáním četnosti mezer.
Jak to udělat s lineární časovou složitostí? Budeme opět porovnávat od nejméně významného,
L-tého znaku - ovšem jen u těch řetězců, které mají alespoň L znaků. Pro ten účel nejprve vstupní
množinu rozdělíme bucketsortem na podmnožiny Pi , kde množina Pi obsahuje znaky délky i,
budeme postupovat od největšího i k nejmenšímu a postupně vytvářet výstupní pole. Po kroku
pro přihrádku Pi bude dočasná výstupní množina obsahovat všechny řetězce délky minimálně i
setříděné podle i, i + 1, i + 2, ..., L znaku. Postup v pseudo-pseudo kódu bude takovýto:
1: vstup [1..N], vysledek [1..N], prihradky [0..R],
vstup_dle_delek [1..N], prihradky_delek [1..L],
vysledek_docasny [1..N]
2: prihradky_delek = [0,0,0..0]
3: for i in 1..N:
4:
prihradky_delek [delka (vstup[i]) ++
5: for k in 2..L:
6:
prihradky_delek [k] += prihradky_delek [k-1]
7: for i in N..1:
8:
vstup_dle_delek [-- prihradky_delek [vstup [i]]] = vstup [i]
9: vysledek = []
10: k = L
11: while k > 0:
12:
vysledek = concat (
vstup_dle_delek [prihradky_delek[k-1]..prihradky_delek [k]],
vysledek)
13:
prihradky = [0,0,0..0]
14:
15:
for i in 1..delka (vysledek):
prihradky [vysledek [i][k]] ++
16:
17:
for r in 1..R:
prihradky [r] += prihradky [r-1]
18:
19:
for i in N..1:
vysledek_docasny [-- prihradky [vysledek [i]]] = vysledek [i]
20:
21:
vysledek = vysledek_docasny
k --
Vidíme, že třídění provádíme
L-krát, každý znak v každém řetězci se prochází právě jednou, časová
PN
složitost je O(RL + i delka(vstup[i])), tedy je lineární s celkovým počtem znaků všech řetězců.
Paměťová náročnost je N + R + L, takže je třeba zaručit, že také maximální délka řetězce bude
„rozumnáÿ.
Správnost algoritmu nahlédneme indukcí - tvrdíme, že po i-tém kroku je dočasná výstupní množina
setříděná podle znaku (L − i + 1) až L. Po prvním kroku to je triviálně vidět, protože dočasná
výstupní množina obsahuje pouze řetězce z PL , setříděné podle L. znaku. Při i-tém kroku se
před dočasný výstupní seznam připojí množina PL−i+1 a dohromady se třídí podle (L − i + 1)-
tého znaku. Pokud dva řetězce mají hodnotu znaku stejnou, zachovává se jejich vzájemné pořadí
(bucketsort je stabilní), takže se udržuje jejich slovníkové uspořádání z přechozího kroku. Pokud
je některý z nich z množiny PL−i+1 , je správně umístěn více vepředu, protože ve slovníkovém
uspořádání řetězec ABC předchází řetězci ABCD.
Přikládám ukázkové řešení v jazyce C. Použil jsem dvě pole velikosti N , která prohazuji, jedno
vždy obsahuje dočasně setříděnou množinu řetězců délky k + 1, do druhého pole jde setříděné
zřetězení množiny Pk a množiny z prvního pole. Je třeba zřetězovat je v tomto pořadí (protože
řetězec ABC má ve výstupu předcházet řetězci ABCD).
Ukázkový postup algoritmu
Nakonec uvádím ukázku třídění řetězců: abc, andalusan, b, cadmium, calcium, dac, kleptoman,
zetor, zita. Každá dvojice tabulek představuje jeden krok algoritmu. Levá tabulka obsahuje
vstupní množiny, dvojitá čára odděluje množinu PL+1−i pro i-tý krok nahoře, dočasný výsledek
dole. Pravá tabulka obsahuje dočasný výsledek po konci kroku. Podbarvené jsou znaky, podle
kterých se setřiďuje.
a
k
n
l
d
e
a
p
l
t
u
o
s
m
a
k
n
l
d
e
a
p
l
t
u
o
s
m
c
c
a
k
a
a
n
l
l
d
d
e
c
m
a
p
i
i
l
t
u
u
u
o
c
c
k
a
a
a
l
n
l
d
e
d
c
m
p
a
i
i
t
l
z
k
c
c
a
e
l
a
a
n
t
e
l
d
d
o
p
c
m
a
z
c
c
a
z
k
i
a
a
n
e
l
t
l
d
d
t
e
a
c
m
a
o
p
i
i
l
r
t
n
n
a
a
m
m
s
m
u
u
o
u
r
t
i
i
l
a
a
m
m
m
s
a
a
a
a
a
a
k
n
l
d
e
a
p
l
t
u
o
s
m
n
n
a
k
n
l
d
e
a
p
l
t
u
o
s
m
n
n
c
c
k
a
a
a
l
n
l
d
e
d
c
m
p
a
i
i
t
l
u
u
o
u
n
n
k
c
c
a
l
a
a
n
e
l
d
d
p
c
m
a
t
i
i
l
c
c
a
z
k
a
a
n
e
l
l
d
d
t
e
c
m
a
o
p
z
a
c
c
z
k
i
n
a
a
e
l
t
d
l
d
t
e
o
u
u
u
m
m
m
s
u
u
u
m
m
s
a
n
o
m
a
n
a
n
n
a
a
c
m
o
p
l
i
i
r
t
n
n
a
a
m
m
m
s
o
u
u
u
i
i
l
r
t
a
a
m
m
m
s
n
n
a
a
n
n
a
n
a
n
u
u
u
m
m
s
a
n
o
m
a
n
u
u
u
s
m
m
a
n
o
m
a
n
d
a
z
a
c
c
z
k
d
a
a
c
k
c
z
z
a
b
i
n
a
a
e
l
c
c
t
d
l
d
t
e
a
b
n
a
l
a
i
e
c
c
d
d
e
l
t
t
a
a
c
m
o
p
a
m
p
c
a
o
l
i
i
r
t
l
i
t
i
u
u
u
s
m
m
a
o
m
a
u
u
o
u
s
m
m
m
n
n
a
n
a
n
r
b
d
c
c
a
z
z
k
a
a
a
a
b
e
i
l
n
c
d
l
c
t
t
e
d
m
c
i
i
o
a
p
a
r
t
l
u
u
m
m
o
u
m
s
a
a
n
n
d
a
a
c
k
c
z
z
d
c
c
a
z
z
k
a
a
a
b
c
c
d
k
z
z
a
b
n
a
l
a
i
e
c
c
d
d
e
l
t
t
a
a
a
b
e
i
l
n
c
d
l
c
t
t
e
d
b
n
c
d
a
a
a
l
e
i
d
l
c
e
t
t
a
m
p
c
a
o
l
i
t
i
u
u
o
u
s
m
m
m
a
n
a
n
m
c
i
i
u
u
m
m
o
a
p
a
r
t
l
o
u
m
s
a
a
n
n
a
l
u
s
a
n
m
c
i
i
u
u
m
m
p
o
a
t
r
o
m
a
n
r
Reference
[1] Zápisy z ADS I. - Martin Mareš http://mj.ucw.cz/vyuka/1011/ads1/
[2] Přihrádkové třídění - Tomáš Slavíček http://www.vbnet.cz/

Podobné dokumenty

Kuřecí prsa po francouzsku - Úvod

Kuřecí prsa po francouzsku - Úvod Petrželku omyjeme a osušíme, zbavíme stonků a nasekáme najemno. Česnek oloupeme a prolisujeme. Vytlačíme si šťávu z půlky citronu a přefiltrujeme ji přes jemné sítko. Parmazán

Více

HelpingPreventCervicalCancer Czech0913

HelpingPreventCervicalCancer Czech0913 Vakcína proti viru HPV Vakcína HPV je k dispozici pro dívky ve věku 12 až 13 let prostřednictvím imunologického programu pro školy. Další informace o vakcíně naleznete na webové stránce s informace...

Více

Lambda depth-first proof

Lambda depth-first proof PN a DN nesmí být nadhodnoceny, jsou to dolní odhady. Odhad obtížnosti důkazu/vyvrácení uzlu. Využití doménových heuristik.

Více

Stránka 1 Obj. kód Specifikace MOC MOC

Stránka 1 Obj. kód Specifikace MOC MOC Baterie Nokia 6100, 6300, 2650, 2652, 3500 classic, 5100, 5310, 6101, 6102, 6103, 6104, 6125, 6131, 6136, 6170, 6103, 6170, 6260, 6301, 7200, 7270, E50, E60, NGage, N70, N71, N72, N91, N91 8GB, 110...

Více

XNA Game Studio 3.1

XNA Game Studio 3.1 Initialize LoadContent

Více

Úvod do Programování

Úvod do Programování je, že není takzvaně case-sensitive, čili nerozlišuje velká a malá písmena. Napsali jsme dva příkazy (každý příkaz v Pascalu je ukončen středníkem „;ÿ). První příkaz je WriteLn(’Ahoj!’); Tento přík...

Více

Seznam všech témat pro ústní zkoušku PRG+IDS 2011

Seznam všech témat pro ústní zkoušku PRG+IDS 2011 • výběry sloupců • aliasy sloupců a tabulek • spojování sloupců pomocí fce CONCAT() • výběry řádků • změna řazení výpisu řádků • omezení řádků výpisu • využití NULL, LIKE • pohledy Terminálový vstu...

Více