Sztuka Programowania. Tom 1. Algorytmy podstawowe

Przybliża techniki programistyczne osobom nie związanym z informatyką, które nie mogą w pełni wykorzystać komputera, bo

946 152 24MB

Polish Pages [698] Year 2001

Report DMCA / Copyright

DOWNLOAD FILE

Polecaj historie

Sztuka Programowania. Tom 1. Algorytmy podstawowe

Citation preview

Donald E. Knuth

Sztuka programowania Tom 1 Algorytmy podstawowe Z angielskiego przełożył

Grzegorz Jakacki

OD REDAKCJI Udostępniane polskim Czytelnikom wielkie dzieło Donalda E. K nutha Sztuka programowania składa się obecnie z trzech tomów. W przedmowie do tom u 1 Autor wspomina o tomach 4 - 7 , które nie zostały jeszcze opublikowane. Czytel­ nik nie powinien się więc dziwić, gdy w treści znajdzie odwołania do zagadnień zawartych w planowanych tomach. Autor zamieścił w swoim dziele wiele cytatów literackich. Niektóre z nich są m ottam i rozdziałów, a inne stanowią podsumowanie treści zawartych w podroz­ działach lub mniejszych partiach tekstu. Część z nich byliśmy zmuszeni pozosta­ wić w wersji oryginalnej. Przekład na język polski nie oddawałby bowiem gry słów wyrażającej myśli Autora. Podobnie postąpiliśm y z cytatam i nieangielskimi przytoczonymi przez A utora w oryginalnym brzmieniu. Kilka dzieł, z których pochodzą m otta, zostało przełożonych na język polski. Gdy jednak tłum aczenie literackie nie oddawało intencji A utora i nie zawierało słów, na użyciu których Mu zależało, zdecydowaliśmy się przytoczyć nowe tłum aczenie. Niektóre z oznaczeń m atematycznych stosowanych przez A utora różnią się nieco od spotykanych w tradycyjnych książkach m atematycznych. Ponieważ za­ leżało nam na tym, by polskie wydanie dzieła było pod każdym względem jak najbardziej zbliżone do oryginału, pozostawiliśmy je bez zmiany.

PRZEDMOWA O to książka, o którą prosili nasi czytelnicy w tysiącach dosłownie listów. Przygotowanie je j zajęło nam lata. W ielokrotnie sprawdzaliśmy różne przepisy, by przedstawić w niej tylko to, co najlepsze, najciekawsze i najdoskonalsze. Teraz możem y ju ż powiedzieć i to bez cienia wątpliwości, że jeśli czytelnik będzie postępował zgodnie z podanym i instrukcjami, otrzym a właśnie to, o co chodzi - choćby nie m iał żadnego doświadczenia kulinarnego. —

M c C a ll’s Cookbook (1 9 63 )

Proces przygotowywania programu dla kom putera cyfrowego jest pociągający nie tylko ze względu na potencjalne korzyści ekonomiczne czy naukowe. W iążą się z nim również przeżycia estetyczne, podobne do tworzenia poezji lub kom­ ponowania muzyki. Niniejsza książka jest pierwszym tomem dzieła mającego na celu przedstawienie Czytelnikowi umiejętności składających się na rzemiosło programistyczne. Książka nie rozpoczyna się od wprowadzenia do programowania. Zakładam, że Czytelnik ma w tej dziedzinie pewne doświadczenie. W ym agania są, praw­ dę powiedziawszy, niewielkie, choć zrozumienie działania kom putera cyfrowego wymaga od początkujących czasu i ćwiczeń. Czytelnik powinien: a) Orientować się, jak działa kom puter cyfrowy, ale niekoniecznie w sensie elek­ tronicznym, raczej na poziomie wykonywania rozkazów przechowywanych w pamięci. b) Umieć wyrażać rozwiązania problemów w sposób na tyle prosty, żeby kom­ puter był w stanie je „zrozumieć” . (Te maszyny nie kierują się zdrowym roz­ sądkiem; robią dokładnie to, co się im każe. Jest to jeden z najpoważniejszych problemów, z jakim i stykają się początkujący użytkownicy komputerów). c) Dysponować pewną wiedzą na tem at podstawowych technik obliczeniowych, wykorzystujących pętle (wielokrotnie wykonywane zestawy instrukcji), pod­ programy, indeksowanie tablic. d) Rozumieć choć trochę żargon komputerowy - czyli wiedzieć, co oznacza „pamięć” , „rejestry” , „bity” , „zmiennopozycyjny” , „przepełnienie” , „opro­ gramowanie” . Większość słów niezdefiniowanych w tekście jest wyjaśniona w skorowidzu zamieszczonym na końcu każdego tomu. Te cztery wymogi można zawrzeć w jednym zdaniu: Czytelnik powinien mieć na swoim koncie przynajmniej cztery napisane i przetestowane programy. ix

X

PRZEDMOWA

