![]() |
![]() ![]()
Autor artykułu: mgr Jerzy Wałaszek |
©2017 mgr
Jerzy Wałaszek
|
Poczynając od tego rozdziału przechodzimy do opisu algorytmów
szybkich, tzn. takich, które posiadają klasę czasowej
złożoności obliczeniowej równą
W informatyce zwykle obowiązuje zasada, iż prosty algorytm posiada dużą złożoność obliczeniową, natomiast algorytm zaawansowany posiada małą złożoność obliczeniową, ponieważ wykorzystuje on pewne własności, dzięki którym szybciej dochodzi do rozwiązania. Wiele dobrych algorytmów sortujących korzysta z rekurencji, która powstaje wtedy, gdy do rozwiązania problemu algorytm wykorzystuje samego siebie ze zmienionym zestawem danych. Przykład: Jako przykład może posłużyć rekurencyjne obliczanie silni. Silnię liczby
n
należącej do zbioru liczb naturalnych definiujemy następująco: n! = 1 × 2 × 3 × ... × (n - 1) × n Na przykład: 5! = 1
×
2
×
3
×
4
×
5 = 120 Specyfikacja algorytmu
Lista kroków
Przykładowy program w języku C++
Dzięki rekurencji funkcja wyliczająca wartość silni staje się niezwykle
prosta. Najpierw sprawdzamy warunek zakończenia rekurencji, tzn. sytuację, gdy
wynik dla otrzymanego zestawu danych jest oczywisty. W przypadku silni sytuacja
taka wystąpi dla
Wynaleziony w 1945 roku przez Johna von Neumanna
algorytm
sortowania przez scalanie jest algorytmem
rekurencyjnym. Wykorzystuje zasadę dziel i zwyciężaj,
która polega na podziale zadania głównego na zadania mniejsze dotąd, aż
rozwiązanie stanie się oczywiste. Algorytm sortujący dzieli porządkowany zbiór
na kolejne połowy dopóki taki podział jest możliwy (tzn.
podzbiór zawiera co najmniej dwa elementy). Następnie uzyskane w ten
sposób części zbioru rekurencyjnie sortuje tym samym algorytmem. Posortowane
części łączy ze sobą za pomocą scalania, tak aby wynikowy zbiór był posortowany. |
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
Scalanie zbiorów uporządkowanychPodstawową operacją algorytmu jest scalanie dwóch zbiorów uporządkowanych w jeden zbiór również uporządkowany. Operację scalania realizujemy wykorzystując pomocniczy zbiór, w którym będziemy tymczasowo odkładać scalane elementy dwóch zbiorów. Ogólna zasada jest następująca:
Przykład:
Połączmy za pomocą opisanego algorytmu dwa uporządkowane zbiory:
Z podanego przykładu możemy wyciągnąć wniosek, iż operacja scalania dwóch uporządkowanych zbiorów jest dosyć prosta. Diabeł jak zwykle tkwi w szczegółach.
Algorytm scalania dwóch zbiorówPrzed przystąpieniem do wyjaśniania sposobu łączenia dwóch zbiorów uporządkowanych w jeden zbiór również uporządkowany musimy zastanowić się nad sposobem reprezentacji danych. Przyjmijmy, iż elementy zbioru będą przechowywane w jednej tablicy, którą oznaczymy literką d. Każdy element w tej tablicy będzie posiadał swój numer, czyli indeks z zakresu od 0 do n-1. Kolejnym zagadnieniem jest sposób reprezentacji scalanych zbiorów. W przypadku algorytmu sortowania przez scalanie zawsze będą to dwie przyległe połówki zbioru, który został przez ten algorytm podzielony. Co więcej, wynik scalenia ma być umieszczony z powrotem w tym samym zbiorze.
Przykład: Prześledźmy prosty przykład. Mamy posortować zbiór o postaci: { 6 5 4 1 3 7 9 2 }
Ponieważ w opisywanym tutaj algorytmie sortującym scalane podzbiory są przyległymi do siebie częściami innego zbioru, zatem logiczne będzie użycie do ich definicji indeksów wybranych elementów tych podzbiorów:
Przez podzbiór młodszy rozumiemy podzbiór zawierający elementy o indeksach mniejszych niż indeksy elementów w podzbiorze starszym.
Indeks końcowego elementu młodszej połówki zbioru z łatwością wyliczamy - będzie on o 1 mniejszy od indeksu pierwszego elementu starszej połówki.
Przykład:
Specyfikacja algorytmu scalaniaScalaj(ip, is, ik)Dane wejściowe
Dane wyjściowe
Zmienne pomocnicze
Lista kroków algorytmu scalania
Schemat blokowy algorytmu scalania![]() Operacja scalania dwóch podzbiorów wymaga dodatkowej pamięci o
rozmiarze równym sumie rozmiarów scalanych podzbiorów. Dla prostoty na potrzeby
naszego algorytmu zarezerwujemy tablicę p
o rozmiarze równym rozmiarowi zbioru Parametrami wejściowymi do algorytmu są indeksy ip,
is oraz ik,
które jednoznacznie definiują położenie dwóch podzbiorów do scalenia w obrębie
tablicy
Zmienna i będzie zawierała indeksy
elementów wstawianych do tablicy Wewnątrz pętli sprawdzamy, czy indeksy i1 i i2 wskazują elementy podzbiorów. Jeśli któryś z nich wyszedł poza dopuszczalny zakres, to dany podzbiór jest wyczerpany - w takim przypadku do tablicy p przepisujemy elementy drugiego podzbioru. Jeśli żaden z podzbiorów nie jest wyczerpany, porównujemy kolejne
elementy z tych podzbiorów wg indeksów i1
i i2.
Do tablicy Wtedy przechodzimy do końcowej pętli, która przepisuje ten obszar
z tablicy |
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
Algorytm sortowania przez scalanieSortuj_przez_scalanie(ip, ik)Dane wejściowe
Dane wyjściowe
Zmienne pomocnicze
Lista kroków algorytmu sortującego
Schemat blokowy algorytmu sortującego![]() Algorytm sortowania przez scalanie jest
algorytmem rekurencyjnym. Wywołuje się go z zadanymi wartościami indeksów
ip
oraz ik. Przy pierwszym wywołaniu indeksy
te powinny objąć cały zbiór d, zatem Najpierw algorytm wyznacza indeks is, który wykorzystywany jest do podziału zbioru na dwie połówki: - młodszą o indeksach elementów od ip
do Następnie sprawdzamy, czy dana połówka zbioru zawiera więcej niż jeden element. Jeśli tak, to rekurencyjnie sortujemy ją tym samym algorytmem. Po posortowaniu obu połówek zbioru scalamy je za pomocą opisanej wcześniej procedury scalania podzbiorów uporządkowanych i kończymy algorytm. Zbiór jest posortowany. W przykładowych programach procedurę scalania umieściliśmy bezpośrednio w kodzie algorytmu sortującego, aby zaoszczędzić na wywoływaniu.
|
Drzewo binarneDotychczas operowaliśmy na prostych strukturach danych,
takich jak
tablice. W tablicy elementy ułożone są
zgodnie z ich numeracją, czyli indeksami.
Jeśli za punkt odniesienia weźmiemy element
Pierwszy element Drzewo binarne jest hierarchiczną
strukturą danych, którego elementy będziemy nazywali
węzłami ![]() Węzły są połączone krawędziami symbolizującymi następstwo kolejnych elementów w strukturze drzewa binarnego. Według rysunku po prawej stronie węzeł A posiada dwa węzły potomne: B i C. Węzeł B nosi nazwę lewego potomka (ang. left child node), a węzeł C nosi nazwę prawego potomka (ang. right child node). Z kolei węzeł B posiada węzły potomne
D i E, a węzeł
C
ma węzły potomne F i G.
Jeśli dany węzeł nie posiada dalszych węzłów potomnych, to jest w
strukturze drzewa binarnego
węzłem terminalnym. Taki węzeł nosi nazwę
liścia Rodzicem, przodkiem (ang. parent node) lub węzłem nadrzędnym będziemy nazywać węzeł leżący na wyższym poziomie hierarchii drzewa binarnego. Dla węzłów B I C węzłem nadrzędnym jest węzeł A. Podobnie dla węzłów D i E węzłem nadrzędnym będzie węzeł B, a dla F i G będzie to węzeł C. Węzeł nie posiadający rodzica nazywamy korzeniem
drzewa binarnego
Odwzorowanie drzewa binarnegoJeśli chcemy przetwarzać za pomocą komputera struktury
drzew binarnych, to musimy zastanowić się nad sposobem reprezentacji
takich struktur w pamięci. Najprostszym rozwiązaniem jest
zastosowanie zwykłej tablicy n elementowej.
Każdy element tej tablicy będzie reprezentował jeden węzeł drzewa
binarnego. Pozostaje nam jedynie określenie związku pomiędzy
indeksami elementów w tablicy a położeniem tych elementów w
strukturze drzewa binarnego.
Zastosujmy następujące odwzorowanie:
Otrzymamy w ten sposób następujące odwzorowanie elementów tablicy w drzewo binarne:
Dla węzła k-tego wyprowadzamy następujące wzory:
Sprawdź, iż podane wzory są również spełnione w drzewach binarnych o większych rozmiarach niż prezentuje nasz przykład (pomocna może być kartka papieru).
Przykład: Skonstruować drzewo binarne z elementów zbioru {7 5 9 2 4 6 1}
Zrównoważone drzewa binarneUmówmy się na potrzeby tego artykułu, iż binarne drzewo
jest
zrównoważone i uporządkowane, jeśli na
wszystkich poziomach za wyjątkiem ostatniego posiada maksymalną
liczbę węzłów, a na poziomie ostatnim węzły są ułożone kolejno od
lewej strony. Innymi słowy, jeśli ostatni węzeł drzewa binarnego
posiada numer i-ty, to drzewo zawiera
wszystkie węzły od numeru
1
do i.
Warunek ten gwarantuje nam, iż każdy element tablicy będzie reprezentował pewien węzeł w drzewie binarnym - czyli w tej strukturze nie wystąpią dziury.
Drzewo po lewej stronie nie posiada węzła Drzewo po prawej stronie nie posiada węzła W uporządkowanych i zrównoważonych drzewach binarnych bardzo
prosto można sprawdzić, czy k-ty węzeł jest
liściem. Będzie tak, jeśli węzeł ten nie posiada węzłów potomnych.
Zatem, jeśli drzewo binarne składa się z n
węzłów, to wystarczy sprawdzić, czy
Ścieżki na drzewach binarnychŚcieżką nazwiemy ciąg węzłów
drzewa binarnego spełniających warunek, iż każdy węzeł poprzedni
jest rodzicem węzła następnego. Jeśli ścieżka składa się z
k węzłów, to długością ścieżki jest liczba
Na powyższym rysunku zaznaczona została ścieżka biegnąca poprzez
węzły Wysokością drzewa binarnego nazwiemy długość najdłuższej ścieżki od korzenia do liścia. W powyższym przykładzie najdłuższa taka ścieżka ma długość 3, zatem zaprezentowane drzewo binarne ma wysokość równą 3. Dla n węzłów zrównoważone drzewo binarne ma wysokość równą:
h = [log2n]
Podsumowanie nowej terminologii
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
KopiecKopiec jest drzewem binarnym, w
którym wszystkie węzły spełniają następujący warunek
(zwany warunkiem kopca):
Węzeł nadrzędny jest większy lub równy węzłom potomnym (w porządku malejącym relacja jest odwrotna - mniejszy lub równy).
Konstrukcja kopca jest nieco bardziej skomplikowana od konstrukcji drzewa binarnego, ponieważ musimy dodatkowo troszczyć się o zachowanie warunku kopca. Zatem po każdym dołączeniu do kopca nowego węzła, sprawdzamy odpowiednie warunki i ewentualnie dokonujemy wymian węzłów na ścieżce wiodącej od dodanego węzła do korzenia.
Przykład: Skonstruować kopiec z elementów zbioru {7 5 9 6 7 8 10}
Charakterystyczną cechą kopca jest to, iż korzeń zawsze jest największym (w porządku malejącym najmniejszym) elementem z całego drzewa binarnego.
AlgorytmPoniżej przedstawiamy algorytm konstrukcji kopca z elementów zbioru.
Specyfikacja problemuDane wejściowe
Dane wyjściowe
Zmienne pomocnicze
Lista kroków
Uwaga: przy porządku malejącym należy zmienić drugi warunek w kroku K04 z d[k] < x na d[k] > x. |
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
Rozbiór kopcaAlgorytmW tym rozdziale nauczymy się rozbierać kopiec. Zasada jest następująca:
Przykład: Dokonaj rozbioru następującego kopca:
Operację rozbioru kopca można przeprowadzić w
miejscu. Jeśli mamy zbiór
Specyfikacja problemuDane wejściowe
Dane wyjściowe
Zmienne pomocnicze
Lista kroków
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
Sortowanie przez kopcowanieAlgorytmJeśli przeczytałeś uważnie poprzednie dwa rozdziały, to zasadę sortowania przez kopcowanie zrozumiesz od razu - w zbiorze tworzymy kopiec, a następnie dokonujemy jego rozbioru. W wyniku wykonania tych dwóch operacji zbiór zostanie posortowany.
Specyfikacja problemuDane wejściowe
Dane wyjściowe
Zmienne pomocnicze i funkcje
Lista kroków
Ponieważ sortowanie przez kopcowanie składa się z dwóch
następujących bezpośrednio po sobie operacji o klasie czasowej
złożoności obliczeniowej
|
AlgorytmAlgorytm sortowania szybkiego opiera się na strategii "dziel i zwyciężaj" (ang. divide and conquer), którą możemy krótko scharakteryzować w trzech punktach:
Idea sortowania szybkiego jest następująca:
Sortowanie szybkie zostało wynalezione przez angielskiego
informatyka, profesora
Tony'ego Hoare'a w latach 60-tych
ubiegłego wieku. W przypadku typowym algorytm ten jest najszybszym
algorytmem sortującym z klasy złożoności obliczeniowej
|
|||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
Tworzenie partycjiDo utworzenia partycji musimy ze zbioru wybrać jeden z
elementów, który nazwiemy piwotem. W lewej
partycji znajdą się wszystkie elementy niewiększe od piwotu, a w
prawej partycji umieścimy wszystkie elementy niemniejsze od piwotu.
Położenie elementów równych nie wpływa na proces sortowania, zatem
mogą one występować w obu partycjach. Również porządek elementów w
każdej z partycji nie jest ustalony. Jako piwot można wybierać element pierwszy, środkowy, ostatni, medianę lub losowy. Dla naszych potrzeb wybierzemy element środkowy:
Dzielenie na partycje polega na umieszczeniu dwóch wskaźników na początku zbioru - i oraz j. Wskaźnik i przebiega przez zbiór poszukując wartości mniejszych od piwotu. Po znalezieniu takiej wartości jest ona wymieniana z elementem na pozycji j. Po tej operacji wskaźnik j jest przesuwany na następną pozycję. Wskaźnik j zapamiętuje pozycję, na którą trafi następny element oraz na końcu wskazuje miejsce, gdzie znajdzie się piwot. W trakcie podziału piwot jest bezpiecznie przechowywany na ostatniej pozycji w zbiorze.
Przykład: Dla przykładu podzielimy na partycje zbiór: { 7 2 4 7 3 1 4 6 5 8 3 9 2 6 7 6 3 }
Po zakończeniu podziału na partycje wskaźnik j
wyznacza pozycję piwotu. Lewa partycja zawiera elementy mniejsze od
piwotu i rozciąga się od początku zbioru do
pozycji
|
|||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
Specyfikacja problemuSortuj_szybko(lewy, prawy)Dane wejściowe
Dane wyjściowe
Zmienne pomocnicze
Lista kroków
Algorytm sortowania szybkiego wywołujemy podając za lewy indeks pierwszego elementu zbioru, a za prawy indeks elementu ostatniego (czyli Sortuj_szybko(0,n-1)). Zakres indeksów jest dowolny - dzięki temu ten sam algorytm może również sortować fragment zbioru, co wykorzystujemy przy sortowaniu wyliczonych partycji.
Schemat blokowy
Na element podziałowy wybieramy element leżący w środku dzielonej partycji. Wyliczamy jego pozycję i zapamiętujemy ją tymczasowo w zmiennej i. Robimy to po to, aby dwukrotnie nie wykonywać tych samych rachunków. Element Ustawiamy zmienną j na początek partycji. Zmienna ta zapamiętuje pozycję podziału partycji. W pętli sterowanej zmienną i
przeglądamy kolejne elementy od pierwszego do przedostatniego
(ostatni został umieszczony na pozycji piwotu, a piwot zapamiętany).
Jeśli Po zakończeniu pętli element z pozycji
Sprawdzamy, czy partycje te obejmują więcej niż jeden
element. Jeśli tak, to wywołujemy rekurencyjnie algorytm sortowania
szybkiego przekazując mu granice wyznaczonych partycji. Po powrocie
z wywołań rekurencyjnych partycja wyjściowa jest posortowana
rosnąco. Kończymy algorytm.
|
Opisany w tym rozdziale algorytm sortowania kubełkowego
pozwala sortować zbiory liczb całkowitych - najlepiej o dużej ilości
elementów, lecz o małym zakresie wartości. Zasada działania jest
następująca:
Przykład: Dla przykładu posortujemy opisaną wyżej metodą zbiór Najpierw określamy zakres wartości elementów (w tym celu możemy na przykład wyszukać w zbiorze element najmniejszy i największy). U nas zakres wynosi:
wmin = 2, wmax = 9
Potrzebujemy zatem:
wmax - wmin + 1 = 9 - 2 + 1 = 8 liczników.
Liczniki ponumerujemy zgodnie z wartościami, które będą zliczały:
[2] [3] [4] [5] [6] [7] [8] [9]
Na początku sortowania wszystkie liczniki mają stan zero:
[2:0] [3:0] [4:0] [5:0] [6:0] [7:0] [8:0] [9:0]
Teraz przeglądamy kolejne elementy zbioru zliczając ich wystąpienia w odpowiednich licznikach:
{ 2 6 4 3 8 7 2 5 7 9 3 5 2 6 } [2:3] [3:2] [4:1] [5:2] [6:2] [7:2] [8:1] [9:1]
Zapis [2:3] oznacza, iż licznik numer 2 zawiera liczbę 3, a to z kolei oznacza, iż liczba 2 pojawiła się w zbiorze 3 razy. Przeglądamy kolejne liczniki począwszy od licznika o najmniejszym numerze (w przypadku sortowania malejącego przeglądanie rozpoczynamy od licznika o największym numerze) i zapisujemy do zbioru wynikowego tyle razy numer licznika, ile wynosi jego zawartość:
[2:3] [3:2] [4:1] [5:2] [6:2] [7:2] [8:1] [9:1] { 2 2 2 3 3 4 5 5 6 6 7 7 8 9 }
Specyfikacja problemuDane wejściowe
Dane wyjściowe
Zmienne pomocnicze
Lista kroków
Algorytm ma klasę czasowej złożoności obliczeniowej
W sytuacji odwrotnej, gdy sortujemy mało elementów o dużym zakresie wartości klasa złożoności zredukuje się z kolei do O(m) - spróbuj uzasadnić ten wynik samemu na podstawie analizy działania poszczególnych fragmentów algorytmu.
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
Sortowanie przez zliczanie
|
Wartość: | 0 | 0 | 1 | 1 | 1 | 2 | 2 | 2 | 2 | 3 | 3 | 3 | 3 | 3 | 4 | 4 | 4 | 5 | 5 | 5 | 6 | 6 | 6 | 6 | 7 | 7 | 7 | 8 | 8 | 8 | 8 | 9 | 9 | 9 |
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
Pozycja: | 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 |
Przeglądamy jeszcze raz zbiór wejściowy idąc od ostatniego elementu do pierwszego (aby zachować stabilność sortowania). Każdy element umieszczamy w zbiorze wynikowym na pozycji równej zawartości licznika dla tego elementu. Po wykonaniu tej operacji licznik zmniejszamy o 1. Dzięki temu następna taka wartość trafi na wcześniejszą pozycję.
W naszym przykładzie rozpoczynamy od ostatniej liczby 3. Jej licznik ma zawartość [3:14]. Zatem liczbę 3 umieszczamy w zbiorze wynikowym na pozycji 14 - 1 = 13 i zmniejszamy o 1 stan licznika otrzymując [3:13]. Kolejna liczba 3 trafi teraz na pozycję 12, itd.
Dla liczby 5 stan licznika wynosi [5:20]. Umieszczamy ją zatem na 20 - 1 = 19 pozycji i licznik zmniejszamy o 1 otrzymując [5:19].
Postępujemy w ten sam sposób z pozostałymi elementami zbioru. W efekcie zbiór wynikowy będzie posortowany rosnąco:
{ 0 0 1 1 1 2 2 2 2 3 3 3 3 3 4 4 4 5 5 5 6 6 6 6 7 7 7 8 8 8 8 9 9 9 }
Przyjrzawszy się dokładnie algorytmowi sortowania przez zliczanie możesz zastanawiać się, dlaczego postępujemy w tak dziwny sposób? Przecież mając zliczone wystąpienia każdej wartości w licznikach, możemy je od razu przepisać do zbioru wyjściowego, jak zrobiliśmy w algorytmie sortowania kubełkowego. Miałbyś rację, gdyby chodziło jedynie o posortowanie liczb. Jest jednak inaczej.
Celem nie jest posortowanie jedynie samych wartości elementów. Sortowane wartości są zwykle tzw. kluczami, czyli wartościami skojarzonymi z elementami, które wyliczono na podstawie pewnego kryterium Sortując klucze chcemy posortować zawierające je elementy. Dlatego do zbioru wynikowego musimy przepisać całe elementy ze zbioru wejściowego, gdyż w praktyce klucze stanowią jedynie część (raczej małą) danych zawartych w elementach. Zatem algorytm sortowania przez zliczanie wyznacza docelowe pozycje elementów na podstawie reprezentujących je kluczy, które mogą się wielokrotnie powtarzać. Następnie elementy są umieszczane na właściwym miejscu w zbiorze wyjściowym. Prześledź dokładnie podany poniżej algorytm oraz przykładowe programy, a wszystko powinno się wyjaśnić.
d[ ] | - | zbiór elementów do posortowania. Każdy element posiada pole klucz, wg którego dokonuje się sortowania. Pole klucz jest liczbą całkowitą. Indeksy elementów rozpoczynają się od 0. |
n | - | ilość elementów w zbiorze d[ ]. n
![]() |
kmin | - | minimalna wartość klucza, kmin
![]() |
kmax | - | maksymalna wartość klucza, kmax
![]() |
b[ ] | - zbiór z posortowanymi elementami ze zbioru d[ ]. Indeksy elementów rozpoczynają się od 0. |
i | - | zmienna dla pętli iteracyjnych, i
![]() |
L[ ] | - | tablica liczników wartości kluczy. Elementy są liczbami całkowitymi. Indeksy przebiegają kolejne wartości od 0 do kmax - kmin . |
K01: | Dla i = 0,1,...,kmax - kmin: wykonuj L[i] ← 0 |
K02: | Dla i = 0,2,...,n - 1: wykonuj L[d[i].klucz - kmin] ← L[d[i].klucz - kmin] + 1 |
K03: | Dla i = 1, 2,...,kmax - kmin: wykonuj L[i] ← L[i] + L[i - 1] |
K04: | Dla i = n - 1, n - 2,...,0: wykonuj K05...K06 |
K05: | b[ L[ d[i].klucz - kmin ] - 1] ← d[i] |
K06: | L[ d[i].klucz - kmin ] ← L[ d[i].klucz - kmin ] - 1 |
K07: | Zakończ |
![]() | I Liceum Ogólnokształcące |
Pytania proszę przesyłać na adres email: i-lo@eduinf.waw.pl
W artykułach serwisu są używane cookies. Jeśli nie chcesz ich otrzymywać,
zablokuj je w swojej przeglądarce.
Informacje dodatkowe