Starałem się pisać to kilkutomowe dzieło tak, żeby zaspokoić wiele potrzeb naraz. Przede wszystkim poszczególne tomy można traktować jako prace obej­ mujące aktualną wiedzę z kilku ważnych dziedzin. Poza tym mogą one służyć jako podręczniki do sam okształcenia lub do wykładów uniwersyteckich z infor­ matyki. Z uwagi na ten cel zamieściłem w nich wiele ćwiczeń, w większości z rozwiązaniami. Starałem się także zapełniać strony faktami, a nie ogólnikowymi komentarzami. Książki te są przeznaczone dla osób, które nie interesują się komputerami jedynie doraźnie. Nie znaczy to bynajm niej, że są adresowane wyłącznie do specjalistów. Tak naprawdę jednym z moich głównych celów było przybliżenie technik programistycznych osobom nie związanym z informatyką, które nie mogą w pełni wykorzystać wszystkich możliwości kom putera, bo nie m ają czasu na to, by szukać potrzebnych im informacji w czasopismach specjalistycznych. Można by powiedzieć, że książki te są poświęcone analizie nienumerycznej. Kom putery tradycyjnie wiąże się z rozwiązywaniem problemów numerycznych, takich jak znajdowanie pierwiastków równania, interpolacja, całkowanie itp., ale tym zajmuję się tu tylko pobieżnie. Programowanie numeryczne jest nie­ zwykle ciekawą i szybko rozwijającą się dziedziną, a na jego tem at napisa­ no już wiele książek. Od wczesnych lat sześćdziesiątych komputery częściej są jednak używane do rozwiązywania problemów, w których liczby pojaw iają się tylko przez przypadek; wykorzystuje się właściwości kom putera umożliwiające podejmowanie decyzji, a nie wykonywanie operacji arytmetycznych. W pro­ blemach nienumerycznych znajdujem y czasem zastosowanie dla dodawania lub odejmowania, ale już dla mnożenia i dzielenia - rzadko. Z książek niniejszych skorzysta jednak również Czytelnik zainteresowany metodami numerycznymi, ponieważ zaprezentowane techniki nienumeryczne przewijają się także w progra­ mach numerycznych. W yniki badań w dziedzinie analizy nienumerycznej są rozrzucone po wielu czasopismach specjalistycznych. Podjąłem więc próbę wyodrębnienia z tej obszer­ nej literatury tych najbardziej elementarnych technik, mających zastosowanie w wielu sytuacjach programistycznych. Starałem się także sformować z tych rozwiązań swego rodzaju „teorię” , a również pokazać, jak teorię zastosować do rozmaitych problemów praktycznych. Oczywiście „analiza nienumeryczna” jest w wypadku tej dziedziny wiedzy nazwą pejoratyw ną. O wiele lepsze byłoby nie budzące wątpliwości, opisowe określenie tem atu. „Przetwarzanie informacji” to term in zbyt obszerny, a „tech­ niki program istyczne” - zbyt wąski. Proponuję więc za nazwę tem atu, któremu poświęcone jest to dzieło, przyjąć analizę algorytmów. Ma ona bowiem oznaczać „teorię własności poszczególnych algorytmów komputerowych” . Zarys dzieła Sztuka programowania przedstawia się następująco: Tom 1. A lgorytm y podstawowe Rozdział 1. Pojęcia podstawowe Rozdział 2. Struktury danych

PRZEDMOWA

xi

Tom 2. A lgorytm y seminumeryczne Rozdział 3. Liczby losowe Rozdział 4. Arytm etyka Tom 3. Sortowanie i wyszukiwanie Rozdział 5. Sortowanie Rozdział 6. Wyszukiwanie Tom 4. A lgorytm y kombinatoryczne Rozdział 7. Wyszukiwanie kombinatoryczne Rozdział 8. Rekursja Tom 5. A lgorytm y składniowe Rozdział 9. Analiza leksykalna Rozdział 10. Analiza składniowa Tom 4 obejmuje tak szeroki zakres m ateriału, że w istocie składają się nań trzy książki (tom 4A, 4B i 4C). W planach są dwa dodatkowe tomy dotyczące bardziej specjalistycznych zagadnień - tom 6 : Teoria języków (rozdział 11), i tom 7: Kom pilatory (rozdział 12). W 1962 roku zacząłem pisać książkę podzieloną na takie właśnie rozdziały, ale bardzo szybko doszedłem do wniosku, że należy dogłębnie, a nie pobieżnie omówić poszczególne zagadnienia. Objętość powstałego tekstu wskazywała, że m ateriału zawartego w dowolnym rozdziale wystarcza na jednosem estralny wy­ kład. Rozsądnym więc rozwiązaniem było opublikowanie dzieła składającego się z oddzielnych tomów. Wiem, że książka w której jest jeden lub dwa rozdziały, wy­ gląda dziwnie, ale zdecydowałem się zachować oryginalną numerację, co ułatwiło odwoływanie się do fragmentów całego dzieła. W planie m am też krótszą wersję tomów 1 - 5 , m ającą służyć za bardziej ogólny przewodnik i/lu b podręcznik dla młodszych studentów, w którym nie m a informacji specjalistycznych. W ydanie skrócone będzie miało tę samą numerację rozdziałów, co pełne. Niniejszy tom może być uznawany za „część wspólną” całego dzieła, z uwagi na fakt, że zawiera podstawowy m ateriał wykorzystywany w następnych tomach. Tomy 2 - 5 można czytać niezależnie. Tom 1 nie jest jednak wyłącznie „kluczem” do pozostałych pozycji. Można go używać jako podręcznika struktur danych (szczególnie z uwagi na rozdział 2), matematyki dyskretnej (podrozdziały 1.1 i 1.2 oraz punkty 1.3.3 i 2.3.4) lub programowania w języku maszynowym (pod­ rozdziały 1.3 i 1.4). Punkt widzenia przyjęty przeze mnie przy pisaniu tych rozdziałów różni się od punktu widzenia innych współczesnych autorów. Ja nie próbuję uczyć Czytelnika, jak m a używać cudzego oprogramowania. Staram się pokazać, jak samemu pisać lepsze programy. Moim pierwotnym celem było zbliżenie Czytelnika do granic poznania w każ­ dym z podjętych tematów. Bardzo trudno jednak dotrzym ać kroku dziedzinie na­ uki, która przynosi zyski ekonomiczne. Nagły rozwój informatyki uczynił mój cel

x ii

PRZEDMOWA

nieosiągalnym. Temat stał się bezkresną pstrokacizną upstrzoną dziesiątkami ty­ sięcy wyrafinowanych wyników, wypracowanych przez dziesiątki tysięcy zdolnych ludzi z całego świata. Z tego powodu za swój nowy cel przyjąłem skupienie się na technikach „klasycznych” , które najprawdopodobniej pozostaną istotne przez wiele dziesięcioleci, oraz na opisaniu ich najlepiej, jak potrafię. W szczególności próbowałem prześledzić historię każdego tem atu i stworzyć stabilne podstawy dalszego postępu. Starałem się stosować zwięzłą terminologię, zgodną z tą ak­ tualnie używaną. Moim celem było opisanie tych wszystkich znanych rozwiązań dotyczących programowania komputerów sekwencyjnych, które odznaczają się jednocześnie pięknem i przejrzystością. Parę słów muszę powiedzieć o m atem atycznej zawartości dzieła. M ateriał jest ułożony tak, by Czytelnik z przygotowaniem z algebry na poziomie szkoły średniej był w stanie czytać tekst, jeśli pominie fragmenty bardziej najeżone ma­ tem atyką, a Czytelnik wyrobiony m atem atycznie poznał wiele ciekawych metod m atem atycznych związanych z m atem atyką dyskretną. Przedstawienie m ateriału na dwóch poziomach okazało się możliwe między innymi dzięki przyporządko­ waniu ćwiczeniom ocen trudności; zadania czysto matem atyczne są odpowiednio oznaczone. Starałem się również tak opracować rozdziały, by zasadnicze wyniki m atem atyczne znalazły się przed ich dowodami. Dowody przedstawiłem w formie ćwiczeń (z odpowiedziami na końcu książki) albo zamieściłem na końcu rozdziału. Czytelnik bardziej zainteresowany programowaniem niż związaną z nim ma­ tem atyką może przerwać lekturę większości rozdziałów, gdy tylko m atem atyka zacznie sprawiać mu trudności. Natom iast Czytelnik zainteresowany m atem a­ tyką najciekawszy m ateriał znajdzie właśnie tu. W wielu publikacjach m ate­ matycznych dotyczących komputerów są poważne nieścisłości. Jednym z zadań, jakie sobie postawiłem przy pisaniu tej książki, było przedstawienie poprawnych sposobów ujęcia matem atycznych aspektów programowania. Z zawodu jestem m atem atykiem . Moim obowiązkiem jest więc dbanie o m atem atyczną spójność. Do zrozumienia bez m ała całej m atem atyki zawartej w tej książce powin­ na wystarczyć podstawowa znajomość analizy matem atycznej, gdyż większość faktów dotyczących innych teorii została tu wyprowadzona od podstaw. Cza­ sami muszę jednak posłużyć się pewnymi głębszymi twierdzeniami z zakresu teorii zmiennej zespolonej, rachunku prawdopodobieństwa, teorii liczb i tym podobnych. W takich przypadkach zamieszczam odniesienia do odpowiednich podręczników. N ajtrudniejsza decyzja, jaką musiałem podjąć, przygotowując to dzieło, do­ tyczyła sposobu prezentacji technik programistycznych. Zalety schematów blo­ kowych (flow charts) i nieformalnego opisu kroków algorytmu są dobrze znane; omówienie tego zagadnienia można znaleźć w artykule,,Computer-Drawn Flow­ charts” , opublikowanym w A C M Communications, Vol. 6 (September 1963), s. 555-563. Niemniej do opisu algorytmów potrzebny jest język formalny i pre­ cyzyjny. M usiałem zatem decydować, czy posłużyć się językiem algebraicznym, takim jak ALGOL lub FORTRAN, czy językiem maszynowym. Być może wielu współczesnych informatyków uzna wybranie przeze mnie języka maszynowego za

PRZEDMOWA

xiii

błąd, ale ja przekonałem się, że m oja decyzja była ze wszech m iar słuszna, a to z następujących powodów: a) Język programowania wpływa na sposób pisania programu; istnieje tenden­ cja do stosowania konstrukcji, które są prostsze do wyrażenia w danym języ­ ku, zam iast tych, które m ają prostszą reprezentację maszynową. Rozumiejąc język maszynowy, program ista skłania się ku wykorzystaniu m etod o wiele wydajniejszych. b) Programy, którymi się zajmujemy, są raczej krótkie (z kilkoma wyjątkami). Zrozumienie ich nie będzie zatem kłopotliwe, jeżeli będziemy dysponować odpowiednim komputerem. c) Języki wysokiego poziomu nie nadają się do wykorzystania w badaniu istot­ nych szczegółów niskopoziomowych, jak współprogramy, generowanie liczb losowych, arytm etyka wysokiej precyzji, a także wielu zagadnień dotyczą­ cych efektywnego wykorzystania pamięci. d) Osoba poważnie zainteresowana kom puteram i ma na ogół pew ną wiedzę na tem at języka maszynowego, gdyż stanowi on zasadniczy element każdego komputera. e) Język maszynowy jest i tak potrzebny, ponieważ wiele omawianych progra­ mów zapisuje wyniki w postaci języka maszynowego. f) Języki algebraiczne wychodzą z mody mniej więcej co pięć lat, a mnie zależy na tym, by uwypuklić te aspekty programowania, które są nieprzemijające. Przyznaję, że łatwiej pisać programy w językach wysokiego poziomu, a już znacz­ nie łatwiej je uruchamiać. Sam od 1970 roku, tworząc programy, rzadko uży­ wałem języków niskiego poziomu. Żyjemy przecież w świecie coraz większych i szybszych komputerów. W wypadku jednak wielu poruszanych przeze mnie problemów najistotniejsza jest sztuka programowania. Weźmy na przykład pew­ ne obliczenia kombinatoryczne, które muszą być powtarzane trylion razy. Na każdej mikrosekundzie, wyciśniętej z wewnętrznej pętli, zyskujemy około 11.6 dni obliczeń. Podobnie jest z programem, który m a być wielokrotnie używany codziennie na wielu komputerach. W arto zrobić wszystko, by napisać go dobrze, skoro robi się to tylko raz. Z decyzją o posłużeniu się językiem maszynowym wiązało się pytanie: któ­ rym konkretnie? Mogłem wybrać język maszyny X , ale ci, którzy nią nie dys­ ponują, pomyśleliby, że to książka tylko dla znawców X . Co więcej, maszyna X miałaby prawdopodobnie wiele szczegółów, które, choć całkowicie nieistotne z punktu widzenia tej książki, musiałyby zostać wyjaśnione. A na dom iar złego po dwóch latach producent maszyny X wypuściłby na rynek maszynę X + 1 albo maszynę 10X, a maszyna X przestałaby kogokolwiek interesować. Aby uniknąć takich rozterek, spróbowałem zaprojektować „idealny” kompu­ ter wyposażony w przejrzysty zestaw operacji (dający się opanować, powiedzmy, w godzinę) i bardzo podobny do istniejących maszyn. Nie m a powodu, dla którego student miałby się ograniczać do poznania szczegółów tylko jednego komputera; nauczenie się jednego języka maszynowego ułatw ia przyswojenie

x iv

PRZEDMOWA

następnego. W pracy zawodowej program ista może się zetknąć z wieloma różnymi językami maszynowymi. Jedyną wadą fikcyjnej maszyny jest kłopot z urucha­ mianiem przeznaczonych dla niej programów. Na szczęście nie jest to istotnym problemem, gdyż wielu ochotników podjęło się zadania napisania symulatora mojego kom putera. Takie sym ulatory świetnie nadają się do celów szkoleniowych, gdyż łatwiej się nimi posługiwać niż prawdziwymi komputerami. Starałem się przytaczać najlepsze wczesne publikacje z każdej omawianej dziedziny, ale zwracać też uwagę na prace najnowsze. Odwołując się do literatury, używam standardowych skrótów nazw czasopism z wyjątkiem tych najczęściej cytowanych, to znaczy: C A C M = Communications of the Association for Computing Machinery J A C M — Journal of the Association for Computing Machinery Comp. J. = The Com puter Journal (British Com puter Society) M ath. Comp. = M athem atics of Com putation AM M = American M athem atical Monthly SIC O M P = SIAM Journal on Computing FO CS = IEEE Symposium on Foundations of Com puter Science SO D A = ACM -SIAM Symposium on Discrète Algorithms S T O C = ACM Symposium on Theory of Computing Crelle = Journal für die reine und angewandte M athem atik Przykładowo, zapis „C A C M 6 (1963), 555 -5 6 3 ” oznacza odniesienie zamieszczo­ ne kilka akapitów wcześniej. Posługuję się także skrótem „CM ath” na oznaczenie książki M atem atyka konkretna, cytowanej we wstępie do podrozdziału 1.2. Wiele prezentowanych problemów technicznych zawarłem w ćwiczeniach. Tam, gdzie pomysł niebanalnego ćwiczenia nie pochodzi ode mnie, starałem się uhonorować jego autora. Odpowiednie odwołania do literatury występują zazwyczaj w punkcie zawierającym ćwiczenie lub przy odpowiedzi do ćwiczenia. Niestety, w wielu wypadkach ćwiczenia opierają się na m ateriałach nieopublikowanych, do których nie sposób się odwołać. W ciągu wielu lat pracy nad tym dziełem całe rzesze osób udzielały mi wsparcia, za co jestem im wszystkim niezmiernie wdzięczny. W yrazy uznania należą się przede wszystkim mojej żonie Jill za jej niewyczerpaną cierpliwość, za przygotowanie wielu ilustracji oraz za wszelką okazywaną mi pomoc, a także Ro­ bertowi W. Floydowi, który w ciągu lat sześćdziesiątych poświęcił mnóstwo czasu na ulepszanie tego tekstu. Tysiące innych osób wniosło również swój znaczący wkład - lista ich nazwisk zapełniłaby kolejny tom! Wiele z nich zezwoliło mi na wykorzystanie swoich dotychczas niepublikowanych prac. Moje badania w Caltech i Stanford były przez wiele lat hojnie finansowane przez National Science Foundation oraz Office of Naval Research. Wydawnictwo Addison-Wesley udzie­ lało mi nieocenionego wsparcia i pomocy od 1962 roku, kiedy podjąłem się tego trudnego przedsięwzięcia. Najlepszym znanym mi sposobem podziękowania tym wszystkim ludziom jest wykazanie, że ich wkład pracy nie poszedł na marne, że dzięki nim napisałem takie książki, jakich się po mnie spodziewali.

PRZEDMOWA

xv

Przedmowa do wydania trzeciego Dziesięć lat spędzonych nad systemami T^X i M E TflFO N T pozwoliło mi spełnić marzenie, które przyświecało mi od początku tej pracy. Chciałem za pomocą T^jX-a i METRFONT-a wykonać skład dzieła Sztuka programowania. Doczekałem dnia, w którym cały tekst został zamknięty w moim komputerze, zapisany w po­ staci elektronicznej zapewniającej łatwe dostosowanie go do przyszłych zmian w technice druku. Nowy układ umożliwił wniesienie dosłownie tysięcy poprawek, na wprowadzenie których czekałem bardzo długo. W tym nowym wydaniu przejrzałem każde słowo tekstu, starając się za­ chować młodzieńczy styl pierwotnych sformułowań, tu i ówdzie dodając czasem kilka dojrzałych sądów. Dołożyłem masę nowych ćwiczeń; do mnóstwa starych podopisywałem nowe, poprawione odpowiedzi. /ÍK Rozbudowa dzieła Sztuka programowania trwa! Z tego powodu niektóre JL części są oznaczone znakiem „Uwaga, prace budowlane!” ostrzegającym , że tekst nie został zaktualizowany. Moje archiwum puchnie od m ateriałów, które zamierzam zamieścić w ostatecznym, wspaniałym, czwartym wydaniu tom u 1 , być może za 15 lat; najpierw muszę jednak skończyć tomy 4 i 5, a nie chciałbym odwlekać opublikowania ich dłużej niż to konieczne. Większość czarnej roboty związanej z przygotowaniem nowego wydania wy­ konali Phyllis W inkler i Silvio Levy, którzy fachowo wpisali i zredagowali tekst wydania drugiego, oraz Jeffrey Oldham, który przekonwertował prawie wszystkie oryginalne ilustracje na format program u METR POST. Poprawiłem wszystkie błędy, które uważni Czytelnicy znaleźli w wydaniu drugim (jak również błę­ dy, których, mimo wszystko, nikt nie znalazł). Starałem się uniknąć błędów w nowych partiach m ateriału. Spodziewam się jednak, że jakieś usterki pozo­ stały i chciałbym jak najszybciej je poprawić. Z tego powodu bez żalu wypłacę 2.56 USD każdemu pierwszemu znalazcy dowolnego błędu technicznego, typo­ graficznego lub historycznego*. Listę wszystkich zgłaszanych mi na bieżąco po­ prawek można znaleźć w witrynie W W W , wymienionej na stronie vi niniejszego tomu. Stanford, Kalifornia Kwiecień 1997

D. E. K.

Wiele się zm ieniło przez ostatnich dwadzieścia lat.

— BILL G A T E S (1 9 9 5 )

* D otyczy to niestety tylko angielskiego oryginału (przyp, tłum .).

Schemat blokowy procedury czytania dzieła Sztuka programowania.

Procedura czytania tego dzieła

1 . Zacznij czytać ten opis, o ile jeszcze tego nie zrobiłeś. Wykonuj kolejno wszys­ tkie podane tu kroki. (Ogólna postać tej procedury i schem atu blokowego będzie wykorzystywana w całej książce). 2 . Przeczytaj uwagi do ćwiczeń zamieszczone na stronach x v -x v ii.

3. Przypisz 1 do N . 4. Zacznij czytać rozdział N. Nie czytaj cytatów na początku rozdziału. 5. Czy tem at rozdziału Cię zaciekawił? Jeśli tak, przejdź do kroku 7; jeśli nie, przejdź do kroku 6. 6 . Czy < 2? Jeśli nie, przejdź do kroku 16; jeśli tak, mimo wszystko przejrzyj rozdział. (Rozdziały 1 i 2 zawierają istotny m ateriał wprowadzający oraz przegląd technik programistycznych. Musisz przynajmniej przejrzeć rozdzia­ ły dotyczące notacji i maszyny MIX).

7. Zacznij czytać kolejny podrozdział; jeśli w rozdziale nie m a więcej podroz­ działów, to przejdź do kroku 16. 8 . Czy podrozdział jest oznaczony „*” ? Jeśli tak, to pomiń go przy pierwszym czytaniu (taki podrozdział zawiera m ateriał specjalistyczny, który jest cie­ kawy, ale nie niezbędny); wróć do kroku 7.

9. Czy masz zacięcie matematyczne? Jeśli m atem atyka jest dla Ciebie czarną magią, to przejdź do kroku 1 1 ; w przeciwnym razie idź do kroku 10. 10. Sprawdź wyprowadzenia wzorów w podrozdziale (błędy zgłoś Autorowi). Przejdź do kroku 12. 1 1 . Jeżeli bieżący podrozdział jest najeżony obliczeniami matem atycznym i, nie czytaj wyprowadzeń. Zapoznaj się mimo wszystko z podstawowymi wynika­ mi przedstawionymi w podrozdziale; są zazwyczaj zamieszczone gdzieś na początku lub wydrukowane pism em pochyłym na samym końcu trudnych fragmentów. 1 2 . Wykonaj polecane ćwiczenia zgodnie ze wskazówkami zawartymi w części „Uwagi do ćwiczeń” (które przeczytałeś, wykonując krok 2).

13. Gdy już napracujesz się nad ćwiczeniami, sprawdź swoje wyniki z odpowie­ dziami zamieszczonymi na końcu książki (jeśli oczywiście jest tam odpowiedź xvii

x v iii

PROCEDURA CZYTANIA TEGO DZIEŁA

do danego ćwiczenia). Przeczytaj także odpowiedzi do ćwiczeń, na które zabrakło Ci czasu. Uwaga: W większości wypadków warto przeczytać od­ powiedzi do ćwiczenia n przed przystąpieniem do rozwiązywania ćwiczenia n + 1 . Z tego powodu kroki 1 2 -1 3 są zazwyczaj wykonywane naprzemiennie. 14. Odczuwasz zmęczenie? Jeśli nie, wróć do kroku 7. 15. Idź spać. Jak się obudzisz, wróć do kroku 7. 16. Zwiększ N o jeden. Jeśli AT = 3, 5, 7, 9, 11 lub 12 , rozpocznij czytanie kolejnego tomu. 17. Jeżeli N jest mniejsze lub równe 12 , wróć do kroku 4. 18. Gratulacje. Teraz przekonaj znajomych, by kupili egzemplarz tomu 1 i za­ częli go czytać, a Ty wróć do kroku 3.

Biada tem u, kto przeczytał tylko jedną książkę. — G E O R G E H E R B E R T , Jacuia Prudentum, 1144 (1640) Le défaut unique de tous les ouvrages c'est d'être trop longs. — V A U V E N A R G U E S , Réflexions, 628 (1746) Treść książek to banał. Życie samo w sobie je s t wspaniałe. — T H O M A S CARLYLE, Journal (1839)

UWAGI DO ĆWICZEŃ Ćwiczenia zawarte w tym dziele zostały opracowane z myślą o Czytelnikach samokształcących się lub biorących udział w zajęciach grupowych. Jest rzeczą niezmiernie trudną, o ile w ogóle możliwą, by nauczyć się czegoś, wyłącznie o tym czytając - nie sprawdzając nabytej wiedzy na konkretnych problemach, a co za tym idzie, nie będąc zmuszonym do myślenia o tym, co się przeczytało. Poza tym najlepiej uczymy się tego, co sami dla siebie odkrywamy. Z tych powodów ćwiczenia stanowią znaczną część książki. A utor dołożył wszelkich starań, by zawrzeć w nich jak najwięcej informacji i wybrać problemy ciekawe, a zarazem kształcące. W wielu książkach proste ćwiczenia są wymieszane z bardzo trudnym i. Jest to zła praktyka, gdyż Czytelnik chce z góry wiedzieć, ile czasu zajmie mu rozwią­ zanie danego problemu, a przy braku tej informacji może zdecydować się na pomi­ nięcie wszystkich ćwiczeń. Klasycznym przykładem takiej książki jest Dynamie Programming Richarda Bellmana. To ważna, pionierska praca, w której zadania są umieszczone pod wspólnym tytułem „Ćwiczenia i problemy badawcze” na końcu niektórych rozdziałów. Skrajnie proste pytania występują w tej książce miedzy trudnym i, nierozwiązanymi problemami. Plotka głosi, że dr Bellman za­ pytany kiedyś, jak odróżnić ćwiczenia od problemów badawczych, odpowiedział: „To, co dasz radę rozwiązać, jest ćwiczeniem, a co nie - problemem badawczym” . Można znaleźć dobre argumenty za zamieszczeniem w książce zarówno ćwi­ czeń, jak i problemów badawczych. Aby zatem uwolnić Czytelnika od konieczno­ ści rozstrzygania, które są którymi, autor wprowadził oceny punktowe wskazujące skalę trudności. Oceny m ają następujące znacznie: Ocena

Interpretacja

00 Skrajnie proste ćwiczenie, które można rozwiązać natychm iast, jeżeli zrozumiało się tekst. Zazwyczaj takie ćwiczenie można zrobić w pamięci. 10 Prosty problem, który zmusza do przemyślenia przeczytanego tekstu. Czytelnik powinien poradzić sobie z rozwiązaniem takiego ćwiczenia w najgorszym razie w ciągu minuty. Przyda się kartka i ołówek. 20 Przeciętny problem, umożliwiający sprawdzenie podstawowego opano­ wania m ateriału. Rozwiązanie go zajmie od piętnastu do dwudziestu minut. 30 Problem o umiarkowanym stopniu trudności i/lu b złożoności. Rozwią­ zanie go może zająć ponad dwie godziny. Przy włączonym telewizorze nawet więcej. xix

xx

UWAGI DO ĆWICZEŃ

40 Dość trudny lub pracochłonny problem, nadający się na kolokwium semestralne. Student powinien sobie z nim poradzić w rozsądnym czasie, ale rozwiązanie jest nietrywialne. 50 Problem badawczy, którego według informacji autora nikt zadowalająco nie rozwiązał, choć próbowało wielu. Czytelnik, który znajdzie rozwią­ zanie, powinien je opublikować. Ponadto autor będzie wdzięczny za jak najszybsze poinformowanie go o rozwiązaniu (o ile jest poprawne). Inne oceny są wyznaczane przez interpolację powyższej „logarytmicznej” skali. Ocena 17 wskazuje na przykład ćwiczenie, które jest nieco prostsze od przeciętnego. Problemy z oceną 50, które zostały ostatnio rozwiązane przez Czytelników, mogą w następnych wydaniach (oraz w erracie publikowanej w In­ ternecie, zobacz strona vi) pojawić się już z oceną 45. Reszta z dzielenia oceny punktowej przez 5 oznacza ilość szczegółowej pracy do wykonania. Stąd rozwiązywanie ćwiczenia ocenionego na 2Ą może zająć więcej czasu niż ćwiczenia ocenionego na 25, ale to drugie będzie wymagało więcej pomysłowości. A utor starał się właściwie dobrać oceny, ale osobie, która wymyśla zadanie, trudno stwierdzić, jak pracochłonne będzie znalezienie rozwiązania. Przy tym różnym osobom rozwiązywanie niektórych typów problemów przychodzi łatwiej, a innych trudniej. Pozostaje mieć nadzieję, że oceny punktowe zadowalająco przybliżają poziom trudności. Należy je jednak traktować raczej jako ogólne wskazówki co do stopnia trudności niż dokładne miary trudności. Książka ta została napisana dla Czytelników o różnym stopniu m atematycz­ nej biegłości i wyrafinowania. Skutkiem tego niektóre ćwiczenia są przeznaczone dla osób o zacięciu matematycznym. Ocena punktowa trudności ćwiczenia jest poprzedzona literą M, jeżeli dotyczy ono m atem atyki bardziej zaawansowanej niż potrzebna do pisania programów. Ćwiczenie jest oznaczone literami HM, jeżeli jego rozwiązanie wymaga znajomości analizy matematycznej lub matematyki wyższej nie przedstawionej w książce. Oznaczenie HM nie musi świadczyć o tym, że ćwiczenie jest trudne. Niektóre ćwiczenia są poprzedzone strzałką ; są one wyjątkowo pouczają­ ce i wyjątkowo polecane. Oczywiście po żadnym studencie/czytelniku nie należy się spodziewać, że rozwiąże wszystkie ćwiczenia, dlatego też zostały wyróżnione te najcenniejsze. (Nie oznacza to jednak, że pozostałymi nie warto się zajmować!) Każdy Czytelnik powinien przynajmniej spróbować rozwiązać wszystkie ćwicze­ nia z oceną 10 lub niższą; strzałki są przy tych z trudniejszych problemów, za które należałoby się zabrać w pierwszej kolejności. Rozwiązania większości ćwiczeń są zamieszczone w oddzielnej części zaty­ tułowanej „Odpowiedzi do ćwiczeń” . Należy korzystać z nich mądrze, to znaczy nie podglądać odpowiedzi, dopóki naprawdę nie spróbuje się rozwiązać zadania samodzielnie, i nie udawać, że nie m a się czasu. Odpowiedź może się okazać pouczająca i pomocna, ale dopiero po samodzielnym rozwiązaniu ćwiczenia lub po uczciwej próbie zrobienia tego. Podane rozwiązanie jest zazwyczaj krótkie, a jego szczegóły są omówione raczej pobieżnie. Autor zakłada bowiem, że Czy­

UWAGI DO ĆWICZEŃ

xxi

telnik próbował samodzielnie zrobić ćwiczenie. Czasami rozwiązanie nie stanowi pełnej odpowiedzi na postawione pytanie, a czasami zawiera aż nadto informacji. Całkiem możliwe, że Czytelnik znajdzie lepsze rozwiązanie od tego opublikowa­ nego w książce albo znajdzie w rozwiązaniu błąd. W takim wypadku autor będzie wdzięczny za podanie wszystkich szczegółów. Kolejne wydania książki będą za­ wierały poprawione rozwiązania opatrzone nazwiskami pogromców błędów. Przy rozwiązywaniu danego ćwiczenia można posługiwać się rozwiązaniami poprzednich ćwiczeń, chyba że tekst wyraźnie tego zabrania. Ponieważ autor uwzględnił taką sytuację przy doborze ocen punktowych, może się okazać, że ćwiczenie n + 1 ma niższą ocenę niż ćwiczenie n, choć rozwiązanie ćwiczenia n wynika z ogólniejszego wyniku uzyskanego w ćwiczeniu n + 1 .

00 10 20 ► Polecane 30 M Dla zainteresowanych m atem atyką 40 HM W ym aga znajomości m atem atyki wyższej 50

Zestawienie oznaczeń:

Trywialne Proste (m inuta) Średnie (kwadrans) Umiarkowanie trudne Na egzamin Problem badawczy

ĆW ICZENIA ► 1 . [00] Co oznacza ocena „M20 v? 2.

[10] Co mogą dać Czytelnikowi ćwiczenia? [1Ą] Udowodnij, że 133 ~ 2197. Uogólnij odpowiedź. [To jest przykład okropnego

3. rodzaju zadania, którego autor starał się unikać].

4. [HMĄ5] Udowodnij, że dla całkowitych n, n > 2, równanie x n + yn = zn nie m a rozwiązań w dodatnich liczbach całkowitych x, y, z.

Ale przynajmniej możemy stawić czoło naszej tajem nicy M ożem y metodycznie i w jakim ś porządku posegregować znane nam fakty. — A G A T H A C H R IS T IE , Morderstwo w/ O rien t Expressie [W ypowiedź Herkulesa Poirot. Przekład Anna Wiśn ie wska- W a iczyk, Wydawnictwo Dolnośląskie, W rocław 1991 (przyp. red.)].

SPIS TREŚCI

R o z d z ia ł 1 — P o ję c ia p o d sta w o w e

...................................................................

1

1.1. 1.2.

A lg o ry tm y ................................................................................................................. Podstaw y m atem atyczne .................................................................................... 1.2.1. Indukcja m a te m a ty c z n a ........................................................................... 1.2.2. Liczby, potęgi i lo g a ry tm y ....................................................................... 1.2.3. Sumy i i l o c z y n y ........................................................................................ 1.2.4. Funkcje całkowitoliczbowe ipodstaw y teorii liczb .......................... 1.2.5. Perm utacje i s i l n i a ..................................................................................... 1.2.6. W spółczynniki d w u m ian o w e.................................................................... 1.2.7. Liczby h a r m o n i c z n e ............................................................................... 1.2.8. Liczby F ib o n a c c ie g o ............................................................................... 1.2.9. Funkcje tw o rz ą c e ........................................................................................ 1.2.10. Analiza a lg o r y tm u .................................................................................... *1.2.11. Reprezentacje a s y m p to ty c z n e .............................................................. *1.2.11.1. N otacja w i e l k i e - O ................................................................... * 1 .2 . 1 1 .2 . W zór sumacyjny E u le r a ........................................................... *1.2.11.3. Kilka obliczeń a s y m p to ty c z n y c h .......................................... 1.3. M I X .............................................................................................................................. 1.3.1. Opis maszyny M I X .................................................................................... 1.3.2. Asembler kom putera M I X ....................................................................... 1.3.3. Zastosowania - p e r m u t a c j e ................................................................... 1.4. Podstawowe m etody p ro g ra m is ty c z n e ............................................................... 1.4.1. P o d p r o g r a m y ............................................................................................ 1.4.2. W s p ó łp r o g ra m y ........................................................................................ 1.4.3. I n te r p r e te r y ................................................................................................ 1.4.3.1. Symulator maszyny M I X ............................................................. * 1 .4. 3.2. Ś le d z e n ie ..................................................................................... 1.4.4. Wejście i w y jś c ie ........................................................................................ 1.4.5. Historia i b ib lio g ra fia ...............................................................................

1 11 12 22 28 41 47 55 78 82 90 99 110 111 115 120 128 128 149 169 192 192 200 207 209 218 221 236

R o z d z ia ł 2 — S tr u k tu ry d a n y c h ..........................................................

240

2.1. 2.2.

240 246 246 252 263

W stęp ...................................................................................................................... Listy lin io w e ............................................................................................................. 2.2. 1 . Stosy, kolejki i kolejki d w u s t r o n n e ...................................................... 2.2.2. T a b l i c e ......................................................................................................... 2.2.3. S truktury z d o w ią z a n ia m i....................................................................... xxii

SPIS TREŚCI

x x iii

2.2.4. Listy c y k lic z n e ............................................................................................. 2.2.5. Listy d w u k ie ru n k o w e ................................................................................. 2.2.6. Tablice i listy o r to g o n a ln e ........................................................................ D r z e w a ...................................................................................................................... 2.3.1. Przechodzenie drzew b in a rn y c h ............................................................... 2.3.2. Reprezentacja drzew za pomocą drzew b in a r n y c h ............................... 2.3.3. Inne reprezentacje drzew ........................................................................ 2.3.4. Podstawowe własności m atem atyczne d r z e w ...................................... 2.3.4.1 . Drzewa w o ln e ................................................................................. 2.3.4.2. Drzewa zorientowane...................................................................... *2.3.4.3. Lemat o drzewach niesk o ń czo n y ch ........................................... *2.3.4.4. Zliczanie d r z e w ............................................................................ 2.3.4.5. Długość ś c i e ż k i ............................................................................ *2.3.4.6 . Historia i b i b l i o g r a f i a ................................................................ 2.3.5. Listy i o d ś m ie c a n ie .................................................................................... Struktury z wieloma d o w ią z a n ia m i................................................................... Dynamiczne przydzielanie p a m i ę c i ................................................................... Historia i b ib lio g r a f ia .............................................................................................

283 290 309 320 330 347 361 376 376 386 397 401 415 422 424 441 453 476

Odpowiedzi do ć w ic z e ń .............................................................................................

485

Dodatek A — Tabele wielkości numerycznych ...............................................

647

2.3.

2.4. 2.5. 2.6.

1. 2. 3.

Podstawowe stałe (d z ie s ię tn ie ) ............................................................... Podstawowe stałe (ó s e m k o w o )............................................................... Liczby harmoniczne, liczby Bernoulliego,liczby Fibonacciego . . .

647 648 649

Dodatek B — Wykaz o z n a c z e ń .............................................................................

651

Skorowidz ze słownikiem

656

ROZDZIAŁ

PIERWSZY

POJĘCIA PODSTAWOWE Wiele osób nie znających nauk matem atycznych sądzi, że skoro zadaniem maszyny analitycznej B abbage'a je s t podawanie wyników w notacji liczbowej, je j obliczenia muszą być natury arytmetycznej i numerycznej, a nie algebraicznej I analitycznej. Takie rozumowanie je s t błędne. Maszyna może zestawiać i łączyć wielkości liczbowe tak, jak b y były literam i lub innymi znakami. Tak naprawdę może przedstawiać wyniki w notacji algebraicznej z zachowaniem wszystkich przyjętych reguł. — A U G U S T A ADA , Hrabina Lovelace (1 8 4 4 ) Ćwicz się, na m iły Bóg, w małych rzeczach, a potem przechodź do większych. — E P IK T E T

( Diatryby IV.i)

1.1. ALGO RYTM Y

W dziedzinie programowania komputerów algorytm to rzecz podstawowa. Za­ cznijmy od uważnej analizy tego pojęcia. Słowo „algorytm” jest interesujące samo w sobie. Na pierwszy rzut oka wydaje się, że ktoś chciał napisać „logarytm” , ale pomieszały mu się cztery pierwsze litery. Słowo nie występowało w słownikach do końca lat pięćdziesiątych. Znajdziemy co najwyżej słowo „algorism” i jego archaiczne znaczenie: wykonywa­ nie działań arytmetycznych przy użyciu liczb arabskich. W średniowieczu istniały dwie kategorie rachmistrzów: abacist i algorist. Abacist to ten, który do obli­ czeń wykorzystywał abacus, natom iast algorist liczył, wykorzystując algorism. Do czasów Renesansu pierwotne znaczenie tego słowa poszło w zapomnienie. Pierwsi lingwiści próbowali wywieść je z połączeń w stylu: algiros [bolesny] + arithmos [liczba]; inni twierdzili, że słowo wzięło się od „Króla Algora z K asty­ lii” . Ostatecznie historycy m atem atyki odnaleźli prawdziwe pochodzenie słowa „algorism” : pochodzi ono od imienia autora sławnego perskiego podręcznika, które brzmi Abu ‘Abd Allah M uham mad ibn Musa al-Khwarizrm (około 825 roku) - dosłownie „Ojciec Abdullaha, Mohammed, syn Mojżesza, pochodzący z Khwarizm” . Morze Aralskie w Azji Środkowej było niegdyś znane jako Jezioro Khwarizm, a region Khwarizm znajduje się w dorzeczu Amu-Darii na południe od morza. Al-Khwarizml napisał znaną książkę K itab al-jabr w a’l-muqabala („Za­ sady redukcji i przenoszenia”). Od ty tu łu tej książki, będącej system atycznym studium na tem at rozwiązywania równań liniowych i kwadratowych, pochodzi l

2

POJĘCIA PODSTAWOWE

1.1

inne słowo - „algebra” . [Więcej o życiu i pracach al-Khwärizmlego można zna­ leźć w: H. Zemanek, Lecture Notes in Computer Science 122 (1981), 1-81]. Stopniowo forma i znaczenie słowa algorism zmieniały się. Jak jest to wyjaś­ nione w Oxford English Dictionary, słowo „przeszło wiele pseudo-etymologicznych w ynaturzeń, łącznie z ostatnim algorithm, które jest mylnie brane” za grecki rdzeń słowa arytm etyka. Ta zmiana z algorism na algoritm nie dziwi, jeśli wziąć pod uwagę, że zapomniano, skąd słowo to pochodzi. Wczesny niemiecki słownik matematyczny, Vollständiges m athem atisches Lexicon (Leipzig: 1747), podaje następującą definicję słowa Algorithm us: „pod tym pojęciem kryją się cztery typy obliczeń arytmetycznych, konkretnie dodawanie, mnożenie, odejmowanie i dzielenie” . Łacińskie określenie algorithmus infinitesimalis było w tym czasie używane do nazywania „sposobów obliczania z użyciem nieskończenie małych wartości, jak te wymyślone przez Leibnitza” . Do 1950 roku słowo „algorytm” było najczęściej kojarzone z algorytmem Euklidesa, tj. procesem znajdowania największego wspólnego dzielnika dwóch liczb, opisanym w Elementach Euklidesa (Księga 7, twierdzenia 1 i 2). Pouczające będzie przedstawienie tego algorytmu: A lg o r y tm E {Algorytm Euklidesa). Dane są dwie dodatnie liczby całkowite m i n, należy znaleźć ich największy wspólny dzielnik, tj. największą dodatnią liczbę całkowitą, która dzieli całkowicie zarówno m, jak i n. E l . [Znajdowanie reszty] Podziel m przez n i niech r oznacza resztę z tego dzielenia. (Mamy 0 < r < n). E 2 . [Czy wyszło zero?] Jeśli r = 0, zakończ algorytm; odpowiedzią jest n. E 3. [Upraszczanie] W ykonaj m