<?xml version='1.0' encoding='UTF-8'?><?xml-stylesheet href="http://www.blogger.com/styles/atom.css" type="text/css"?><feed xmlns='http://www.w3.org/2005/Atom' xmlns:openSearch='http://a9.com/-/spec/opensearchrss/1.0/' xmlns:georss='http://www.georss.org/georss' xmlns:gd='http://schemas.google.com/g/2005' xmlns:thr='http://purl.org/syndication/thread/1.0'><id>tag:blogger.com,1999:blog-8336144765189037467</id><updated>2011-11-28T01:14:07.391+01:00</updated><category term='algorytmy'/><category term='metody'/><category term='wydarzenia'/><category term='ciekawe błędy'/><category term='Perełki'/><category term='technikalia'/><category term='Zadania'/><category term='teoria grafów'/><category term='OCaml'/><category term='pogadanka'/><category term='ITPW'/><category term='bash'/><category term='ITPW 2008'/><category term='Struktury danych'/><category term='wykłady'/><category term='przykładowe programy'/><title type='text'>Tematy około algorytmiczne</title><subtitle type='html'>Bo algorytmika to nasza pasja :-)</subtitle><link rel='http://schemas.google.com/g/2005#feed' type='application/atom+xml' href='http://npb-algorytmy.blogspot.com/feeds/posts/default'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/8336144765189037467/posts/default?max-results=100'/><link rel='alternate' type='text/html' href='http://npb-algorytmy.blogspot.com/'/><link rel='hub' href='http://pubsubhubbub.appspot.com/'/><author><name>npb</name><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><generator version='7.00' uri='http://www.blogger.com'>Blogger</generator><openSearch:totalResults>46</openSearch:totalResults><openSearch:startIndex>1</openSearch:startIndex><openSearch:itemsPerPage>100</openSearch:itemsPerPage><entry><id>tag:blogger.com,1999:blog-8336144765189037467.post-7207184492750407635</id><published>2009-09-18T13:40:00.002+02:00</published><updated>2009-09-18T13:59:18.440+02:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='OCaml'/><title type='text'>Pułapka</title><content type='html'>Pisałem ostatnio program wykonujący dość długo skomplikowane obliczenia. Przy pewnych danych wejściowych program przepełniał stos i się wysypywał. Po kilku godzinach frustracji postanowiłem przepisać każdą funkcję na wersję ogonową.&lt;br /&gt;W trakcie tego jak to robiłem zacząłem się zastanawiać nad programowaniem funkcyjnym. Generalnie to jego główną ideą jest to, że piszemy w nim nie jak coś policzyć (tak jak to jest w programowaniu imperatywnym) tylko czym wynik danej funkcji ma być. I to jest bardzo przyjemne i bardzo fajnie się tak pisze - wszystkie funkcje wklepuje się niemal intuicyjnie. Problem jest jak dojdzie do funkcji ogonowych. Funkcje ogonowe (zwłaszcza nieco bardziej skomplikowanych obliczeń) są w ogóle nie intuicyjne. Trzeba zacząć się zastanawiać co ma być akumulatorem (może trzeba dać dwa akumulatory?) jakie dodatkowe informacje należy przekazać itp. itd.&lt;br /&gt;Na szczęście udało mi się wszystkie funkcje przepisać na wersje ogonowe (Teraz jak ktoś spojrzy na kod to już się nie dowie co to a to robi :) ). Nie udało się przepisać tylko jednej. Może ktoś z was będzie miał pomysł. Funkcja dostaje długość listy l oraz sumę s i generuje wszystkie listy o długości l zawierające liczby dodatnie sumujące się co najwyżej do s. Na przykład: funkcja 3 5 = [[1,1,1],[1,1,2],[1,1,3],[1,2,1],[1,2,2],[1,3,1][2,1,1],[2,1,2],[2,2,1],[3,1,1]]. Kolejność list nie jest ważna.&lt;br /&gt;Gdy już miałem prawie wszystkie funkcje ogonowe i sprawdziłem ręcznie, że program nie wywiesza się na tej funkcji nie ogonowej... program dalej się wywieszał :-) Zasięgnąłem zatem opinii dokumentacji i okazało się... że standardowa funkcja map nie jest ogonowa... Troszeczkę się zdenerwowałem. Gdzie kolejność elementów nie była dla mnie ważna użyłem funkcji rev_map. W innych sytuacjach napisałem własną funkcję map:&lt;pre class="mycode"&gt;&lt;br /&gt;let mymap l p = rev (map l p);;&lt;br /&gt;&lt;/pre&gt; Program wciąż nie działa - typ razem już na mojej funkcji (opisanej wyżej). Przepisałem program do C++ działa i to sto razy szybciej ;)&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/8336144765189037467-7207184492750407635?l=npb-algorytmy.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://npb-algorytmy.blogspot.com/feeds/7207184492750407635/comments/default' title='Komentarze do posta'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=8336144765189037467&amp;postID=7207184492750407635' title='Komentarze (1)'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/8336144765189037467/posts/default/7207184492750407635'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/8336144765189037467/posts/default/7207184492750407635'/><link rel='alternate' type='text/html' href='http://npb-algorytmy.blogspot.com/2009/09/puapka.html' title='Pułapka'/><author><name>npb</name><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>1</thr:total></entry><entry><id>tag:blogger.com,1999:blog-8336144765189037467.post-8714273011916741083</id><published>2009-06-28T02:55:00.003+02:00</published><updated>2009-06-28T03:01:58.851+02:00</updated><title type='text'>Labirynt cz II</title><content type='html'>Normalnie bym nie pisał - bo sesja, ale udało mi się odratować kod źródłowy słynnego już labiryntu. Oto i on:&lt;pre class="my code"&gt;&lt;br /&gt;Rysuj&lt;br /&gt;  | form pen ile i |&lt;br /&gt;  form := Display.&lt;br /&gt;  pen := Pen newOnForm: form.&lt;br /&gt;  pen up.&lt;br /&gt;  form fillWhite.&lt;br /&gt; &lt;br /&gt;  ile := lab size.&lt;br /&gt;  i := 1.&lt;br /&gt;  [i &lt;= ile] whileTrue:&lt;br /&gt;  [&lt;br /&gt;    pen goto: (lab at: i).&lt;br /&gt;    pen down.&lt;br /&gt;    pen goto: (lab at: (i+1)).&lt;br /&gt;    pen up.&lt;br /&gt;    i := i + 2.&lt;br /&gt;  ]&lt;br /&gt;&lt;br /&gt;  pen goto: 0@0.&lt;br /&gt;  pen down.&lt;br /&gt;  pen goto: (10*xsize)@0.&lt;br /&gt;  pen goto: (10*xsize)@(10*(ysize // 2)).&lt;br /&gt;  pen goto: 0@(10*(ysize // 2)).&lt;br /&gt;  pen goto: 0@0.&lt;br /&gt;  pen up.&lt;br /&gt;&lt;br /&gt;  pen goto: 0@(10*((ysize // 2) +1)).&lt;br /&gt;  pen down.&lt;br /&gt;  pen goto: (10*xsize)@(10*((ysize // 2) +1)).&lt;br /&gt;  pen goto: (10*xsize)@(10*ysize).&lt;br /&gt;  pen goto: 0@(10*ysize).&lt;br /&gt;  pen goto: 0@(10*((ysize // 2) +1)).&lt;br /&gt;  pen up.&lt;br /&gt;&lt;br /&gt;  pen goto: 0@(10*((ysize // 2) +1) + 1).&lt;br /&gt;  pen down.&lt;br /&gt;  pen goto: (10*xsize)@(10*((ysize // 2) +1) + 1).&lt;br /&gt;  pen up.&lt;br /&gt;&lt;br /&gt;  pen goto: 0@(10*((ysize // 2)) - 1).&lt;br /&gt;  pen down.&lt;br /&gt;  pen goto: (10*xsize)@(10*((ysize // 2)) - 1).&lt;br /&gt;  pen up.&lt;br /&gt;&lt;br /&gt;  [Sensor keyboardPressed] whileFalse: [].&lt;br /&gt;  Display restore.&lt;br /&gt;&lt;br /&gt;Stworz: x y: y&lt;br /&gt;  | r v |&lt;br /&gt;  xsize := x.&lt;br /&gt;  ysize := y.&lt;br /&gt;  r := Random new.&lt;br /&gt;  lab := OrderedCollection new.&lt;br /&gt;  0 to: (x-1) do:&lt;br /&gt;    [:x1 |&lt;br /&gt;      0 to: (y-1) do:&lt;br /&gt;        [:y1 |&lt;br /&gt;          (y1 = (y // 2)) ifFalse:&lt;br /&gt;          [&lt;br /&gt;            v := r nextInt: 5.&lt;br /&gt;            (v &gt; 2) ifTrue:&lt;br /&gt;            [ lab addLast: (10*x1)@(10*y1)&lt;br /&gt;              lab addLast: (10*(x1+1))@(10*y1) ].&lt;br /&gt;            (v &lt; 4) ifTrue:&lt;br /&gt;            [ lab addLast: (10*x1)@(10*y1)&lt;br /&gt;              lab addLast: (10*x1)@(10*(y1+1)) ].&lt;br /&gt;          ].&lt;br /&gt;        ].&lt;br /&gt;    ].&lt;/pre&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/8336144765189037467-8714273011916741083?l=npb-algorytmy.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://npb-algorytmy.blogspot.com/feeds/8714273011916741083/comments/default' title='Komentarze do posta'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=8336144765189037467&amp;postID=8714273011916741083' title='Komentarze (0)'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/8336144765189037467/posts/default/8714273011916741083'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/8336144765189037467/posts/default/8714273011916741083'/><link rel='alternate' type='text/html' href='http://npb-algorytmy.blogspot.com/2009/06/labirynt-cz-ii.html' title='Labirynt cz II'/><author><name>npb</name><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-8336144765189037467.post-378849237817436993</id><published>2009-05-27T20:29:00.004+02:00</published><updated>2009-05-27T21:11:49.039+02:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='pogadanka'/><title type='text'>Labirynt</title><content type='html'>Zadanie brzmiało:&lt;br /&gt;&lt;br /&gt;Zaprogramuj klasę generującą i rysującą labirynt o rozmiarze zadanym podczas tworzenia obiektu. Przyjmij że w labiryncie są tylko dwa wejścia oraz że istnieje droga łącząca te dwa wejścia.&lt;br /&gt;&lt;br /&gt;Zadanie rozwiązałem po najmniejszej linii oporu. Labirynty generowane przez mój algorytm wyglądały mniej więcej tak:&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://3.bp.blogspot.com/_dMhinKIQ0wM/Sh2PAq_pKtI/AAAAAAAAAHk/ldrAmfmp_BY/s1600-h/labirynt.png"&gt;&lt;img style="display:block; margin:0px auto 10px; text-align:center;cursor:pointer; cursor:hand;width: 150px; height: 100px;" src="http://3.bp.blogspot.com/_dMhinKIQ0wM/Sh2PAq_pKtI/AAAAAAAAAHk/ldrAmfmp_BY/s200/labirynt.png" border="0" alt=""id="BLOGGER_PHOTO_ID_5340581974835276498" /&gt;&lt;/a&gt;Prowadzący chciał mnie za to poćwiartkować.. Ale przyznał, że mój algorytm spełnia specyfikację zadania (jest to labirynt z dwoma wejściami taki, że istnieje ścieżka między nimi) i skończyło się na zaliczeniu programu na maksymalną ilość punktów.&lt;br /&gt;&lt;br /&gt;Jako feature dodałem wysoce specjalistyczny algorytm sztucznej inteligencji znajdujący rozwiązania tego typu labiryntów 8)&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/8336144765189037467-378849237817436993?l=npb-algorytmy.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://npb-algorytmy.blogspot.com/feeds/378849237817436993/comments/default' title='Komentarze do posta'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=8336144765189037467&amp;postID=378849237817436993' title='Komentarze (6)'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/8336144765189037467/posts/default/378849237817436993'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/8336144765189037467/posts/default/378849237817436993'/><link rel='alternate' type='text/html' href='http://npb-algorytmy.blogspot.com/2009/05/labirynt.html' title='Labirynt'/><author><name>npb</name><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://3.bp.blogspot.com/_dMhinKIQ0wM/Sh2PAq_pKtI/AAAAAAAAAHk/ldrAmfmp_BY/s72-c/labirynt.png' height='72' width='72'/><thr:total>6</thr:total></entry><entry><id>tag:blogger.com,1999:blog-8336144765189037467.post-8555740973815616100</id><published>2009-05-21T20:15:00.004+02:00</published><updated>2009-05-21T20:34:39.868+02:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='teoria grafów'/><category scheme='http://www.blogger.com/atom/ns#' term='Zadania'/><title type='text'>Cykl Eulera cz II.</title><content type='html'>Cyklem Eulera w grafie nazywamy następujące obejście grafu:&lt;br /&gt;&lt;br /&gt;- zaczynamy w wybranym przez nas wierzchołku&lt;br /&gt;- obchodzimy graf w ten sposób, że każdą krawędź przechodzimy dokładnie raz&lt;br /&gt;- kończymy na wierzchołku w którym zaczęliśmy.&lt;br /&gt;&lt;br /&gt;Jakie warunki musi spełniać graf aby istniał w nim cykl Eulera? Graf przede wszystkim musi być spójny. Jeśli by nie był mogłaby istnieć krawędź do której nie możemy dojść. Ponadto za każdym razem gdy wchodzimy do jakiegoś wierzchołka musimy umieć z niego wyjść. Zatem stopień każdego wierzchołka musi być wielokrotnością dwójki.&lt;br /&gt;&lt;br /&gt;Okazuje się, że jeśli graf spełnia te dwa warunki to istnieje w nim cykl Eulera (dowód przez podanie algorytmu Fleury'ego będzie przedstawiony w którejś z kolejnych notek).&lt;br /&gt;&lt;br /&gt;Zadanie z winniczkiem wydaje się teraz banalne. Spójność grafu mamy dane w treści zadania. Ponadto każdą krawędź w tym grafie musimy przejść dwukrotnie (ścieżki są dwa razy szersze od kosiarki) - zatem spełniony jest również drugi warunek. Zatem w grafie istnieje cykl Eulera. Ponieważ w zadaniu nie proszą nas o znalezienie tego cyklu, a jedynie o podanie w jakim czasie Winicjusz jest w stanie przejść ten graf, więc odpowiadamy: suma wag na krawędziach przemnożona przez dwa.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/8336144765189037467-8555740973815616100?l=npb-algorytmy.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://npb-algorytmy.blogspot.com/feeds/8555740973815616100/comments/default' title='Komentarze do posta'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=8336144765189037467&amp;postID=8555740973815616100' title='Komentarze (0)'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/8336144765189037467/posts/default/8555740973815616100'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/8336144765189037467/posts/default/8555740973815616100'/><link rel='alternate' type='text/html' href='http://npb-algorytmy.blogspot.com/2009/05/cykl-eulera-cz-ii.html' title='Cykl Eulera cz II.'/><author><name>npb</name><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-8336144765189037467.post-5505416123232919643</id><published>2009-05-13T12:10:00.002+02:00</published><updated>2009-05-21T20:35:20.314+02:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='teoria grafów'/><category scheme='http://www.blogger.com/atom/ns#' term='Zadania'/><title type='text'>Cykl Eulera cz I.</title><content type='html'>Oto zadanie, które musiał rozwiązać w miniony weekend. Zadanie wygląda na bardzo trudne, ale z odrobiną teorii okazuje się banalne.&lt;br /&gt;&lt;br /&gt;Jak wszyscy dobrze wiemy, w soboty nie chodzi się do szkoły. Każde dziecko bardzo się z tego powodu cieszy i winniczek Winicjusz nie stanowi pod tym względem wyjątku. Niestety rodzice zaplanowali już, że w sobotę odbędzie się wielkie koszenie trawy w parku przed domem. Ponieważ dawno nikt tego nie robił, park strasznie zarósł i cała rodzina uznała, że nie starczy weekendu, aby doprowadzić go do ładu. Postanowili zatem, że skoszą jedynie trawę rosnącą na ścieżkach.&lt;br /&gt;&lt;br /&gt;Przydomowy park jest bardzo typowy. Poprzecinany jest siecią alejek, które spotykają się ze sobą na ponumerowanych skrzyżowaniach. Ponieważ parki zazwyczaj służą do spacerowania, z dowolnego skrzyżowania można dojść na dowolne inne.&lt;br /&gt;&lt;br /&gt;Ponieważ przyjaciele Winicjusza chcą wyciągnąć go wieczorem na pizzę, winniczek chciałby wiedzieć, ile czasu zajmie mu koszenie trawy. Kosiarka podczas koszenia porusza się z prędkością 1m/s oraz 2m/s, gdy jedzie po skoszonej trawie, a szerokość alejki jest dwa razy większa niż szerokość kosiarki.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/8336144765189037467-5505416123232919643?l=npb-algorytmy.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://npb-algorytmy.blogspot.com/feeds/5505416123232919643/comments/default' title='Komentarze do posta'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=8336144765189037467&amp;postID=5505416123232919643' title='Komentarze (0)'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/8336144765189037467/posts/default/5505416123232919643'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/8336144765189037467/posts/default/5505416123232919643'/><link rel='alternate' type='text/html' href='http://npb-algorytmy.blogspot.com/2009/05/cykl-eulera-cz-i.html' title='Cykl Eulera cz I.'/><author><name>npb</name><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-8336144765189037467.post-4491899457865614855</id><published>2009-05-08T18:22:00.004+02:00</published><updated>2009-05-08T20:22:19.709+02:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='ciekawe błędy'/><title type='text'>Program, który wie jak bardzo został zoptymalizowany.</title><content type='html'>Wczoraj na zajęciach z programowania prowadzący zajęcia powiedział nam o bardzo fajnym programie. Otóż taki program, korzystając z błędów kompilatora wypisywał -O1 kiedy był kompilowany z flagą -O1 oraz -O2 kiedy był kompilowany z flagą -O2. Bardzo zainteresowałem się tematem i postanowiłem wyszukać informacje na temat takiego programu w internecie. Niestety nie znalazłem. Na szczęście wyszukałem na tyle potrzebnych informacji, że udało mi się bez trudu napisać program który sprawdza jak był kompilowany:&lt;pre class="mycode"&gt;[npb@localhost ~]$ cat fun.cpp&lt;br /&gt;#include &lt;stdio.h&gt;&lt;br /&gt;&lt;br /&gt;int main(void)&lt;br /&gt;{&lt;br /&gt;  unsigned long l  = 0x00110011;&lt;br /&gt;  float         f  = *((float*)(&amp;l));&lt;br /&gt;  char*         c  = (char*)(&amp;f);&lt;br /&gt;&lt;br /&gt;  if      (c[0] == 17) printf("-O1\n");&lt;br /&gt;  else                 printf("-O2\n");&lt;br /&gt;&lt;br /&gt;  return 0;&lt;br /&gt;}&lt;br /&gt;[npb@localhost ~]$ g++ -O1 -o funO1 fun.cpp&lt;br /&gt;[npb@localhost ~]$ g++ -O2 -o funO2 fun.cpp&lt;br /&gt;[npb@localhost ~]$ ./funO1&lt;br /&gt;-O1&lt;br /&gt;[npb@localhost ~]$ ./funO2&lt;br /&gt;-O2&lt;br /&gt;[npb@localhost ~]$&lt;/pre&gt;Program nie korzysta z konkretnego błędu w kompilatorze, tylko z faktu że trochę oszukujemy kompilator. Widać że autor nie do końca sam wiedział co chciał zrobić. Udało mi się rozbudować program w taki sposób aby wykrywał również opcję -O3. Okazało się niestety że nie działa to na wszystkich kompilatorach g++; jednak kod przedstawię:&lt;pre class="mycode"&gt;[npb@localhost ~]$ cat fun.cpp&lt;br /&gt;#include &lt;stdio.h&gt;&lt;br /&gt;&lt;br /&gt;unsigned long long_it(unsigned long in)&lt;br /&gt;{&lt;br /&gt;  return 0x00110011;&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;float float_it(float in)&lt;br /&gt;{&lt;br /&gt;  unsigned long v = long_it(*((unsigned long*)(&amp;in)));&lt;br /&gt;  return *((float*)(&amp;v));&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;int main(void)&lt;br /&gt;{&lt;br /&gt;  float notimportant = 10;&lt;br /&gt;  float retval       = float_it(notimportant);&lt;br /&gt;  char  *retvalP     = (char*)(&amp;retval);&lt;br /&gt;&lt;br /&gt;  if      (retvalP[0] == 17) printf("-O1\n");&lt;br /&gt;  else if (retvalP[0] == 0)  printf("-O2\n");&lt;br /&gt;  else                       printf("-O3\n");&lt;br /&gt;&lt;br /&gt;  return 0;&lt;br /&gt;}&lt;br /&gt;[npb@localhost ~]$ g++ -O1 -o funO1 fun.cpp&lt;br /&gt;[npb@localhost ~]$ g++ -O2 -o funO2 fun.cpp&lt;br /&gt;[npb@localhost ~]$ g++ -O3 -o funO3 fun.cpp&lt;br /&gt;[npb@localhost ~]$ ./funO1&lt;br /&gt;-O1&lt;br /&gt;[npb@localhost ~]$ ./funO2&lt;br /&gt;-O2&lt;br /&gt;[npb@localhost ~]$ ./funO3&lt;br /&gt;-O3&lt;br /&gt;[npb@localhost ~]$&lt;/pre&gt;&lt;br /&gt;Postawie browara pierwszej osobie, której uda się ten sam trick z opcją -g :)&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/8336144765189037467-4491899457865614855?l=npb-algorytmy.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://npb-algorytmy.blogspot.com/feeds/4491899457865614855/comments/default' title='Komentarze do posta'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=8336144765189037467&amp;postID=4491899457865614855' title='Komentarze (4)'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/8336144765189037467/posts/default/4491899457865614855'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/8336144765189037467/posts/default/4491899457865614855'/><link rel='alternate' type='text/html' href='http://npb-algorytmy.blogspot.com/2009/05/program-ktory-wie-jak-bardzo-zosta.html' title='Program, który wie jak bardzo został zoptymalizowany.'/><author><name>npb</name><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>4</thr:total></entry><entry><id>tag:blogger.com,1999:blog-8336144765189037467.post-9024220646448439366</id><published>2009-05-08T11:21:00.003+02:00</published><updated>2009-05-08T12:16:53.164+02:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='ciekawe błędy'/><title type='text'>Niebezpieczne makra cz II.</title><content type='html'>Spójrzmy raz jeszcze raz na program. Po podstawieniu za makro instrukcji if jest on postaci:&lt;pre class="mycode"&gt;// Program pierwszy&lt;br /&gt;if (warunek1)&lt;br /&gt;  if (warunek2)&lt;br /&gt;    instrukcja1;&lt;br /&gt;else&lt;br /&gt;  instrukcja2;&lt;/pre&gt;Spostrzegawczy czytelnik na pewno zauważy, że instrukcja2 tak na prawdę powinna być kolejnym ifem, jednak dla czytelności kodu zostawię ją tak jak jest.&lt;br /&gt;W programie nie ma nawiasów klamrowych. Wcięcia sugerują, że instrukcja2 powinna zostać wykonana wtedy, gdy nie spełniony zostanie warunek1. Jednakże kompilator nie zwraca uwagi na wcięcia. Powyższy program i poniższy są dla kompilatora identyczne:&lt;pre class="mycode"&gt;// Program drugi&lt;br /&gt;if (warunek1)&lt;br /&gt;  if (warunek2)&lt;br /&gt;    instrukcja1;&lt;br /&gt;  else&lt;br /&gt;    instrukcja2;&lt;/pre&gt;Widzimy, że te dwa programy różnią się od siebie. Instrukcja2 wykonywana jest tylko wtedy gdy zostanie spełniony warunek pierwszy i niezostanie spełniony warunek drugi.&lt;br /&gt;Powyższe programy dla kompilatora który ignoruje białe znaki jest identyczny? Pytanie zatem: jak kompilator traktuje taki kod. Tak jak program pierwszy czy tak jak program drugi? Okazuje się że gdy kompilator napotyka słowo kluczowe "else" próbuje je związać z ostatnią napotkaną pętlą "if". Zatem zinterpretuje kod źródłowy tak jak w programie drugim.&lt;br /&gt;&lt;br /&gt;Aby unikać takich sytuacji dobrze jest stosować nawiasy klamrowe w ifach. Dobrym pomysłem jest też zamykanie w klamry całego makra.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/8336144765189037467-9024220646448439366?l=npb-algorytmy.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://npb-algorytmy.blogspot.com/feeds/9024220646448439366/comments/default' title='Komentarze do posta'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=8336144765189037467&amp;postID=9024220646448439366' title='Komentarze (0)'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/8336144765189037467/posts/default/9024220646448439366'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/8336144765189037467/posts/default/9024220646448439366'/><link rel='alternate' type='text/html' href='http://npb-algorytmy.blogspot.com/2009/05/niebezpieczne-makra-cz-ii.html' title='Niebezpieczne makra cz II.'/><author><name>npb</name><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-8336144765189037467.post-2351456442373250588</id><published>2009-05-06T08:09:00.005+02:00</published><updated>2009-05-06T08:44:47.340+02:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='ciekawe błędy'/><title type='text'>Niebezpieczne makra cz I.</title><content type='html'>Wczoraj wieczorem zabrałem się za rozwiązanie zadania z pracowni z ASD. Trochę za późno się za to wziąłem, bo na dwie godziny przed oddaniem programu byłem na etapie czytania treści zadania. Po napisaniu programu zająłem się debugowaniem. Doszedłem do wniosku, że błąd tkwi w poniższej pętli warunkowej.&lt;pre class="mycode"&gt;if (j-KLOCKI[i] &gt;= 0)&lt;br /&gt;  assign(TAB[j-KLOCKI[i]][p2], TAB[j][p1]);&lt;br /&gt;else&lt;br /&gt;  assign(TAB[KLOCKI[i]-j][p2], TAB[j][p1]+KLOCKI[i]-j);&lt;/pre&gt;Przyglądałem się bardzo uważnie tym instrukcjom, ale nie umiałem dojść dlaczego program nie wchodzi do instrukcji w ciele else. Pomocną informacją może okazać się że assign to makro:&lt;pre class="mycode"&gt;#define assign(a,b) if ((a) &lt; (b)) a = (b)&lt;/pre&gt;Mógłbym popsuć wam zabawę i napisać gdzie tkwi błąd. Jednak tego nie zrobię. Opiszę to dopiero w następnej notce. Życzę miłej zabawy :-)&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/8336144765189037467-2351456442373250588?l=npb-algorytmy.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://npb-algorytmy.blogspot.com/feeds/2351456442373250588/comments/default' title='Komentarze do posta'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=8336144765189037467&amp;postID=2351456442373250588' title='Komentarze (3)'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/8336144765189037467/posts/default/2351456442373250588'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/8336144765189037467/posts/default/2351456442373250588'/><link rel='alternate' type='text/html' href='http://npb-algorytmy.blogspot.com/2009/05/niebezpieczne-makra-cz-i.html' title='Niebezpieczne makra cz I.'/><author><name>npb</name><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>3</thr:total></entry><entry><id>tag:blogger.com,1999:blog-8336144765189037467.post-8393194922705386201</id><published>2009-04-30T09:37:00.006+02:00</published><updated>2009-04-30T10:47:03.935+02:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='metody'/><category scheme='http://www.blogger.com/atom/ns#' term='algorytmy'/><title type='text'>Wyszukiwanie maksimum lokalnego cz II. - O szybkim turyście i chciwym bacy</title><content type='html'>Treść tego zadania jest bardzo głupia :) Chciałem ją zmodyfikować, ale stwierdziłem, że tak będzie śmieszniej :) Miłej lektury.&lt;br /&gt;&lt;br /&gt;Mamy dany graf w którym wyróżniono dwa wierzchołki - A oraz B. Z każdą krawędzią i są związane dwie liczby rzeczywiste: a&lt;sub&gt;i&lt;/sub&gt; oraz b&lt;sub&gt;i&lt;/sub&gt;. Koszt przejechania tej krawędzi w czasie t wynosi a&lt;sub&gt;i&lt;/sub&gt;t + b&lt;sub&gt;i&lt;/sub&gt;.&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://2.bp.blogspot.com/_dMhinKIQ0wM/SflgIjacTHI/AAAAAAAAAG4/lQX6ypgNKVA/s1600-h/baca1.png"&gt;&lt;img style="display:block; margin:0px auto 10px; text-align:center;cursor:pointer; cursor:hand;width: 200px; height: 100px;" src="http://2.bp.blogspot.com/_dMhinKIQ0wM/SflgIjacTHI/AAAAAAAAAG4/lQX6ypgNKVA/s200/baca1.png" border="0" alt=""id="BLOGGER_PHOTO_ID_5330397334031060082" /&gt;&lt;/a&gt;Turysta chce przejść z punktu A do B. Turysta jest bardzo sprytny i w dowolnym czasie t potrafi znaleźć najtańszą drogę z punktu A do B. Jest też bardzo bardzo szybki (struś pędziwiatr to przy nim żółw) i całą trasę potrafi przebiec w czasie zerowym!&lt;br /&gt;&lt;br /&gt;Pytanie: W jakim czasie T z przedziału [0, 1] baca powinien wypuścić turystę ze swojej chatki, aby zmaksymalizować swój zysk?&lt;br /&gt;&lt;br /&gt;Co ma z tym wspólnego maksimum lokalne? Dla każdej ścieżki w grafie jej koszt jest funkcją liniową zależną od T.&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://3.bp.blogspot.com/_dMhinKIQ0wM/SflgdGvTxxI/AAAAAAAAAHA/H42LlSuyT5g/s1600-h/baca2.png"&gt;&lt;img style="display:block; margin:0px auto 10px; text-align:center;cursor:pointer; cursor:hand;width: 165px; height: 81px;" src="http://3.bp.blogspot.com/_dMhinKIQ0wM/SflgdGvTxxI/AAAAAAAAAHA/H42LlSuyT5g/s200/baca2.png" border="0" alt=""id="BLOGGER_PHOTO_ID_5330397687111206674" /&gt;&lt;/a&gt;Zatem baca jeśli wypuści turystę w czasie T zarobi min(T) dudków, gdzie min(T) jest dane wzorem:&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://3.bp.blogspot.com/_dMhinKIQ0wM/SflkOA3X5lI/AAAAAAAAAHI/gd8OYdgQoHI/s1600-h/baca3.png"&gt;&lt;img style="display:block; margin:0px auto 10px; text-align:center;cursor:pointer; cursor:hand;width: 200px; height: 40px;" src="http://3.bp.blogspot.com/_dMhinKIQ0wM/SflkOA3X5lI/AAAAAAAAAHI/gd8OYdgQoHI/s200/baca3.png" border="0" alt=""id="BLOGGER_PHOTO_ID_5330401825882891858" /&gt;&lt;/a&gt;Spójrzmy na wykres tej funkcji.&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://4.bp.blogspot.com/_dMhinKIQ0wM/SfllHK94boI/AAAAAAAAAHQ/o3PoETXMxFo/s1600-h/baca4.png"&gt;&lt;img style="display:block; margin:0px auto 10px; text-align:center;cursor:pointer; cursor:hand;width: 200px; height: 200px;" src="http://4.bp.blogspot.com/_dMhinKIQ0wM/SfllHK94boI/AAAAAAAAAHQ/o3PoETXMxFo/s200/baca4.png" border="0" alt=""id="BLOGGER_PHOTO_ID_5330402807847087746" /&gt;&lt;/a&gt;Funkcja ma tylko jedno maksimum lokalne. Możemy zatem użyć wyszukiwania ternarnego (wystarczy tylko uogólnić algorytm na przedział rzeczywisty - co pozostawiam jako proste ćwiczenie ;) )&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/8336144765189037467-8393194922705386201?l=npb-algorytmy.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://npb-algorytmy.blogspot.com/feeds/8393194922705386201/comments/default' title='Komentarze do posta'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=8336144765189037467&amp;postID=8393194922705386201' title='Komentarze (0)'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/8336144765189037467/posts/default/8393194922705386201'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/8336144765189037467/posts/default/8393194922705386201'/><link rel='alternate' type='text/html' href='http://npb-algorytmy.blogspot.com/2009/04/wyszukiwanie-maksimum-lokalnego-cz-ii-o.html' title='Wyszukiwanie maksimum lokalnego cz II. - O szybkim turyście i chciwym bacy'/><author><name>npb</name><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://2.bp.blogspot.com/_dMhinKIQ0wM/SflgIjacTHI/AAAAAAAAAG4/lQX6ypgNKVA/s72-c/baca1.png' height='72' width='72'/><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-8336144765189037467.post-5474884695464867261</id><published>2009-04-29T12:29:00.004+02:00</published><updated>2009-04-29T13:16:50.435+02:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='algorytmy'/><title type='text'>Wyszukiwanie maksimum lokalnego cz I. - wyszukiwanie ternarne</title><content type='html'>Mamy daną tablicę A[1..n] wypełnioną parami różnymi liczbami rzeczywistymi. Element, który jest większy od swoich sąsiadów nazywamy maksimum lokalnym. W tej notce przedstawię algorytm, który dla danej tablicy znajdzie (jakieś) maksimum lokalne.&lt;br /&gt;W pierwszej kolejności sprawdźmy elementy A[1] oraz A[n]. Mają one tylko jednego sąsiada. Jeśli zatem A[1] jest większe niż A[2] albo A[n] jest większe od A[n-1] to znaleźliśmy maksimum lokalne i kończymy algorytm.&lt;br /&gt;Co jednak jeśli tak nie jest? Wyobraźmy sobie tablice jako wierzchołki. Krawędź między dwoma wierzchołkami jest skierowana w stronę większego elementu. Mamy zatem taką sytuację:&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://3.bp.blogspot.com/_dMhinKIQ0wM/SfgztsJWAjI/AAAAAAAAAGg/m6caWjzmi_U/s1600-h/ternarne.png"&gt;&lt;img style="margin: 0px auto 10px; display: block; text-align: center; cursor: pointer; width: 200px; height: 20px;" src="http://3.bp.blogspot.com/_dMhinKIQ0wM/SfgztsJWAjI/AAAAAAAAAGg/m6caWjzmi_U/s200/ternarne.png" alt="" id="BLOGGER_PHOTO_ID_5330067019030463026" border="0" /&gt;&lt;/a&gt;Algorytm działa rekurencyjnie. Oznaczmy zatem element najbardziej na lewo jako A[l], a najbardziej na prawo jako A[r]. Niezmiennikiem naszego wywołania rekurencyjnego będzie to że element A[l] jest mniejszy od A[l+1] a element A[r] jest mniejszy od elementu A[r-1] (rysunek powyżej). Można łatwo udowodnić że w takim przedziale znajduje się maksimum lokalne.&lt;br /&gt;Weźmy dwa środkowe elementy tablicy. Oznaczmy je jako A[p] oraz A[q]. Zapytajmy się który z nich jest większy.&lt;br /&gt;Jeśli A[p] &lt; A[q] to rozwiązanie znajduje się w przedziale A[p..r].&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://4.bp.blogspot.com/_dMhinKIQ0wM/SfgztsmLzoI/AAAAAAAAAGo/vCB5hNNAx2s/s1600-h/ternarne2.png"&gt;&lt;img style="margin: 0px auto 10px; display: block; text-align: center; cursor: pointer; width: 200px; height: 40px;" src="http://4.bp.blogspot.com/_dMhinKIQ0wM/SfgztsmLzoI/AAAAAAAAAGo/vCB5hNNAx2s/s200/ternarne2.png" alt="" id="BLOGGER_PHOTO_ID_5330067019151429250" border="0" /&gt;&lt;/a&gt;Jeśli A[p] &gt; A[q] to rozwiązanie znajduje się w przedziale A[l..q].&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://4.bp.blogspot.com/_dMhinKIQ0wM/SfgztoYjrUI/AAAAAAAAAGw/4jTRvDodI7M/s1600-h/ternarne3.png"&gt;&lt;img style="margin: 0px auto 10px; display: block; text-align: center; cursor: pointer; width: 200px; height: 40px;" src="http://4.bp.blogspot.com/_dMhinKIQ0wM/SfgztoYjrUI/AAAAAAAAAGw/4jTRvDodI7M/s200/ternarne3.png" alt="" id="BLOGGER_PHOTO_ID_5330067018020531522" border="0" /&gt;&lt;/a&gt;Nie zdarzy się, ża A[p] = A[q] bo założyliśmy że elementy są parami różne. Algorytm zatrzymuje się gdy w dostajemy tablicę 3 elementową (można łatwo udowodnić, że na taką tablicę trafimy: gdy natrafiamy na tablicę rozmiaru 4 to następnie uruchamiamy się dla tablicy 3 elementowej; gdy natrafimy na tablicę rozmiaru 5 to następnie uruchamiamy się dla tablicy albo 3 elementowej albo 4 elementowej). Gdy natrafimy na tablicę 3 elementową to zgodnie z niezmiennikiem algorytmu jego środkowy element będzie maksimum lokalnym.&lt;br /&gt;Algorytm jako że w każdej iteracji wykonuje stałą liczbę operacji, a zawsze przedział dzielony jest na "prawie" połowę to działa w czasie O(lg n).&lt;br /&gt;Jeśli elementy w tablicy najpierw rosną, a potem maleją (lub odwrotnie) to tablica taka ma tylko jedno maksimum (minimum) lokalne i jest nim największy (najmniejszy) element w tablicy. Zatem w tego rodzajach tablic jesteśmy w stanie znaleźć element największy (najmniejszy) w czasie logarytmicznym!&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/8336144765189037467-5474884695464867261?l=npb-algorytmy.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://npb-algorytmy.blogspot.com/feeds/5474884695464867261/comments/default' title='Komentarze do posta'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=8336144765189037467&amp;postID=5474884695464867261' title='Komentarze (1)'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/8336144765189037467/posts/default/5474884695464867261'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/8336144765189037467/posts/default/5474884695464867261'/><link rel='alternate' type='text/html' href='http://npb-algorytmy.blogspot.com/2009/04/wyszukiwanie-maksimum-lokalnego-cz-i.html' title='Wyszukiwanie maksimum lokalnego cz I. - wyszukiwanie ternarne'/><author><name>npb</name><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://3.bp.blogspot.com/_dMhinKIQ0wM/SfgztsJWAjI/AAAAAAAAAGg/m6caWjzmi_U/s72-c/ternarne.png' height='72' width='72'/><thr:total>1</thr:total></entry><entry><id>tag:blogger.com,1999:blog-8336144765189037467.post-4714029303719612700</id><published>2009-03-13T19:37:00.009+01:00</published><updated>2009-03-15T13:35:03.286+01:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Struktury danych'/><category scheme='http://www.blogger.com/atom/ns#' term='Perełki'/><title type='text'>Posortowana lista w sqrt(n)</title><content type='html'>Mamy posortowaną listę. Chcemy przy użyciu dodatkowej O(sqrt(n)) ilości pamięci umieć wstawiać i usuwać elementy z tej listy w czasie O(sqrt(n)).&lt;br /&gt;&lt;br /&gt;Takie zadanie pojawiło się na pierwszej liście z AiSD. Większość rozwiązań tego zadania dzieliło listę na pierwiastek z n bloków o równej długości. Sprawiało to wiele problemów w sytuacjach w których należało zwiększyć liczbę bloków (jak to zrobić, aby zmieścić się w czasie O(sqrt(n))?). Moje rozwiązanie opierało się na nieco innym pomyśle, dzięki czemu cała struktura danych staje się bardzo prosta i elegancka.&lt;br /&gt;&lt;br /&gt;Podzielmy listę (dwukierunkową) na bloki. Pierwszy blok będzie miał jeden element; drugi blok dwa elementy, trzeci trzy... i tak dalej. Przy czym dopuszczamy, aby ostatni blok był niepełny. To będzie nasz niezmiennik. Taka lista będzie miała k dodatkowych wskaźników (na początki bloków) i każdy z bloków będzie miał rozmiar nie większy niż k. Liczba elementów na takiej liście będzie równa 1 + 2 + 3 + ... + k = k(k+1) / 2 = n. Zatem jak widzimy k jest rzędu O(sqrt(n)).&lt;br /&gt;&lt;br /&gt;Wstawianie elementu el wykonujemy w czterech prostych krokach:&lt;br /&gt; - Szukamy do którego bloku musi trafić element el (O(k) operacji).&lt;br /&gt; - Szukamy w które miejsce ma trafić element i umieszczamy go w tym miejscu (O(k)).&lt;br /&gt; - Przywracamy niezmiennik listy. Robimy to w ten sposób, że wskaźniki do wszystkich bloków znajdujących się na prawo od wstawionego elementu przesuwamy o jeden element w lewo (O(k) operacji).&lt;br /&gt; - Jeśli ostatni blok przekroczy dozwolony rozmiar, to tworzymy nowy blok (O(1)).&lt;br /&gt;Wstawienie elementu prezentuje poniższy rysunek.&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://4.bp.blogspot.com/_dMhinKIQ0wM/SbrPbyzYC_I/AAAAAAAAAGA/kU_isa0sJWY/s1600-h/sqrt.bmp"&gt;&lt;img style="display:block; margin:0px auto 10px; text-align:center;cursor:pointer; cursor:hand;width: 349px; height: 218px;" src="http://4.bp.blogspot.com/_dMhinKIQ0wM/SbrPbyzYC_I/AAAAAAAAAGA/kU_isa0sJWY/s1600/sqrt.bmp" border="0" alt=""id="BLOGGER_PHOTO_ID_5312786786837597170" /&gt;&lt;/a&gt;Usuwanie elementu w sposób analogiczny.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/8336144765189037467-4714029303719612700?l=npb-algorytmy.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://npb-algorytmy.blogspot.com/feeds/4714029303719612700/comments/default' title='Komentarze do posta'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=8336144765189037467&amp;postID=4714029303719612700' title='Komentarze (2)'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/8336144765189037467/posts/default/4714029303719612700'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/8336144765189037467/posts/default/4714029303719612700'/><link rel='alternate' type='text/html' href='http://npb-algorytmy.blogspot.com/2009/03/posortowana-lista-w-sqrtn.html' title='Posortowana lista w sqrt(n)'/><author><name>npb</name><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://4.bp.blogspot.com/_dMhinKIQ0wM/SbrPbyzYC_I/AAAAAAAAAGA/kU_isa0sJWY/s72-c/sqrt.bmp' height='72' width='72'/><thr:total>2</thr:total></entry><entry><id>tag:blogger.com,1999:blog-8336144765189037467.post-380426219224606441</id><published>2009-03-08T16:40:00.005+01:00</published><updated>2009-03-08T19:18:05.844+01:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='wykłady'/><title type='text'>ZOSIA wykład</title><content type='html'>Na &lt;a href="http://zosia2009.pl/"&gt;Zimowym Obozie Studentów Informatyki (ZOSIa)&lt;/a&gt; przedstawiłem wykład na temat gry SZOK. Zgodnie z obietnicą umieszczam tutaj materiały do wykładu. Poprawioną wersję &lt;a href="http://sites.google.com/site/npbalgorytmy/Home/SZOK.pdf?attredirects=0"&gt;prezentacji&lt;/a&gt;. &lt;a href="http://sites.google.com/site/npbalgorytmy/Home/Dokumentacja.pdf?attredirects=0"&gt;Dokumentację&lt;/a&gt; projektu (gorąco polecam! :) znajduje się w niej opis instalacji). Oraz wreszcie samą grę &lt;a href="http://sites.google.com/site/npbalgorytmy/Home/szok_v0.71.tar.gz?attredirects=0"&gt;SZOK&lt;/a&gt;. W razie problemów z linkami proszę o kontakt.&lt;br /&gt;&lt;br /&gt;Szok to prosta gra w której musimy pomóc owieczce pozbierać z planszy wszystkie marchewki. W tym celu piszemy program w języku logo-podobnym i uruchamiamy go w symulatorze.&lt;br /&gt;I nie byłoby w tej grze nic wyjątkowego, gdyby na każdej planszy nie znajdował się smok. Smok jest także programem napisanym pseudo-logo. Nie chodzi on jednak po planszy, tylko po kodzie źródłowym owieczki i zjada z niego instrukcje…&lt;br /&gt;&lt;br /&gt;Do plansz islandofsecrets oraz piratestreasure nie ustaliłem limitów. Nie chciałem ich obierać "na oko", a sam tych planszy jeszcze nie przeszedłem (w sumie nawet nie próbowałem). Osoby, które przejdą te plansze i chcą pomóc przy ustalaniu progów są proszone o kontakt ze mną :-)&lt;br /&gt;Pozdrawiam!&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/8336144765189037467-380426219224606441?l=npb-algorytmy.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://npb-algorytmy.blogspot.com/feeds/380426219224606441/comments/default' title='Komentarze do posta'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=8336144765189037467&amp;postID=380426219224606441' title='Komentarze (0)'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/8336144765189037467/posts/default/380426219224606441'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/8336144765189037467/posts/default/380426219224606441'/><link rel='alternate' type='text/html' href='http://npb-algorytmy.blogspot.com/2009/03/zosia-wykad.html' title='ZOSIA wykład'/><author><name>npb</name><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-8336144765189037467.post-4226401524510675981</id><published>2009-02-12T14:05:00.004+01:00</published><updated>2009-02-12T14:55:42.381+01:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='przykładowe programy'/><category scheme='http://www.blogger.com/atom/ns#' term='bash'/><title type='text'>Niecierpliwiec</title><content type='html'>Kolokwium już napisane, teraz najgorsze - czekanie na wyniki. Zazwyczaj sprawa wyglądała tak, że wchodziło się na stronę wykładowcy i odświeżało się ją co kilka minut. Na dłuższą metę jest to po prostu nie wygodne i męczące. A że potrzeba jest matką wynalazków... prezentuję niecierpliwca. Ten kilkulinijkowy skrypt ułatwia już życie niejednemu studentowi :)&lt;pre class="mycode"&gt;#!/bin/bash&lt;br /&gt;echo "Niecierpliwiec v. 0.3"&lt;br /&gt;echo "Autor: Krzysztof Piecuch"&lt;br /&gt;rm -f Wzorzec.html Kopia.html&lt;br /&gt;wget -O Wzorzec.html -q $1&lt;br /&gt;&lt;br /&gt;while [ true ]&lt;br /&gt;do&lt;br /&gt;   sleep 20&lt;br /&gt;   wget -O Kopia.html -q $1&lt;br /&gt;   if ! diff -q Kopia.html Wzorzec.html&lt;br /&gt;   then&lt;br /&gt;      mplayer Muzyka/coś_tam.mp3&lt;br /&gt;      break&lt;br /&gt;   fi&lt;br /&gt;   rm -f Kopia.html&lt;br /&gt;done&lt;/pre&gt;Program ma jedną wadę. Czasami zdarza się, że wgetowi nie uda się pobrać strony. Przez co tworzy w miejscu kopii pusty plik. Następnie diff wykrywa różnice między tym plikiem a wzorcem i wszczyna niepotrzebny alarm.&lt;br /&gt;Program wciąż w fazie testów.&lt;br /&gt;Zamiast uruchamiania mplayera polecam beepa. Jednak na moim sprzęcie beep nie działa :-) Życzę miłej zabawy i powodzenia w sesji poprawkowej ;-)&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/8336144765189037467-4226401524510675981?l=npb-algorytmy.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://npb-algorytmy.blogspot.com/feeds/4226401524510675981/comments/default' title='Komentarze do posta'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=8336144765189037467&amp;postID=4226401524510675981' title='Komentarze (2)'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/8336144765189037467/posts/default/4226401524510675981'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/8336144765189037467/posts/default/4226401524510675981'/><link rel='alternate' type='text/html' href='http://npb-algorytmy.blogspot.com/2009/02/niecierpliwiec.html' title='Niecierpliwiec'/><author><name>npb</name><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>2</thr:total></entry><entry><id>tag:blogger.com,1999:blog-8336144765189037467.post-7068275975709733863</id><published>2009-02-06T20:42:00.007+01:00</published><updated>2009-02-07T22:11:03.801+01:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Struktury danych'/><category scheme='http://www.blogger.com/atom/ns#' term='Perełki'/><title type='text'>Wielopoziomowa Lista Liczb Całkowitych</title><content type='html'>Zadanie z kursu ANSI C brzmiało:&lt;br /&gt;&lt;br /&gt;Wielopoziomową Listę Liczb Całkowitych (w skrócie WLLC) definiujemy jako skończony (w tym także pusty) ciąg, którego elementami są liczby całkowite lub WLLC. Jeśli lista zawiera tylko liczby to nazywamy ją jednopoziomową. Przykłady L1 = [3,1,5]; L2 = [2,[4,7],[]]; L3 = [[[3],[5,8],2],[1,5]]. Lista L1 jest jednopoziomowa. Zdefiniować moduł WLLC (tzn. podać zawartość plików wllc.c oraz wllc.h), w którym:&lt;br /&gt;- Zdefiniowana jest funkcja WLLC merge(WLLC l1, WLLC l2), która zwraca listę powstałą z dołączenia listy l2 na końcu listy l1. Na przykład dołączenie listy L1 na końcu listy L2 powinno stworzyć listę [2,[4,7],[],3,1,5].&lt;br /&gt;- Zdefiniowana jest funkcja WLLC flat(WLLC li), która tworzy nową listę jednopoziomową zawierającą wszystkie liczby z listy li z zachowaniem ich kolejności. Na przykład wywołanie flat(L3) powinno zwrócić listę [3,5,8,2,1,5].&lt;br /&gt;&lt;br /&gt;Ja na tym kolokwium podszedłem do tego zadania bardzo rutynowo i stworzyłem strukturę, która wyglądała mniej więcej tak:&lt;pre class="mycode"&gt;struct WLLCnode&lt;br /&gt;{&lt;br /&gt;  bool  isWLLC;    // True jeśli element jest listą WLLC&lt;br /&gt;  int   intvalue;  // Wartość liczbowa&lt;br /&gt;  WLLC* WLLCvalue; // Wartość listowa&lt;br /&gt;  WLLC* next;      // Wskaźnik na następny element&lt;br /&gt;};&lt;br /&gt;typedef WLLCnode* WLLC;&lt;/pre&gt;Po czym występowały definicje funkcji. Trochę się zamotałem z tymi wskaźnikami,&lt;br /&gt;&lt;blockquote&gt;"Dać programiście wskaźniki to tak jakby dać małpie karabin maszynowy" Piotr Chrząstowski-Wachtel&lt;/blockquote&gt;&lt;br /&gt;pokreśliłem pół kartki ale ostatecznie coś wyszło i o dziwo okazało się poprawne. Nie mam zamiaru odtwarzać tego rozwiązania, ale wierzcie mi - było straszne :D. Natomiast Maciek zaczął to zadanie tak:&lt;pre class="mycode"&gt;typedef char* WLLC;&lt;/pre&gt;i wszystkie funkcje pisze się miło i przyjemnie. Bardzo spodobało mi się to rozwiązanie. Z moją pomocą udało się zmniejszyć złożoność obu funkcji do liniowych i zmniejszyć rozmiar tych funkcji do kilku linijek.&lt;br /&gt;&lt;br /&gt;Pierwsza funkcja jest bardzo prosta, aż niema co w niej opisywać. Rezerwujemy pamięć, kopiujemy pierwszą listę, kopiujemy drugą listę, wstawiamy przecinek w odpowiednie miejsce. Osobno rozważamy przypadki gdy lista jest pusta.&lt;pre class="mycode"&gt;WLLC merge(WLLC a, WLLC b)&lt;br /&gt;{&lt;br /&gt;  int lena = strlen(a);&lt;br /&gt;  int lenb = strlen(b);&lt;br /&gt;  WLLC answer = malloc((lena + lenb) * sizeof(char));&lt;br /&gt;  &lt;br /&gt;  // Jeśli lista a jest pusta - zwróć listę b&lt;br /&gt;  if (lena == 2)&lt;br /&gt;    return strcpy(answer, b);&lt;br /&gt;&lt;br /&gt;  // Analogicznie&lt;br /&gt;  if (lenb == 2)&lt;br /&gt;    return strcpy(answer, a);&lt;br /&gt;  &lt;br /&gt;  strcpy(answer, a);&lt;br /&gt;  strcpy(answer + lena, b + 1);&lt;br /&gt;  answer[lena - 1] = ',';&lt;br /&gt;&lt;br /&gt;  return answer;&lt;br /&gt;}&lt;/pre&gt;Z funkcją flat na początku były kłopoty. Maciek strasznie zakręcił... ale rozwiązanie jest dość proste:&lt;pre class="mycode"&gt;WLLC flat(WLLC a)&lt;br /&gt;{&lt;br /&gt;  int  j = 1;&lt;br /&gt;  bool inint = false;&lt;br /&gt;  WLLC answer = malloc(strlen(a) * sizeof(char));&lt;br /&gt;  &lt;br /&gt;  answer[0] = '[';&lt;br /&gt;  for (int i = 0; a[i] != '\0'; i++)&lt;br /&gt;  {&lt;br /&gt;    if (('0' &lt;= a[i] &amp;&amp; a[i] &lt;= '9') || a[i] == '-')&lt;br /&gt;    {&lt;br /&gt;      answer[j++] = a[i];&lt;br /&gt;      inint = true;&lt;br /&gt;    }&lt;br /&gt;    else&lt;br /&gt;    {&lt;br /&gt;      if (inint) answer[j++] = ',';&lt;br /&gt;      inint = false;&lt;br /&gt;    }&lt;br /&gt;  }&lt;br /&gt;  if (j == 1) j++;&lt;br /&gt;  answer[j-1] = ']';&lt;br /&gt;  answer[j]   = '\0';&lt;br /&gt;  &lt;br /&gt;  return answer;&lt;br /&gt;}&lt;/pre&gt;&lt;br /&gt;Iterator i przebiega listę, którą chcemy spłaszczyć. Iterator j przebiega naszą listę wynikową. Jeśli na danej nam liście znajduje się cyfra - to ją przepisujemy. Jeśli nie, to sprawdzamy czy nowy znak zakończył nam jakąś liczbę (służy nam do tego zmienna "inint"). Jeśli zakończył to stawiamy przecinek. Na końcu zamykamy nawias i zwracamy wynik. Warunek if na samym końcu zapewnia nas, że zwrócimy poprawny wynik także dla listy pustej. Przykład użycia:&lt;pre class = "mycode"&gt;  WLLC L0 = "[]";&lt;br /&gt;  WLLC L1 = "[3,1,5]";&lt;br /&gt;  WLLC L2 = "[2,[4,7],[]]";&lt;br /&gt;  WLLC L3 = "[[[3],[5,8],2],[1,5]]";&lt;br /&gt;  &lt;br /&gt;  printf("%s\n", merge(L2, L1));&lt;br /&gt;  printf("%s\n", flat(L3));&lt;/pre&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/8336144765189037467-7068275975709733863?l=npb-algorytmy.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://npb-algorytmy.blogspot.com/feeds/7068275975709733863/comments/default' title='Komentarze do posta'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=8336144765189037467&amp;postID=7068275975709733863' title='Komentarze (2)'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/8336144765189037467/posts/default/7068275975709733863'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/8336144765189037467/posts/default/7068275975709733863'/><link rel='alternate' type='text/html' href='http://npb-algorytmy.blogspot.com/2009/02/wielopoziomowa-lista-liczb-cakowitych.html' title='Wielopoziomowa Lista Liczb Całkowitych'/><author><name>npb</name><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>2</thr:total></entry><entry><id>tag:blogger.com,1999:blog-8336144765189037467.post-584453661109533350</id><published>2009-01-31T18:09:00.001+01:00</published><updated>2009-01-31T18:11:09.550+01:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='wydarzenia'/><title type='text'>Delta</title><content type='html'>Został jeszcze tydzień sesji i przez ten czas pewnie nie napiszę nic kreatywnego na tym blogu. Jeśli jednak ktoś chciałby mnie poczytać, to w nowym numerze Delty znajduje się mój artykuł poświęcony Algorytmowi SPFA. Życzę przyjemnej lektury.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/8336144765189037467-584453661109533350?l=npb-algorytmy.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://npb-algorytmy.blogspot.com/feeds/584453661109533350/comments/default' title='Komentarze do posta'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=8336144765189037467&amp;postID=584453661109533350' title='Komentarze (0)'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/8336144765189037467/posts/default/584453661109533350'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/8336144765189037467/posts/default/584453661109533350'/><link rel='alternate' type='text/html' href='http://npb-algorytmy.blogspot.com/2009/01/delta.html' title='Delta'/><author><name>npb</name><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-8336144765189037467.post-2745121749355262678</id><published>2009-01-16T22:14:00.003+01:00</published><updated>2009-01-16T22:47:41.886+01:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='wydarzenia'/><title type='text'>100 ciekawych wpisów</title><content type='html'>Mój blog (a konkretnie notka o &lt;a href="http://npb-algorytmy.blogspot.com/2008/11/5-najbardziej-spektakularnych-bdw.html"&gt;5 najbardziej spektakularnych błędów oprogramowania&lt;/a&gt;) trafił na &lt;a href="http://antyweb.pl/setka-ciekawych-wpisow-z-polskich-blogow-czyli-kto-wygral-gta-iv-i-tomb-raidera/"&gt;antywebową listę 100 ciekawych notek&lt;/a&gt;.&lt;br /&gt;&lt;br /&gt;W związku ze zbliżającą się sesją nie mam za wiele czasu na prowadzenie tego bloga. Nie będą się zatem w przeciągu najbliższych dwóch tygodni pojawiały notki.&lt;br /&gt;W Ferie postaram się nadrobić zaległości ;)&lt;br /&gt;&lt;br /&gt;Pozdrawiam&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/8336144765189037467-2745121749355262678?l=npb-algorytmy.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://npb-algorytmy.blogspot.com/feeds/2745121749355262678/comments/default' title='Komentarze do posta'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=8336144765189037467&amp;postID=2745121749355262678' title='Komentarze (2)'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/8336144765189037467/posts/default/2745121749355262678'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/8336144765189037467/posts/default/2745121749355262678'/><link rel='alternate' type='text/html' href='http://npb-algorytmy.blogspot.com/2009/01/100-ciekawych-wpisw.html' title='100 ciekawych wpisów'/><author><name>npb</name><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>2</thr:total></entry><entry><id>tag:blogger.com,1999:blog-8336144765189037467.post-685971379283012064</id><published>2009-01-01T13:46:00.004+01:00</published><updated>2009-01-02T14:16:17.694+01:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='wydarzenia'/><title type='text'>2009 (0x07D9)</title><content type='html'>Ile jest w systemach bugów&lt;br /&gt;Ile w internecie znajdziesz cracków&lt;br /&gt;Ile lamer stracił danych&lt;br /&gt;Ile na rapidzie plików wgranych&lt;br /&gt;Ile w skrzynce miałeś spamu&lt;br /&gt;Ile Vista zżera ramu&lt;br /&gt;Ile notek na tym blogu&lt;br /&gt;Tyle szczęścia w nowym roku&lt;br /&gt;&lt;br /&gt;życzy npb&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/8336144765189037467-685971379283012064?l=npb-algorytmy.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://npb-algorytmy.blogspot.com/feeds/685971379283012064/comments/default' title='Komentarze do posta'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=8336144765189037467&amp;postID=685971379283012064' title='Komentarze (0)'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/8336144765189037467/posts/default/685971379283012064'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/8336144765189037467/posts/default/685971379283012064'/><link rel='alternate' type='text/html' href='http://npb-algorytmy.blogspot.com/2009/01/2009-0x07d9.html' title='2009 (0x07D9)'/><author><name>npb</name><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-8336144765189037467.post-1061139032492278741</id><published>2008-12-20T10:24:00.004+01:00</published><updated>2009-01-06T06:39:12.932+01:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='OCaml'/><title type='text'>Fresh i Reset bez użycia zmiennych globalnych</title><content type='html'>Rozważmy następujący problem. Mamy stworzyć dwie funkcje: fresh i reset. Pierwsza z nich ma generować kolejne liczby naturalne dodatnie, druga ma nam posłużyć do zerowania naszego stanu liczniki. Przykładowa &lt;!-- google_ad_section_start --&gt;sesja programu&lt;!-- google_ad_section_end --&gt; może wyglądać na przykład tak:&lt;pre style="mycode"&gt;# fresh ();;&lt;br /&gt;- : int = 1&lt;br /&gt;# fresh ();;&lt;br /&gt;- : int = 2&lt;br /&gt;# fresh ();;&lt;br /&gt;- : int = 3&lt;br /&gt;# fresh ();;&lt;br /&gt;- : int = 4&lt;br /&gt;# reset ();;&lt;br /&gt;- : unit = ()&lt;br /&gt;# fresh ();;&lt;br /&gt;- : int = 1&lt;br /&gt;# fresh ();;&lt;br /&gt;- : int = 2&lt;/pre&gt;Cały problem w napisaniu tej funkcji polega na tym, że w &lt;!-- google_ad_section_start --&gt;implementacji&lt;!-- google_ad_section_end --&gt; nie możemy korzystać ze &lt;!-- google_ad_section_start --&gt;zmiennych globalnych&lt;!-- google_ad_section_end --&gt;. Polecam, abyś sam przez chwilę zastanowił się jak ten problem rozwiązać zanim przeczytasz moje rozwiązanie.&lt;br /&gt;&lt;br /&gt;&lt;!-- google_ad_section_start --&gt;Zmienna w OCamlu&lt;!-- google_ad_section_end --&gt; "żyje" tak długo aż istnieje wskaźnik na tą wartość. I nie ważne czy &lt;!-- google_ad_section_start --&gt;zmienna&lt;!-- google_ad_section_end --&gt; ta została &lt;!-- google_ad_section_start --&gt;zdefiniowana globalnie czy lokalnie w funkcji&lt;!-- google_ad_section_end --&gt;.&lt;br /&gt;&lt;br /&gt;Pierwszy pomysł to stworzenie &lt;!-- google_ad_section_start --&gt;funkcji&lt;!-- google_ad_section_end --&gt;, która jako argument bierze unit, a zwraca parę funkcji (fresh, reset). Zadeklaruje ona &lt;!-- google_ad_section_start --&gt;lokalnie zmienną&lt;!-- google_ad_section_end --&gt;, która będzie użyta do &lt;!-- google_ad_section_start --&gt;zdefiniowania funkcji&lt;!-- google_ad_section_end --&gt;. Po wyjściu zmienna ta nie będzie już nigdzie widoczna poza zwróconą parą funkcji.&lt;pre style="mycode"&gt;type r = { mutable x : int };;&lt;br /&gt;&lt;br /&gt;let create () =&lt;br /&gt;    let y = ref {x = 0} in&lt;br /&gt;    ((fun () -&gt; (ignore (!y.x &lt;- !y.x + 1) ; (!y.x))),&lt;br /&gt;      fun () -&gt; ignore (!y.x &lt;- 0));;&lt;br /&gt;&lt;br /&gt;let x = create () ;;&lt;br /&gt;let fresh = fst x and reset = snd x;;&lt;/pre&gt;Takie rozwiązanie ma swoje wady i zalety. Zaletą jest to że możemy tworzyć wiele par fresh-reset, wadą to, że pozwalamy na korzystanie ze zmiennej x bez konieczności użycia funkcji fresh i reset.&lt;br /&gt;&lt;br /&gt;Edit: W komentarzach pojawiły się inne (imho lepsze) rozwiązania tego zadania. Polecam lekturę tych komentarzy ;)&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/8336144765189037467-1061139032492278741?l=npb-algorytmy.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://npb-algorytmy.blogspot.com/feeds/1061139032492278741/comments/default' title='Komentarze do posta'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=8336144765189037467&amp;postID=1061139032492278741' title='Komentarze (4)'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/8336144765189037467/posts/default/1061139032492278741'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/8336144765189037467/posts/default/1061139032492278741'/><link rel='alternate' type='text/html' href='http://npb-algorytmy.blogspot.com/2008/12/fresh-i-reset-bez-uycia-zmiennych.html' title='Fresh i Reset bez użycia zmiennych globalnych'/><author><name>npb</name><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>4</thr:total></entry><entry><id>tag:blogger.com,1999:blog-8336144765189037467.post-4067890326585766691</id><published>2008-12-18T18:05:00.002+01:00</published><updated>2008-12-18T18:11:44.872+01:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='wydarzenia'/><title type='text'>20 000</title><content type='html'>Dzisiejszego dnia strona została wyświetlona po raz 20 000. Dziękuję wszystkim moim Czytelnikom. To dla was tworzę tego bloga.&lt;br /&gt;&lt;br /&gt;W najbliższym tygodniu napiszę najprawdopodobniej dwa artykuły dotyczące programowaniu w OCamlu. W pierwszej opiszę pewną sztuczkę z dzieleniem zmiennych pomiędzy dwie funkcje, bez użycia zmiennych globalnych. W drugiej stworzymy gwiazdkę Kocha (tak świątecznie :))&lt;br /&gt;&lt;br /&gt;Pozdrawiam!&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/8336144765189037467-4067890326585766691?l=npb-algorytmy.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://npb-algorytmy.blogspot.com/feeds/4067890326585766691/comments/default' title='Komentarze do posta'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=8336144765189037467&amp;postID=4067890326585766691' title='Komentarze (0)'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/8336144765189037467/posts/default/4067890326585766691'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/8336144765189037467/posts/default/4067890326585766691'/><link rel='alternate' type='text/html' href='http://npb-algorytmy.blogspot.com/2008/12/20-000.html' title='20 000'/><author><name>npb</name><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-8336144765189037467.post-8343283137176341070</id><published>2008-12-15T21:57:00.000+01:00</published><updated>2008-12-15T22:00:48.716+01:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='wydarzenia'/><title type='text'>Do pobrania</title><content type='html'>Zmieniłem serwis na którym trzymam pliki z sekcji "do pobrania". Mam nadzieję, że teraz wszystkim będzie się żyło lepiej :)&lt;br /&gt;Pozdrawiam&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/8336144765189037467-8343283137176341070?l=npb-algorytmy.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://npb-algorytmy.blogspot.com/feeds/8343283137176341070/comments/default' title='Komentarze do posta'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=8336144765189037467&amp;postID=8343283137176341070' title='Komentarze (0)'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/8336144765189037467/posts/default/8343283137176341070'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/8336144765189037467/posts/default/8343283137176341070'/><link rel='alternate' type='text/html' href='http://npb-algorytmy.blogspot.com/2008/12/do-pobrania.html' title='Do pobrania'/><author><name>npb</name><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-8336144765189037467.post-6461443369029012726</id><published>2008-12-07T12:50:00.002+01:00</published><updated>2008-12-07T13:04:32.323+01:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='wydarzenia'/><title type='text'>Wykop</title><content type='html'>Kilka dni temu Alek poinformował mnie, że mój blog (a właściwie notka o najbardziej spektakularnych błędach) trafił na &lt;a href="http://www.wykop.pl/link/118248/5-najbardziej-spektakularnych-bledow-oprogramowania"&gt;stronę główną wykopu&lt;/a&gt;. Zdobył nawet bardzo przyzwoity wynik :). Mam nadzieję, że dzięki wykopowi zdobędę kilku nowych czytelników. Ja natomiast obiecuję wciąż trzymać dobry poziom moich notek.&lt;br /&gt;Pozdrawiam serdecznie wszystkich wykopowiczów!&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/8336144765189037467-6461443369029012726?l=npb-algorytmy.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://npb-algorytmy.blogspot.com/feeds/6461443369029012726/comments/default' title='Komentarze do posta'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=8336144765189037467&amp;postID=6461443369029012726' title='Komentarze (0)'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/8336144765189037467/posts/default/6461443369029012726'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/8336144765189037467/posts/default/6461443369029012726'/><link rel='alternate' type='text/html' href='http://npb-algorytmy.blogspot.com/2008/12/wykop.html' title='Wykop'/><author><name>npb</name><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-8336144765189037467.post-4809228326126852245</id><published>2008-12-04T18:49:00.004+01:00</published><updated>2008-12-05T11:17:12.455+01:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='ciekawe błędy'/><category scheme='http://www.blogger.com/atom/ns#' term='OCaml'/><title type='text'>Błędy w OCamlu</title><content type='html'>Programy w OCamlu pisze się bardzo przyjemnie. Schody zaczynają się gdy OCaml chce nas poinformować, że zrobiliśmy błąd. Często robi to tak nieudolnie, że bardzo trudno jest błąd nawet zlokalizować. Dziś przez pół godziny szukałem z Maćkiem błędu w implementacji Grafu. Błąd znaleźliśmy, ale w zupełnie innym module niż ten na który wskazywał OCaml.&lt;br /&gt;Dziś rano z kolei OCaml powitał mnie komunikatem&lt;br /&gt;&lt;blockquote&gt;File "Database.ml", line 54, characters 17-25:&lt;br /&gt;This pattern matches values of type punkt&lt;br /&gt;but is here used to match values of type punkt&lt;/blockquote&gt;&lt;br /&gt;Bardzo zdziwiłem się widząc ten komunikat. I chyba nie znalazłbym błędu, gdybym nie widział podobnego błędu wcześniej. Troszkę starań i OCaml wypluje nam taki komunikat:&lt;br /&gt;&lt;blockquote&gt;This expression has type t but is here used with type t&lt;/blockquote&gt;&lt;br /&gt;Jak zmusić OCamla do wyplucia takiego błędu? Opiszemy za chwilę. Na razie spróbujmy zrozumieć co tak na prawdę OCaml ma na myśli. Rozważmy następującą sesję ewaluatora:&lt;pre class="mycode"&gt;# type typ1 = Konstruktor | Innykonstruktor;;&lt;br /&gt;type typ1 = Konstruktor | Innykonstruktor&lt;br /&gt;&lt;br /&gt;# Konstruktor;;&lt;br /&gt;- : typ1 = Konstruktor&lt;br /&gt;&lt;br /&gt;# type typ2 = Konstruktor | Jeszczeinnykonstruktor;;&lt;br /&gt;type typ2 = Konstruktor | Jeszczeinnykonstruktor&lt;br /&gt;&lt;br /&gt;# Konstruktor;;&lt;br /&gt;- : typ2 = Konstruktor&lt;/pre&gt;W trzecim poleceniu do zdefiniowania typu "typ2" użyliśmy ponownie konstruktora "Konstruktor". Przesłoniliśmy w ten sposób konstruktor o tej samej nazwie z typu pierwszego. Nie będziemy mogli już z niego normalnie korzystać. Gdy użyjemy teraz w dowolnym miejscu konstruktora "Konstruktor" zostanie on potraktowany jako konstruktor z typu drugiego (a nie jako konstruktor typu pierwszego).&lt;pre class="mycode"&gt;# type t = Konstruktor of int;;&lt;br /&gt;type t = Konstruktor of int&lt;br /&gt;&lt;br /&gt;# let get_int a = match a with Konstruktor b -&gt; b;;&lt;br /&gt;val get_int : t -&gt; int = &lt;fun&gt;&lt;br /&gt;&lt;br /&gt;# type t = Konstruktor of int;;&lt;br /&gt;type t = Konstruktor of int&lt;br /&gt;&lt;br /&gt;# let osiem = Konstruktor 8;;&lt;br /&gt;val osiem : t = Konstruktor 8&lt;br /&gt;&lt;br /&gt;# get_int osiem;;&lt;br /&gt;This expression has type t but is here used with type t&lt;/pre&gt;Przeanalizujmy co tutaj się stało. W pierwszej linijce tworzymy nowy typ t. W drugiej linijce definiujemy funkcję, która jako argument bierze typ t - ten z pierwszej linijki (mniejsza o to co ta funkcja robi). W linijce trzeciej tworzymy nowy typ t (ma on nawet tą samą definicję co nasz pierwszy typ t - mimo to będzie traktowany jako nowy typ). Przesłaniamy w ten sposób pierwszy typ t. W linijce czwartej definiujemy wartość "osiem" używając konstruktora "Konstruktor". Jak wiemy z poprzedniego akapitu - będzie to wartość typu t zadeklarowanego w 3 linijce. Na koniec próbujemy wywołać funkcję od wartości "osiem", która jest typu t (zdefiniowanego w linijce 3) podczas gdy funkcja przyjmuje argumenty typu t (zdefiniowane w linijce pierwszej).&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/8336144765189037467-4809228326126852245?l=npb-algorytmy.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://npb-algorytmy.blogspot.com/feeds/4809228326126852245/comments/default' title='Komentarze do posta'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=8336144765189037467&amp;postID=4809228326126852245' title='Komentarze (0)'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/8336144765189037467/posts/default/4809228326126852245'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/8336144765189037467/posts/default/4809228326126852245'/><link rel='alternate' type='text/html' href='http://npb-algorytmy.blogspot.com/2008/12/bdy-w-ocamlu.html' title='Błędy w OCamlu'/><author><name>npb</name><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-8336144765189037467.post-5683384769236575654</id><published>2008-11-30T11:52:00.009+01:00</published><updated>2008-12-04T07:54:50.012+01:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='ciekawe błędy'/><category scheme='http://www.blogger.com/atom/ns#' term='pogadanka'/><title type='text'>5 najbardziej spektakularnych błędów oprogramowania</title><content type='html'>&lt;!-- google_ad_section_start --&gt;Informatyka&lt;!-- google_ad_section_end --&gt; jest wszędzie. &lt;!-- google_ad_section_start --&gt;Programy komputerowe&lt;!-- google_ad_section_end --&gt; otaczają nas zewsząd. W banku, w szpitalu, na ulicach, w elektrowniach. Nawet nie wiemy jak wiele zależy w naszym życiu od tego czy programy te zostały rzetelnie przetestowane przez &lt;!-- google_ad_section_start --&gt;programistów&lt;!-- google_ad_section_end --&gt;. Przedstawiam ranking 5 najbardziej spektakularnych błędów w &lt;!-- google_ad_section_start --&gt;oprogramowaniu&lt;!-- google_ad_section_end --&gt;. Błędy te pochłonęły miliony dolarów, a co gorsza - w wyniku tych błędów zginęli ludzie.&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight:bold;"&gt;5 miejsce&lt;br /&gt;Therac-25&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;Therac-25 jest maszyną do radioterapii. Między 1985 a 1987 rokiem odnotowano przynajmniej 6 przypadków w których pacjentom podano za dużą dawkę promieniowania. Pacjenci zachorowali na chorobę popromienną. Pięciu z nich z tego powodu zmarło.&lt;br /&gt;Powodem był błąd oprogramowania spowodowany tak zwaną sytuacją wyścigu (race condtition). Z sytuacją taką mamy do czynienia na przykład gdy wynik działania jakiegoś procesu zależy od zgrania z czasem lub innych zdarzeń (procesów). Problem ten jest skomplikowany i nie będę się tu nim zajmował. Osób zainteresowanych tym tematem odsyłam do &lt;a href="http://www.nfsec.pl/hakin9/wyscig.pdf"&gt;artykułu Michała Wojciechowskiego&lt;/a&gt;.&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight:bold;"&gt;4 miejsce&lt;br /&gt;Blackout 2003&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;14 sierpnia 2003 roku miała miejsce największa awaria zasilania w historii. Odciętych od prądu zostało 50 mln ludzi. W USA całkowicie od prądu zostały odłączone stany Ohio, Nowy Jork, New England, Massachusetts, Connecticut, Michigan, Pensylwania oraz północne New Jersey. W Kanadzie prowincja Quebec i Ontario. W wyniku awarii zostało wyłączonych 100 elektrowni (w tym 22 atomowe), przestały kursować pociągi, stanęły windy, ulice zostały zakorkowane z powodu braku sygnalizacji świetlnej. Na kilku lotniskach zawieszono loty. Działalność zawiesiła nowojorska giełda towarowa. Mieszkańcy stanu Michigan ucierpieli dodatkowo w wyniku braku wody, która dostarczana jest tam za pomocą pomp elektrycznych. W samym Nowym Jorku straż pożarna odnotowała 3000 zgłoszeń do pożarów (wywołanych zazwyczaj nieumiejętnym posługiwaniem się świeczkami). Awaria zasilania pochłonęła co najmniej 11 ofiar.&lt;br /&gt;Na tą awarię złożyło się kilka czynników. Jednym z nich był błąd w programie w którym dochodziło do sytuacji wyścigu (patrz wyżej).&lt;br /&gt;&lt;a href="http://pl.youtube.com/watch?v=65GRh-b81C0&amp;feature=related"&gt;Wydanie specjalne wiadomości.&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight:bold;"&gt;3 miejsce&lt;br /&gt;Mariner 1&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;22 lipca 1966 roku wystartowała sonda kosmiczna Mariner 1. Po 5 minutach lotu oficer bezpieczeństwa widząc nienormalne zachowanie się rakiety wydał polecenie autodestrukcji.&lt;br /&gt;Błąd w oprogramowaniu wynikał... ze złego przepisania wzoru z kartki... Smutne, ale prawdziwe. Przepisujący nie zauważył kreski nad pochodną w czasie n-tego promienia. Kreska oznacza funkcję wygładzania. Bez tej kreski komputer traktował najmniejszą zmianę prędkości bardzo poważnie i wykonywał serię gwałtownych manewrów.&lt;br /&gt;Straty szacuje się na około 18.5 mln $.&lt;br /&gt;&lt;a href="http://dayton.hq.nasa.gov/IMAGES/SMALL/GPN-2000-000608.jpg"&gt;Zdjęcie startu Mariner 1&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight:bold;"&gt;2 miejsce&lt;br /&gt;Masakra w Dhahran&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;25 lutego 1991 roku iracka rakieta typu SCUD trafia w barak w Dhahranie (Arabia Saudyjska) zabijając 28 amerykańskich żołnierzy. Zawiodło oprogramowanie systemu obrony przeciwlotniczej PATRIOT.&lt;br /&gt;Zmienne zmiennoprzecinkowe mają taką własność, że małe liczby są zapamiętywane z dużą dokładnością, natomiast wielkie z niewielką dokładnością. Jest to bardzo przydatna własność. Gdy chcemy zmierzyć wielkość bakterii to błędy rzędu milimetra powodują, że nasze obliczania nadają się tylko do śmietnika. Jednak gdybyśmy chcieli zmierzyć odległość z Ziemi do Księżyca to jesteśmy w stanie zaakceptować błędy rzędu kilometrów.&lt;br /&gt;Zegar (licznik) baterii patriot liczył czas w zmiennej całkowitej. Następnie w celu dalszych obliczeń ten licznik rzutowany był na liczbę zmiennoprzecinkową. Gdy wartość licznika była duża to błąd bezwzględny był również duży. Podczas gdy Irakijczycy wystrzelili rakietę, system PATRIOT działał już od ponad 100 godzin. Błąd zegara po zrzutowaniu na zmienną zmiennoprzecinkową wynosił około 1/3 sekundy. Co przy prędkościach pocisków balistycznych spowodowało błąd obliczenia celu pocisku o około 700 metrów! System PATRIOT zawiódł.&lt;br /&gt;Amerykanie wiedzieli o tym błędzie. Odpowiednia poprawka oprogramowania była już w drodze. Do Arabii doszła dzień po tragedii.&lt;br /&gt;Masakry można było uniknąć. Wystarczyło co kilka godzin zerować wartość licznika.&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight:bold;"&gt;1 miejsce&lt;br /&gt;Ariane Lot 501&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;Choć to zazwyczaj Amerykanom zdarzały się spektakularne klęski, to niestety z bólem serca Europejczykom muszę przyznać pierwsze miejsce w tym rankingu.&lt;br /&gt;4 czerwca 1996 roku. Z kosmodromu Kourou w Gujanie Francuskiej w swój pierwszy lot testowy wyrusza europejska rakieta Ariane 5. Po 37 sekundach lotu rakieta zeszła z kursu i została zniszczona przez system autodestrukcji. Straty szacuje się na około 370 mln $. Sam koszt wystrzelenia takiej rakiety to około 180 mln $.&lt;br /&gt;Choć przed lotem próbnym przetestowano dokładnie cały sprzęt, to nie przetestowano oprogramowania. Bo i po co? Przecież został on niemal w całości skopiowany z Ariane 4, na którym to działał bez zarzutów. Jednak Ariane 5 miał szybsze silniki niż jego poprzednik, przez co oprogramowanie generowało większe liczby. Błąd pojawił się, gdy 64 bitową zmienną zmiennoprzecinkową program próbował zrzutować na 16-bitową zmienną całkowitą. Gdy wartość liczby 64-bitowej nie mogła się zmieścić w 16 bitach, komputer rzucił wyjątek (arithmetic overflow). Spowodowało to efekt domina - komputer zaczął rzucać serię kolejnych wyjątków. Końcowym efektem było zboczenie rakiety z kursu i autodestrukcja.&lt;br /&gt;&lt;a href="http://www.youtube.com/watch?v=IONcgYzVFlg"&gt;Film z feralnego lotu można znaleźć tutaj&lt;/a&gt;.&lt;br /&gt;&lt;br /&gt;Starałem się rzetelnie opisać na czym polegały błędy w oprogramowaniu, choć szukając źródeł trafiałem bardzo często na sprzeczne ze sobą informacje. Niech nie zdziwi was zatem fakt, że być może znajdziecie w innych źródłach inne wyjaśnienia dotyczące błędów w opisanych przeze mnie sytuacjach.&lt;br /&gt;&lt;br /&gt;Po tym artykule trochę inaczej będę podchodził do tego gdy mój ćwiczeniowiec znowu krzyknie: "Aha! Pana program źle działa dla takich danych wejściowych!".&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/8336144765189037467-5683384769236575654?l=npb-algorytmy.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://npb-algorytmy.blogspot.com/feeds/5683384769236575654/comments/default' title='Komentarze do posta'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=8336144765189037467&amp;postID=5683384769236575654' title='Komentarze (13)'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/8336144765189037467/posts/default/5683384769236575654'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/8336144765189037467/posts/default/5683384769236575654'/><link rel='alternate' type='text/html' href='http://npb-algorytmy.blogspot.com/2008/11/5-najbardziej-spektakularnych-bdw.html' title='5 najbardziej spektakularnych błędów oprogramowania'/><author><name>npb</name><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>13</thr:total></entry><entry><id>tag:blogger.com,1999:blog-8336144765189037467.post-95702744414882027</id><published>2008-11-28T20:10:00.007+01:00</published><updated>2008-11-28T20:53:57.988+01:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='przykładowe programy'/><category scheme='http://www.blogger.com/atom/ns#' term='OCaml'/><title type='text'>Zbiór Mandelbrota w OCamlu</title><content type='html'>Ostatnio na pracowni z &lt;!-- google_ad_section_start --&gt;programowania funkcyjnego&lt;!-- google_ad_section_end --&gt; kazano nam napisać program w &lt;!-- google_ad_section_start --&gt;OCamlu&lt;!-- google_ad_section_end --&gt; rysujący zbiór Mandelbrota.&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://2.bp.blogspot.com/_dMhinKIQ0wM/STBMFJUra3I/AAAAAAAAAEY/6fBFXQRFUz4/s1600-h/mdelbrot.png"&gt;&lt;img style="display:block; margin:0px auto 10px; text-align:center;cursor:pointer; cursor:hand;width: 192px; height: 200px;" src="http://2.bp.blogspot.com/_dMhinKIQ0wM/STBMFJUra3I/AAAAAAAAAEY/6fBFXQRFUz4/s200/mdelbrot.png" border="0" alt=""id="BLOGGER_PHOTO_ID_5273798814936558450" /&gt;&lt;/a&gt;Postanowiłem zamieścić tutaj swoje rozwiązanie dlatego, że niewiarygodne jest jakie piękne efekty możemy otrzymać za pomocą 20-linijkowego programu.&lt;br /&gt;&lt;pre class="mycode"&gt;(* Mandelbrot :-) *)&lt;br /&gt;&lt;br /&gt;#load "graphics.cma";;&lt;br /&gt;open Graphics;;&lt;br /&gt;open Complex;;&lt;br /&gt;&lt;br /&gt;let conve a =&lt;br /&gt;    float_of_int(a) /. (640. /. 4.) -. 2.;;&lt;br /&gt;&lt;br /&gt;let rec calc_color p zn k =&lt;br /&gt;    if      k = 0 then 0&lt;br /&gt;    else if norm zn &gt;= 2. then k&lt;br /&gt;    else    calc_color p (add (mul zn zn) p) (k-1);;&lt;br /&gt;&lt;br /&gt;let display () =&lt;br /&gt;open_graph " 640x640";&lt;br /&gt;for x = 0 to 640 do&lt;br /&gt;   for y = 0 to 640 do&lt;br /&gt;      let p = {re = conve x; im = conve y} in&lt;br /&gt;      let k = 8 * calc_color p p 31 in&lt;br /&gt;      set_color (rgb k k k);&lt;br /&gt;      plot x y&lt;br /&gt;   done&lt;br /&gt;done;&lt;br /&gt;let _ = read_key () in close_graph();;&lt;/pre&gt;Zbiorem Mandelbrota nazywamy zbiór punktów p na przestrzeni zespolonej, który spełnia warunek |z&lt;sub&gt;n&lt;/sub&gt;| &lt; 2. Przy czym z&lt;sub&gt;0&lt;/sub&gt; = p oraz z&lt;sub&gt;n&lt;/sub&gt; = z&lt;sub&gt;n-1&lt;/sub&gt; * z&lt;sub&gt;n-1&lt;/sub&gt; + p dla n &gt; 0. Przybliżenie tego zbioru otrzymujemy ustalając pewną liczbę powtórzeń m, a następnie sprawdzając, które punkty płaszczyzny spełniają z&lt;sub&gt;0&lt;/sub&gt; &lt; 2, z&lt;sub&gt;1&lt;/sub&gt; &lt; 2, ..., z&lt;sub&gt;m&lt;/sub&gt; &lt; 2.&lt;br /&gt;&lt;br /&gt;Funkcja conve zamienia liczbę naturalną z przedziału [0..640] (w oknie o rozdzielczości 640x640 będziemy rysowali zbiór Mandelbrota) na liczbę rzeczywistą z przedziału [-2..2] (jeśli, któraś ze współrzędnych danego punktu jest spoza tego przedziału to punkt ten nie należy do zbioru Mandelbrota).&lt;br /&gt;&lt;br /&gt;Funkcja calc_color liczy kolejne wartości ciągu z&lt;sub&gt;n&lt;/sub&gt; dla n = 0..k i szuka najmniejszego takiego m, że z&lt;sub&gt;m&lt;/sub&gt; &gt;= 2. Funkcja zwraca k - m. Od tej wartości będzie zależał kolor na jaki pomalujemy dany punkt na płaszczyźnie (stąd nazwa).&lt;br /&gt;&lt;br /&gt;Funkcja display tworzy okno o rozmiarach 640 x 640. Następnie dla każdego piksela w tym oknie liczymy jego współrzędne zespolone. Następnie obliczamy kolor w jakim będziemy malować ten piksel, ustawiamy pędzel na ten kolor i na końcu malujemy ten piksel na dany kolor.&lt;br /&gt;&lt;br /&gt;O &lt;!-- google_ad_section_start --&gt;funkcyjnym paradygmacie programowania&lt;!-- google_ad_section_end --&gt; napiszę słów kilka w niedalekiej przyszłości.&lt;br /&gt;Jeśli coś było niejasnego w tej notce, lub notka zawiera błąd, to będę wdzięczny za komentarze.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/8336144765189037467-95702744414882027?l=npb-algorytmy.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://npb-algorytmy.blogspot.com/feeds/95702744414882027/comments/default' title='Komentarze do posta'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=8336144765189037467&amp;postID=95702744414882027' title='Komentarze (1)'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/8336144765189037467/posts/default/95702744414882027'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/8336144765189037467/posts/default/95702744414882027'/><link rel='alternate' type='text/html' href='http://npb-algorytmy.blogspot.com/2008/11/zbir-mandelbrota-w-ocamlu.html' title='Zbiór Mandelbrota w OCamlu'/><author><name>npb</name><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://2.bp.blogspot.com/_dMhinKIQ0wM/STBMFJUra3I/AAAAAAAAAEY/6fBFXQRFUz4/s72-c/mdelbrot.png' height='72' width='72'/><thr:total>1</thr:total></entry><entry><id>tag:blogger.com,1999:blog-8336144765189037467.post-7556164135924251888</id><published>2008-11-11T22:48:00.003+01:00</published><updated>2008-11-12T07:28:46.351+01:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='ITPW 2008'/><category scheme='http://www.blogger.com/atom/ns#' term='ITPW'/><category scheme='http://www.blogger.com/atom/ns#' term='wydarzenia'/><title type='text'>Weronika</title><content type='html'>W dziale "do pobrania" pojawił się program Weronika v 8.0. Program walczący, który w tegorocznej edycji Internetowego Turnieju Programów Walczących zajął 16 miejsce.&lt;br /&gt;&lt;br /&gt;Imię Weronika pochodzi z języka greckiego: phero - nieść; nike - zwycięstwo. Dosłownie "Nosząca zwycięstwo".&lt;br /&gt;&lt;br /&gt;W następnych notkach postaram się przedstawić główną idee działania tego &lt;!-- google_ad_section_start --&gt;algorytmu&lt;!-- google_ad_section_end --&gt;.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/8336144765189037467-7556164135924251888?l=npb-algorytmy.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://npb-algorytmy.blogspot.com/feeds/7556164135924251888/comments/default' title='Komentarze do posta'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=8336144765189037467&amp;postID=7556164135924251888' title='Komentarze (0)'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/8336144765189037467/posts/default/7556164135924251888'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/8336144765189037467/posts/default/7556164135924251888'/><link rel='alternate' type='text/html' href='http://npb-algorytmy.blogspot.com/2008/11/weronika.html' title='Weronika'/><author><name>npb</name><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-8336144765189037467.post-5232255012768465688</id><published>2008-11-10T17:53:00.006+01:00</published><updated>2008-11-10T19:24:12.679+01:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='algorytmy'/><title type='text'>Algorytm Forda-Johnsona cz III.</title><content type='html'>Zgodnie z obietnicą w tej części postaram się wyjaśnić dlaczego akurat taki ciąg został wybrany w części drugiej.&lt;br /&gt;&lt;br /&gt;Wszystkie rozważenia przeprowadzę na następującym przykładzie:&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://3.bp.blogspot.com/_dMhinKIQ0wM/SRhqgwOlf7I/AAAAAAAAAEQ/sHFvwT87pJs/s1600-h/fj5.png"&gt;&lt;img style="display:block; margin:0px auto 10px; text-align:center;cursor:pointer; cursor:hand;width: 200px; height: 44px;" src="http://3.bp.blogspot.com/_dMhinKIQ0wM/SRhqgwOlf7I/AAAAAAAAAEQ/sHFvwT87pJs/s200/fj5.png" border="0" alt=""id="BLOGGER_PHOTO_ID_5267076875144232882" /&gt;&lt;/a&gt;Rozważymy trzy proste ciągi i policzymy ile w najgorszym przypadku będziemy potrzebowali porównań, aby posortować te liczby. Przypomnę jeszcze, że aby do ciągu n elementowego wstawić liczbę potrzebujemy [lg n] + 1 porównań (gdzie [x] - oznacza podłogę z liczby x).&lt;br /&gt;&lt;br /&gt;Spróbujmy wstawiać elementy od lewej do prawej:&lt;br /&gt;&lt;pre&gt;Wstawiamy 8 --- Wykonujemy 4 porównania ([lg 8] + 1)&lt;br /&gt;Wstawiamy 7 --- Wykonujemy 4 porównania ([lg 8] + 1)&lt;br /&gt;Wstawiamy 6 --- Wykonujemy 4 porównania ([lg 8] + 1)&lt;br /&gt;Wstawiamy 5 --- Wykonujemy 4 porównania ([lg 8] + 1)&lt;br /&gt;Wstawiamy 4 --- Wykonujemy 4 porównania ([lg 8] + 1)&lt;br /&gt;Wstawiamy 3 --- Wykonujemy 4 porównania ([lg 8] + 1)&lt;br /&gt;Wstawiamy 2 --- Wykonujemy 4 porównania ([lg 8] + 1)&lt;br /&gt;W sumie - 28 porównań.&lt;/pre&gt;Zauważmy, że w tej metodzie wstawiając każdy element, wykonaliśmy tyle samo porównań (skorzystamy z tego faktu). Teraz spróbujmy wstawiać elementy od prawej do lewej:&lt;br /&gt;&lt;pre&gt;Wstawiamy 2 --- Wykonujemy 2 porównania ([lg 2] + 1)&lt;br /&gt;Wstawiamy 3 --- Wykonujemy 3 porównania ([lg 4] + 1)&lt;br /&gt;Wstawiamy 4 --- Wykonujemy 3 porównania ([lg 6] + 1)&lt;br /&gt;Wstawiamy 5 --- Wykonujemy 4 porównania ([lg 8] + 1)&lt;br /&gt;Wstawiamy 6 --- Wykonujemy 4 porównania ([lg 10] + 1)&lt;br /&gt;Wstawiamy 7 --- Wykonujemy 4 porównania ([lg 12] + 1)&lt;br /&gt;Wstawiamy 8 --- Wykonujemy 4 porównania ([lg 14] + 1)&lt;br /&gt;W sumie - 24 porównania.&lt;/pre&gt;Czyli w drugim przypadku wykonaliśmy o 4 porównania mniej. I nasza metoda z poprzedniej notki:&lt;br /&gt;&lt;pre&gt;Wstawiamy 3 --- Wykonujemy 2 porównania ([lg 3] + 1)&lt;br /&gt;Wstawiamy 2 --- Wykonujemy 2 porównania ([lg 3] + 1)&lt;br /&gt;Wstawiamy 5 --- Wykonujemy 3 porównania ([lg 7] + 1)&lt;br /&gt;Wstawiamy 4 --- Wykonujemy 3 porównania ([lg 7] + 1)&lt;br /&gt;Wstawiamy 8 --- Wykonujemy 4 porównania ([lg 12] + 1)&lt;br /&gt;Wstawiamy 7 --- Wykonujemy 4 porównania ([lg 12] + 1)&lt;br /&gt;Wstawiamy 6 --- Wykonujemy 4 porównania ([lg 12] + 1)&lt;br /&gt;W sumie - 22 porównania.&lt;/pre&gt;Zauważmy dwie rzeczy. W momentach w którym nasz ciąg maleje - (np. we wstawieniu 8, 7, 6) wykonujemy tyle samo porównań (zauważyliśmy już to w ciągu pierwszym). Nie przypadkiem jest również to, że wewnątrz logarytmów są liczby bliskie potęgom liczby 2 (gdybyśmy wstawiali liczby do 11 to w miejscu [lg 12] pojawił by się [lg 15]).&lt;br /&gt;&lt;br /&gt;Ciąg trzeci został więc wybrany następująco (zachłannie):&lt;br /&gt;- wybierzmy wierzchołek najbardziej na lewo, który jesteśmy w stanie wstawić w dwóch ruchach.&lt;br /&gt;- wstawmy go do ciągu "głównego" wraz z wszystkimi elementami na prawo od niego&lt;br /&gt;- wybierzmy wierzchołek najbardziej na lewo, który jesteśmy w stanie wstawić w trzech ruchach.&lt;br /&gt;- wstawmy go do ciągu "głównego" wraz z wszystkimi elementami na prawo od niego&lt;br /&gt;- wybierzmy wierzchołek najbardziej na lewo, który jesteśmy w stanie wstawić w czterech ruchach.&lt;br /&gt;- wstawmy go do ciągu "głównego" wraz z wszystkimi elementami na prawo od niego&lt;br /&gt;...&lt;br /&gt;&lt;br /&gt;Mam nadzieję, że nieco się wyjaśniło odnośnie tego ciągu. Jeśli nie to proszę o kontakt :)&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/8336144765189037467-5232255012768465688?l=npb-algorytmy.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://npb-algorytmy.blogspot.com/feeds/5232255012768465688/comments/default' title='Komentarze do posta'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=8336144765189037467&amp;postID=5232255012768465688' title='Komentarze (0)'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/8336144765189037467/posts/default/5232255012768465688'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/8336144765189037467/posts/default/5232255012768465688'/><link rel='alternate' type='text/html' href='http://npb-algorytmy.blogspot.com/2008/11/algorytm-forda-johnsona-cz-iii.html' title='Algorytm Forda-Johnsona cz III.'/><author><name>npb</name><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://3.bp.blogspot.com/_dMhinKIQ0wM/SRhqgwOlf7I/AAAAAAAAAEQ/sHFvwT87pJs/s72-c/fj5.png' height='72' width='72'/><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-8336144765189037467.post-1579188783132927893</id><published>2008-11-02T11:25:00.005+01:00</published><updated>2008-11-02T13:05:11.834+01:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='algorytmy'/><title type='text'>Algorytm Forda-Johnsona cz II.</title><content type='html'>Algorytm Forda Johnsona służy do posortowania n-elementowej tablicy. Algorytm jest bardzo ciekawy z teoretycznego punktu widzenia, bo wykonuje bardzo małą liczbę porównań, bliską optymalnej. Algorytm działa optymalnie dla n &lt; 16 oraz dla n = 20, 21, 22, a najmniejszy n dla którego znamy algorytm wymagający mniejszej liczby porównań to n = 47.&lt;br /&gt;&lt;br /&gt;Na początku podzielmy tablicę n-elementową na pary i porównujemy je w tych parach. Jeśli liczba elementów jest nieparzysta to jeden element zostaje nieporównany.&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://4.bp.blogspot.com/_dMhinKIQ0wM/SQ2E5-VhX3I/AAAAAAAAAEA/GjnbVHF8koA/s1600-h/fj3.PNG"&gt;&lt;img style="display:block; margin:0px auto 10px; text-align:center;cursor:pointer; cursor:hand;width: 175px; height: 45px;" src="http://4.bp.blogspot.com/_dMhinKIQ0wM/SQ2E5-VhX3I/AAAAAAAAAEA/GjnbVHF8koA/s200/fj3.PNG" border="0" alt=""id="BLOGGER_PHOTO_ID_5264009670986653554" /&gt;&lt;/a&gt;Elementy, które okazały się mniejsze w parach, sortujemy rekurencyjnie. Dla ułatwienia naszych dalszych rozważań ponumerujmy elementy. Największy numer dostaje element, który nie został jeszcze porównany (jeśli tablica ma nieparzyście wiele elementów). Resztę elementów numerujemy tak jak na rysunku.&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://3.bp.blogspot.com/_dMhinKIQ0wM/SQ2O9V8qQMI/AAAAAAAAAEI/OmS5h7YCWVA/s1600-h/fj4.PNG"&gt;&lt;img style="display:block; margin:0px auto 10px; text-align:center;cursor:pointer; cursor:hand;width: 175px; height: 45px;" src="http://3.bp.blogspot.com/_dMhinKIQ0wM/SQ2O9V8qQMI/AAAAAAAAAEI/OmS5h7YCWVA/s200/fj4.PNG" border="0" alt=""id="BLOGGER_PHOTO_ID_5264020723980714178" /&gt;&lt;/a&gt;Teraz każdy element znajdujący się w ciągu "na dole" będziemy chcieli umieścić w ciągu "na górze". Szukając miejsca tego elementu, będziemy korzystać z wyszukiwania binarnego.&lt;br /&gt;Kolejność w której będziemy wrzucać elementy z dołu do elementów na górze ma kolosalne znaczenie. Optymalną kolejnością wrzucania elementów jest następująca: &lt;span style="font-weight:bold;"&gt;1&lt;/span&gt;, &lt;span style="font-weight:bold;"&gt;3&lt;/span&gt;, 2, &lt;span style="font-weight:bold;"&gt;5&lt;/span&gt;, 4, &lt;span style="font-weight:bold;"&gt;11&lt;/span&gt;, 10, 9, 8, 7, 6, &lt;span style="font-weight:bold;"&gt;21&lt;/span&gt;, 20, 19, 18, 17, 16, 15, 14, 13, 12, &lt;span style="font-weight:bold;"&gt;43&lt;/span&gt;, 42 ... . Element 1 wpisałem dla porządku, element ten jest już na swoim miejscu i nie trzeba nic z nim robić. Ciąg niemniej może wydawać się trochę skomplikowany. Już tłumaczę jak powstał. Można zauważyć, że po wszystkich liczbach zaznaczonych pogrubieniem, liczby maleją, aż skończą się nam liczby. Następnie pojawia się znowu pogrubiona liczba i liczby znowu zmniejszają się o jeden. Aby umieć wygenerować taki ciąg wystarczy zatem wiedzieć na jakiej podstawie wybieramy pogrubione liczby. Zauważmy, że sumy kolejnych dwóch liczb pogrubionych są równe kolejnym potęgom dwójki: 1 + 3 = 4; 3 + 5 = 8; 5 + 11 = 16; 11 + 21 = 32 itd.&lt;br /&gt;&lt;br /&gt;Algorytm jest nieco skomplikowany. Jeśli są z nim jakieś problemy, albo trzeba coś jeszcze wytłumaczyć - to proszę o kontakt.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/8336144765189037467-1579188783132927893?l=npb-algorytmy.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://npb-algorytmy.blogspot.com/feeds/1579188783132927893/comments/default' title='Komentarze do posta'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=8336144765189037467&amp;postID=1579188783132927893' title='Komentarze (2)'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/8336144765189037467/posts/default/1579188783132927893'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/8336144765189037467/posts/default/1579188783132927893'/><link rel='alternate' type='text/html' href='http://npb-algorytmy.blogspot.com/2008/11/algorytm-forda-johnsona-cz-ii.html' title='Algorytm Forda-Johnsona cz II.'/><author><name>npb</name><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://4.bp.blogspot.com/_dMhinKIQ0wM/SQ2E5-VhX3I/AAAAAAAAAEA/GjnbVHF8koA/s72-c/fj3.PNG' height='72' width='72'/><thr:total>2</thr:total></entry><entry><id>tag:blogger.com,1999:blog-8336144765189037467.post-8466433046949400594</id><published>2008-10-31T17:38:00.005+01:00</published><updated>2008-10-31T18:07:00.824+01:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='algorytmy'/><title type='text'>Algorytm Forda-Johnsona cz I.</title><content type='html'>Spróbujmy posortować ciąg 5 liczb za pomocą 7 porównań. Oznaczmy te elementy jako a, b, c, d oraz e. Porównajmy element a z elementem b i załóżmy, że a jest mniejszy (ew. zamieńmy a z b miejscami). Porównajmy element c z d i przyjmijmy, że element c jest mniejszy. I wreszcie porównajmy element a z c i przyjmijmy, że element a jest mniejszy. Wykonaliśmy do tej pory 3 porównania, a sytuację w której się znaleźliśmy przedstawia poniższy rysunek.&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://3.bp.blogspot.com/_dMhinKIQ0wM/SQs1trcPO8I/AAAAAAAAADw/erjxIQlkGS4/s1600-h/fj1.PNG"&gt;&lt;img style="display:block; margin:0px auto 10px; text-align:center;cursor:pointer; cursor:hand;width: 108px; height: 66px;" src="http://3.bp.blogspot.com/_dMhinKIQ0wM/SQs1trcPO8I/AAAAAAAAADw/erjxIQlkGS4/s200/fj1.PNG" border="0" alt=""id="BLOGGER_PHOTO_ID_5263359648384105410" /&gt;&lt;/a&gt;Spróbujmy teraz wcisnąć element e gdzieś do ciągu [a, c, d]. Możemy to zrobić za pomocą dwóch porównań (użyjemy wyszukiwania binarnego). Najpierw element e  sprawdzamy z elementem c. Jeśli jest mniejszy to sprawdzamy z elementem a; w przeciwnym przypadku z elementem d. Trudno przewidzieć w którym miejscu stanie element e. Rozważmy dwa przypadki. Albo e jest najmniejszym elementem z tej trójki (a, c, d), albo nie jest. Ten drugi przypadek przedstawia poniższy rysunek.&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://4.bp.blogspot.com/_dMhinKIQ0wM/SQs1txpfO1I/AAAAAAAAAD4/wNvSOmQ-PJE/s1600-h/fj2.PNG"&gt;&lt;img style="display:block; margin:0px auto 10px; text-align:center;cursor:pointer; cursor:hand;width: 153px; height: 66px;" src="http://4.bp.blogspot.com/_dMhinKIQ0wM/SQs1txpfO1I/AAAAAAAAAD4/wNvSOmQ-PJE/s200/fj2.PNG" border="0" alt=""id="BLOGGER_PHOTO_ID_5263359650050292562" /&gt;&lt;/a&gt;Jedyną rzeczą jaką trzeba teraz zrobić to wstawić element b pomiędzy elementy {c, d, e}. Identycznie jak poprzednio możemy to zrobić w dwóch ruchach.&lt;br /&gt;W drugim przypadku, gdy element e jest najmniejszy, wystarczy element b porównać tylko z elementami c oraz d. To też możemy zrobić używając dwóch ruchów.&lt;br /&gt;&lt;br /&gt;Reasumując. Na początku porównując elementy a, b, c oraz d - wykonaliśmy 3 porównania. Wpychając element e pomiędzy elementy [a, c, e] wykonaliśmy dodatkowe 2 porównania. Na końcu ustawiliśmy element b na swoje miejsce używając nie więcej niż 2 porównań. 3 + 2 + 2 = 7&lt;br /&gt;&lt;br /&gt;W następnej notce uogólnimy ten algorytm na tablicę n-elementową.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/8336144765189037467-8466433046949400594?l=npb-algorytmy.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://npb-algorytmy.blogspot.com/feeds/8466433046949400594/comments/default' title='Komentarze do posta'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=8336144765189037467&amp;postID=8466433046949400594' title='Komentarze (0)'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/8336144765189037467/posts/default/8466433046949400594'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/8336144765189037467/posts/default/8466433046949400594'/><link rel='alternate' type='text/html' href='http://npb-algorytmy.blogspot.com/2008/10/algorytm-forda-johnsona-cz-i.html' title='Algorytm Forda-Johnsona cz I.'/><author><name>npb</name><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://3.bp.blogspot.com/_dMhinKIQ0wM/SQs1trcPO8I/AAAAAAAAADw/erjxIQlkGS4/s72-c/fj1.PNG' height='72' width='72'/><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-8336144765189037467.post-8925410417898521573</id><published>2008-10-19T09:53:00.005+02:00</published><updated>2009-01-01T21:23:13.133+01:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='pogadanka'/><title type='text'>Studia informatyczne to magia</title><content type='html'>Znajomi moi często pytają się mnie czego ja się uczę na studiach informatycznych. Gdy odpowiadam, że na zajęciach piszemy algorytmy, mówimy jak działa komputer (na poziomie bramek logicznych), rozwiązujemy całki itp, to znajomi odpowiadają, że dla nich to czarna magia.&lt;br /&gt;&lt;br /&gt;Jaka to czarna magia? - myślałem sobie - Wszystko to jest proste i logiczne! Jednak na pierwszych zajęciach z programowania funkcyjnego profesor UW Marcin Kubica (nie mylić z Robertem) wytłumaczył mi, że to jednak moi znajomi mają rację.&lt;br /&gt;&lt;br /&gt;No bo co to jest magia? Cytując za Nową Encyklopedią Powszechną PWN jest to "Zespół działań, zasadniczo pozaempirycznych, symbolicznych, których celem jest bezpośrednie osiągnięcie (...) pożądanych skutków". Wszystko się zgadza, ale pójdźmy dalej.&lt;br /&gt;&lt;br /&gt;Wyróżniamy przy tym następujące składniki działań magicznych:&lt;br /&gt;- zrytualizowane działania&lt;br /&gt;- materialne obiekty magiczne&lt;br /&gt;- reguły obowiązujące przy praktykach magicznych&lt;br /&gt;- formuły tekstowe mające moc sprawczą (zaklęcia)&lt;br /&gt;&lt;br /&gt;Zrytualizowanymi działaniami jest na przykład wyłączanie komputera, logowanie się do sieci etc. Indeks i karta egzaminacyjna są materialnymi obiektami, które w istocie mają magiczną moc. Jest cała lista reguł obowiązująca przy praktykach magicznych (do sali komputerowej nie można wnosić jedzenia i/lub picia, nie wolno wnosić okryć wierzchnich ani dużych toreb... itp. itd). Natomiast formuły tekstowe mające moc sprawczą są istotą informatyki:&lt;br /&gt;&lt;pre class="mycode"&gt;// Przykład formuły tekstowej mającej moc sprawczą&lt;br /&gt;&lt;br /&gt;int main(void)&lt;br /&gt;{&lt;br /&gt;  printf("Hello World!\n");&lt;br /&gt;  return 0;&lt;br /&gt;}&lt;/pre&gt;&lt;br /&gt;Ale pójdźmy jeszcze dalej! Duch to obiekt niematerialny zdolny do działania. Spójrzmy na procesy obliczeniowe - nie można ich zobaczyć, ani dotknąć, ani powąchać, ale możemy obserwować skutki ich działania. Ba! Możemy się ich spytać o interesujące nas informacje.&lt;br /&gt;&lt;br /&gt;Istna czarna magia!&lt;br /&gt;&lt;br /&gt;Edit (01.01.2009):&lt;br /&gt;Właśnie znalazłem, pasuje jak ulał. Z praw Murphy'ego:&lt;br /&gt;Zasada Clarke'a:&lt;br /&gt;"Każda dostatecznie zaawansowana technologia niczym nie różni się od magii."&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/8336144765189037467-8925410417898521573?l=npb-algorytmy.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://npb-algorytmy.blogspot.com/feeds/8925410417898521573/comments/default' title='Komentarze do posta'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=8336144765189037467&amp;postID=8925410417898521573' title='Komentarze (3)'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/8336144765189037467/posts/default/8925410417898521573'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/8336144765189037467/posts/default/8925410417898521573'/><link rel='alternate' type='text/html' href='http://npb-algorytmy.blogspot.com/2008/10/studia-informatyczne-to-magia.html' title='Studia informatyczne to magia'/><author><name>npb</name><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>3</thr:total></entry><entry><id>tag:blogger.com,1999:blog-8336144765189037467.post-2483618007427253615</id><published>2008-10-13T10:41:00.004+02:00</published><updated>2008-10-13T10:45:22.628+02:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='wydarzenia'/><title type='text'>3 wiadomości</title><content type='html'>Mam do zakomunikowania 3 wiadomości.&lt;br /&gt;&lt;br /&gt;Po pierwsze pojawił się nowy dział "Do pobrania", a w nim moja prezentacja z liceum na temat diagramów Voronoi. Wkrótce umieszczę tam więcej ciekawych rzeczy. Póki co rzeczy tam umieszczane znajdują się na chomiku. Prawdopodobnie przeniosę je jak znajdę jakieś lepsze miejsce (albo nie :)).&lt;br /&gt;&lt;br /&gt;Po drugie niestety nie mam teraz stałego dostępu do internetu i notki niestety nie będą pojawiały się tak często jakbym chciał.&lt;br /&gt;&lt;br /&gt;Po trzecie rozpoczął się konkurs ITPW. Więcej informacji na stronie http://www.mimuw.edu.pl/KNI/ITPW/.&lt;br /&gt;&lt;br /&gt;Pozdrawiam!&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/8336144765189037467-2483618007427253615?l=npb-algorytmy.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://npb-algorytmy.blogspot.com/feeds/2483618007427253615/comments/default' title='Komentarze do posta'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=8336144765189037467&amp;postID=2483618007427253615' title='Komentarze (0)'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/8336144765189037467/posts/default/2483618007427253615'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/8336144765189037467/posts/default/2483618007427253615'/><link rel='alternate' type='text/html' href='http://npb-algorytmy.blogspot.com/2008/10/3-wiadomoci.html' title='3 wiadomości'/><author><name>npb</name><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-8336144765189037467.post-5264531839199754018</id><published>2008-10-05T13:40:00.005+02:00</published><updated>2008-10-05T17:55:34.680+02:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='technikalia'/><title type='text'>Problemy z typami danych cz II.</title><content type='html'>Do pomiaru rozmiaru struktur danych służy operator sizeof(). Sprawdzimy na początek ile pamięci zajmują wybrane standardowe typy danych.&lt;pre class="mycode"&gt;#include &amp;lt;stdio.h&amp;gt;&lt;br /&gt;&lt;br /&gt;int main(void)&lt;br /&gt;{&lt;br /&gt;  printf("%d\n", sizeof(char));&lt;br /&gt;  printf("%d\n", sizeof(short));&lt;br /&gt;  printf("%d\n", sizeof(int));&lt;br /&gt;  return 0;&lt;br /&gt;}&lt;/pre&gt;Program wypisze nam ile bajtów zajmuje każdy z następujących typów danych: char, short oraz int. Wyniki zwracane przez program będą różne dla różnych architerktur komputerów na których były uruchomione. Polecam uruchomienie tego programu na własnym komputerze. Na moim komputerze wyniki to: 1 bajt dla chara, 2 bajty dla shorta i 4 bajty dla inta.&lt;br /&gt;&lt;br /&gt;Zbadamy teraz ile bajtów zajmują zdefiniowane przez nas struktury danych. Zaczniemy od prostej, lecz często stosowanej konstrukcji.&lt;pre class="mycode"&gt;// Przykład 1&lt;br /&gt;&lt;br /&gt;struct struktura&lt;br /&gt;{&lt;br /&gt;  char a;&lt;br /&gt;};&lt;br /&gt;&lt;br /&gt;sizeof(struktura) == 1;&lt;/pre&gt;Wszystko wygląda w porządku. Mamy w strukturze jedną zmienną typu char, która zajmuje 1 bajt. Zatem cała struktura zajmie nam w pamięci 1 bajt. Nic nadzwyczajnego tu się nie dzieje. Przejdźmy do drugiego przykładu.&lt;pre class="mycode"&gt;// Przykład 2&lt;br /&gt;&lt;br /&gt;struct struktura&lt;br /&gt;{&lt;br /&gt;  char a;&lt;br /&gt;  short b;&lt;br /&gt;};&lt;br /&gt;&lt;br /&gt;sizeof(struktura) == 4;&lt;/pre&gt;Tutaj stało się coś dziwnego.. Zmienna char zajmuje 1 bajt, a zmienna short 2 bajty. Zatem intuicyjnie struktura zawierający te dwie zmienne, powinna zajmować 3 bajty. Natomiast sizeof() informuje nas, że struktura zajmuje aż 4 bajty! Czy to błąd kompilatora albo funkcji sizeof? A może celowe działanie? Spróbuję to wytłumaczyć w dalszej części tego artykułu. Na razie przyjrzyjmy się kolejnemu przykładowi:&lt;pre class="mycode"&gt;// Przykład 3&lt;br /&gt;&lt;br /&gt;struct struktura&lt;br /&gt;{&lt;br /&gt;  char a;&lt;br /&gt;  int b;&lt;br /&gt;  char c;&lt;br /&gt;};&lt;br /&gt;&lt;br /&gt;sizeof(struktura) == 12;&lt;/pre&gt;Pewnie spodziewaliśmy się, że i w tym przypadku rozmiar struktury będzie nieco większy niż wynikałoby to z prostej matematyki. Ale że struktura będzie zajmowała dwa razy więcej miejsca niż zmienne w strukturze? I to jeszcze nie koniec! Przyjrzyjmy się kolejnemu przykładowi.&lt;pre class="mycode"&gt;// Przykład 4&lt;br /&gt;&lt;br /&gt;struct struktura&lt;br /&gt;{&lt;br /&gt;  char a;&lt;br /&gt;  char c;&lt;br /&gt;  int b;&lt;br /&gt;};&lt;br /&gt;&lt;br /&gt;sizeof(struktura) == 8;&lt;/pre&gt;Struktura z praktycznego punktu widzenia nie różni się tak bardzo od poprzedniej. I tu i tu mamy po dwa chary i jednego inta. Zmienne nawet w obu przypadkach są tak samo nazwane! Różnica jest jedynie w kolejności w jakiej te zmienne występują. Dzięki tej z pozoru nieistotnej zmianie zyskaliśmy aż 4 bajty w pamięci. Dlaczego tak się dzieje? O tym w kolejnej części.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/8336144765189037467-5264531839199754018?l=npb-algorytmy.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://npb-algorytmy.blogspot.com/feeds/5264531839199754018/comments/default' title='Komentarze do posta'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=8336144765189037467&amp;postID=5264531839199754018' title='Komentarze (0)'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/8336144765189037467/posts/default/5264531839199754018'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/8336144765189037467/posts/default/5264531839199754018'/><link rel='alternate' type='text/html' href='http://npb-algorytmy.blogspot.com/2008/10/problemy-z-typami-danych-cz-ii.html' title='Problemy z typami danych cz II.'/><author><name>npb</name><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-8336144765189037467.post-480227785149792517</id><published>2008-09-28T10:03:00.010+02:00</published><updated>2008-10-05T17:55:22.922+02:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='technikalia'/><title type='text'>Problemy z typami danych cz I.</title><content type='html'>Notka będzie najeżona dużą dawką informacji. Zacznijmy!&lt;br /&gt;Na początek tabelka rozmiarów podstawowych typów danych.&lt;pre class="mycode"&gt;char      1&lt;br /&gt;short     2&lt;br /&gt;int       4 (na 32-bitowych komputerach!)&lt;br /&gt;long long 8&lt;/pre&gt;Przyjrzyjmy się bliżej typowi int. Jego zakres to -2&lt;sup&gt;31&lt;/sup&gt; ... 2&lt;sup&gt;31&lt;/sup&gt;-1. Warto przy tym wspomnieć, że liczba 2&lt;sup&gt;31&lt;/sup&gt;-1 (0x7fffffff) jest liczbą pierwszą. Zapamiętaj to! Znajomość dużych liczb pierwszych przyda Ci się przy kilku algorytmach.&lt;br /&gt;W związku z tym, że mamy o jedną liczbę ujemną więcej niż dodatnią, rodzi się nasz pierwszy problem. Spójrzmy na następujący kod źródłowy programu C++:&lt;pre class="mycode"&gt;int x = -2&lt;sup&gt;31&lt;/sup&gt;;&lt;br /&gt;int y = -x;&lt;br /&gt;pritnf("%d\n", y);&lt;/pre&gt;Pierwsza linijka nie stanowi żadnego kłopotu (nie licząc tego, że kompilator jej nie zaakceptuje). Druga linia rodzi pewien problem. Teoretycznie zmienna x powinna przyjąć wartość 2&lt;sup&gt;31&lt;/sup&gt;. Jednak ta liczba nie mieści się w zakresie inta. Pytanie: Jaką zatem wartość ma zmienna y?&lt;br /&gt;Aby to ustalić spójrzmy jak w systemie binarnym zapisane są wybrane liczby całkowite.&lt;pre class="mycode"&gt; 0    00000000 00000000 00000000 00000000&lt;br /&gt; 1    00000000 00000000 00000000 00000001&lt;br /&gt;-1    11111111 11111111 11111111 11111111&lt;br /&gt;-2&lt;sup&gt;31&lt;/sup&gt;  10000000 00000000 00000000 00000000&lt;/pre&gt;Prześledźmy działanie operatora unarnego "-":&lt;br /&gt;- Negujemy wszystkie bity liczby&lt;br /&gt;- Dodajemy do liczby jeden&lt;br /&gt;Prześledźmy jak ten operator działa dla powyższych liczb. Zero poprawnie przechodzi na zero. Jeden przechodzi na minus jeden, a minus jeden na jeden. Natomiast -2&lt;sup&gt;31&lt;/sup&gt; przechodzi na... -2&lt;sup&gt;31&lt;/sup&gt;. To nie koniec niespodzianek.&lt;br /&gt;&lt;br /&gt;Przeanalizujmy następujący program:&lt;pre class="mycode"&gt;printf("%d", 1 &lt;&lt; 2);&lt;br /&gt;printf("%d", 1 &lt;&lt; 31);&lt;br /&gt;printf("%d", 1 &lt;&lt; 32);&lt;/pre&gt;Pierwsze dwie linie programu działają według naszych przypuszczeń. Pierwsza linijka wypisze na ekran "4", natomiast druga "-2&lt;sup&gt;31&lt;/sup&gt;". Natomiast z trzecią linijką jest kłopot o czym informuje nas już kompilator: "warning: left shift count &gt;= width of type". Na ekranie zostanie wypisane "0". Ale spójrzmy jeszcze na to:&lt;pre class="mycode"&gt;int x = 32;&lt;br /&gt;printf("%d", 1 &lt;&lt; x);&lt;/pre&gt;Program nie powinien się różnić od poprzedniego przykładu, a jednak. Po pierwsze kompilator nie informuje nas o zagrożeniu (kompilator "nie może wiedzieć" czy wartość x przekracza dozwolony zakres). Po drugie, na ekranie zostanie wypisana "1". Procesor bowiem weźmie resztę z dzielenia liczby x przez 32 i o taką liczbę bitów przesunie 1 w lewo. Trzeba o tym pamiętać i mieć to na uwadze.&lt;br /&gt;&lt;br /&gt;W drugiej części przedstawię kolejne problemy, tym razem z własnymi strukturami danych.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/8336144765189037467-480227785149792517?l=npb-algorytmy.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://npb-algorytmy.blogspot.com/feeds/480227785149792517/comments/default' title='Komentarze do posta'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=8336144765189037467&amp;postID=480227785149792517' title='Komentarze (2)'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/8336144765189037467/posts/default/480227785149792517'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/8336144765189037467/posts/default/480227785149792517'/><link rel='alternate' type='text/html' href='http://npb-algorytmy.blogspot.com/2008/09/problemy-z-typami-danych-cz-i.html' title='Problemy z typami danych cz I.'/><author><name>npb</name><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>2</thr:total></entry><entry><id>tag:blogger.com,1999:blog-8336144765189037467.post-8795420801377874218</id><published>2008-09-26T12:58:00.009+02:00</published><updated>2009-02-07T22:41:06.700+01:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='technikalia'/><title type='text'>Przewidywanie skoków w procesorze</title><content type='html'>Przeanalizujmy następujący program.&lt;br /&gt;&lt;pre class="mycode"&gt;const n = 10000000;&lt;br /&gt;int P[n];&lt;br /&gt;&lt;br /&gt;for (int i = 0; i &lt; n; i++)&lt;br /&gt;  scanf("%d", &amp;p[i]);&lt;br /&gt;&lt;br /&gt;for (int i = 0; i &lt; n; i++)&lt;br /&gt;{&lt;br /&gt;  if (p[i] &lt; N/2) ++w;&lt;br /&gt;  else ++y;&lt;br /&gt;&lt;br /&gt;  if (p[(i+100)%N] &lt; N/2) ++w;&lt;br /&gt;  else ++h;&lt;br /&gt;}&lt;/pre&gt;Program na wejściu dostaje permutację liczb 1, 2, ..., n. Program nie liczy nic ciekawego. Ważną rzeczą jest, że dla dowolnej permutacji każda instrukcja w programie zostanie wykonana dokładnie taką samą ilość razy. Mimo to dla permutacji &lt;1, 2, ..., n&gt; program działa szybciej niż dla jakiejkolwiek losowej permutacji:&lt;br /&gt;&lt;span style="font-family: courier new; font-size: 85%;"&gt;&lt;br /&gt;Losowa permutacja: 4.07 s&lt;br /&gt;Posortowane dane:  3.91 s&lt;br /&gt;&lt;/span&gt;&lt;br /&gt;Minimalnej różnicy mogliśmy się spodziewać. Czas działania tego programu jest opóźniony przez operację wejścia / wyjścia. Jednak dlaczego program na posortowanych danych działa szybciej?&lt;br /&gt;&lt;br /&gt;W każdym programie około 10% instrukcji to skoki. Problemem dla procesora są zwłaszcza tak zwane skoki warunkowe. Gdy procesor wykonuje jakąś komendę, to następne instrukcje już lądują w specjalnej kolejce do tego przeznaczonej. W sytuacji w której wykonujemy skok warunkowy, nie możemy stwierdzić które instrukcje powinny być następnie wykonywane, dopóki nie zostanie sprawdzony warunek. Jednak czekając tak długo tracimy cenne cykle procesora... Jest jednak wyjście z tej sytuacji.&lt;br /&gt;&lt;br /&gt;Procesor gdy napotyka na skok warunkowy próbuje "przewidzieć" wynik skoku i odpowiednie instrukcje trafiają do kolejki. Jeśli procesor "zgadł", to instrukcje są wykonywane normalnie. W przeciwnym przypadku instrukcje znajdujące w kolejce są anulowane i wszelkie efekty działania tych instrukcji (tak, tak - procesor czasem wykona te operacje), a do kolejki trafiają poprawne instrukcje.&lt;br /&gt;&lt;br /&gt;W sytuacji w której dane są posortowane - procesorowi będzie łatwiej przewidzieć skoki, podczas gdy dla losowych danych takie przewidywania są niemal niemożliwe. Dlatego program dla danych posortowanych działał szybciej.&lt;br /&gt;&lt;br /&gt;Jaki jest morał z tego wykładu? Przecież zwykle nie mamy wpływu na dane wejściowe. Zgadza się! Ale czasami chcielibyśmy obliczyć ile program działa w najgorszym wypadku. Mimo, że permutacja &lt;1, 2, ..., n&gt; jest największa z możliwych, a każda instrukcja wykonywana jest w każdej permutacji taką samą ilość razy, to jednak to nie jest najgorsza możliwa permutacja dla tego programu.. Niejeden programista się na tym przejechał.&lt;br /&gt;&lt;br /&gt;Mały FAQ dla chcących wiedzieć więcej:&lt;br /&gt;&lt;span style="font-weight:bold;"&gt;Jak dobrze procesor "przewiduje skoki"?&lt;/span&gt; Bardzo dobrze. W zależności od procesora ok 70 - 90%.&lt;br /&gt;&lt;span style="font-weight:bold;"&gt;Czy gra jest warta świeczki? Czy procesor po prostu nie mógłby poczekać aż zostanie obliczony warunek skoku?&lt;/span&gt; Nie! Jeśli w kolejce trzymanych jest 100 operacji to wśród nich jest około 10 skoków! Bez zgadywania w takiej sytuacji procesor byłby 10-krotnie mniej wydajny.&lt;br /&gt;&lt;span style="font-weight:bold;"&gt;Na podstawie czego procesor przewiduje skoki?&lt;/span&gt; Istnieją dwie metody. Pierwsza z nich to metoda statyczna. Każdemu skokowi przyporządkowuje przepowiednię. Faktycznie - dla większości skoków możemy powiedzieć, która z opcji będzie częściej wykonywana po warunku. Druga metoda to metoda dynamiczna. Dla każdego skoku spamiętujemy jego ostatnie wyniki. Na podstawie nich obliczamy naszą "przepowiednię".&lt;br /&gt;&lt;span style="font-weight:bold;"&gt;Coś więcej na temat algorytmu dynamicznego?&lt;/span&gt; Spragnionych wiedzy odsyłam do wyszukiwarki google.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/8336144765189037467-8795420801377874218?l=npb-algorytmy.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://npb-algorytmy.blogspot.com/feeds/8795420801377874218/comments/default' title='Komentarze do posta'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=8336144765189037467&amp;postID=8795420801377874218' title='Komentarze (0)'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/8336144765189037467/posts/default/8795420801377874218'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/8336144765189037467/posts/default/8795420801377874218'/><link rel='alternate' type='text/html' href='http://npb-algorytmy.blogspot.com/2008/09/przewidywanie-skokw-w-procesorze.html' title='Przewidywanie skoków w procesorze'/><author><name>npb</name><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-8336144765189037467.post-7612376558570327172</id><published>2008-09-26T10:42:00.007+02:00</published><updated>2009-03-08T16:39:55.308+01:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='wykłady'/><title type='text'>MOKIP wykład</title><content type='html'>Zostałem poproszony o przygotowanie wykładu dla Międzyszkolnego Olimpijskiego Kółka Informatycznego Pika (MOKIP). Wykład odbył się 25 września o godzinie 14:35 w VIII Liceum Ogólnokształcącym w Katowicach w sali 114.&lt;br /&gt;&lt;br /&gt;Wykład podzielony był na dwie części. W pierwszej "poprawialiśmy" Cormena, w drugiej mówiliśmy o architekturze komputera.&lt;br /&gt;&lt;br /&gt;1. Poprawianie Cormena&lt;br /&gt;&lt;br /&gt;- ulepszony algorytm Grahama&lt;br /&gt;- szukanie najbliższej pary punktów&lt;br /&gt;- potęgowanie binarne&lt;br /&gt;&lt;br /&gt;2. Architektura komputera&lt;br /&gt;&lt;br /&gt;- &lt;a href="http://npb-algorytmy.blogspot.com/2008/09/problemy-z-typami-danych-cz-i.html"&gt;problemy z typami danych&lt;/a&gt;&lt;br /&gt;- &lt;a href="http://npb-algorytmy.blogspot.com/2008/08/wierszami-czy-kolumnami-cz-i.html"&gt;wierszami czy kolumnami?&lt;/a&gt;&lt;br /&gt;- cache procesora&lt;br /&gt;- &lt;a href="http://npb-algorytmy.blogspot.com/2008/09/przewidywanie-skokw-w-procesorze.html"&gt;przewidywanie skoków w procesorze&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;Część materiałów z tego wykładu już znajduje się na blogu. Resztę umieszczę wkrótce.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/8336144765189037467-7612376558570327172?l=npb-algorytmy.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://npb-algorytmy.blogspot.com/feeds/7612376558570327172/comments/default' title='Komentarze do posta'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=8336144765189037467&amp;postID=7612376558570327172' title='Komentarze (0)'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/8336144765189037467/posts/default/7612376558570327172'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/8336144765189037467/posts/default/7612376558570327172'/><link rel='alternate' type='text/html' href='http://npb-algorytmy.blogspot.com/2008/09/mokip-wykad.html' title='MOKIP wykład'/><author><name>npb</name><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-8336144765189037467.post-3724349985830203890</id><published>2008-09-21T16:08:00.005+02:00</published><updated>2008-09-22T13:04:44.174+02:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='metody'/><title type='text'>Metoda włączeń i wyłączeń cz II.</title><content type='html'>Przedstawię dwa proste zadania, które można rozwiązać za pomocą metody włączeń i wyłączeń.&lt;br /&gt;&lt;br /&gt;Mamy danych 10 prostopadłościanów ortogonalnych (to znaczy takich, których krawędzie są równoległe do osi układów współrzędnych). Prostopadłościany te mogą na siebie nachodzić. Pytamy o sumę objętości tych prostopadłościanów.&lt;br /&gt;Prostopadłościan ortogonalny może być zapisany za pomocą pary punktów: lewego, dolnego, "bliższego" (nam) oraz prawego, górnego, "dalszego". Powiedzmy, że pewien prostopadłościan jest określony za pomocą pary: (a&lt;sub&gt;1&lt;/sub&gt;, a&lt;sub&gt;2&lt;/sub&gt;, a&lt;sub&gt;3&lt;/sub&gt;) oraz (b&lt;sub&gt;1&lt;/sub&gt;, b&lt;sub&gt;2&lt;/sub&gt;, b&lt;sub&gt;3&lt;/sub&gt;). Jego objętość można wyrazić wzorem: (b&lt;sub&gt;1&lt;/sub&gt;-a&lt;sub&gt;1&lt;/sub&gt;)(b&lt;sub&gt;2&lt;/sub&gt;-a&lt;sub&gt;2&lt;/sub&gt;)(b&lt;sub&gt;3&lt;/sub&gt;-a&lt;sub&gt;3&lt;/sub&gt;).&lt;br /&gt;Bardzo łatwo także wyznaczyć przecięcie dwóch prostopadłościanów, które także jest prostopadłościanem. Jeśli pierwszy z prostopadłościanów to (a&lt;sub&gt;1&lt;/sub&gt;, a&lt;sub&gt;2&lt;/sub&gt;, a&lt;sub&gt;3&lt;/sub&gt;) oraz (b&lt;sub&gt;1&lt;/sub&gt;, b&lt;sub&gt;2&lt;/sub&gt;, b&lt;sub&gt;3&lt;/sub&gt;), a drugi: (c&lt;sub&gt;1&lt;/sub&gt;, c&lt;sub&gt;2&lt;/sub&gt;, c&lt;sub&gt;3&lt;/sub&gt;) oraz (d&lt;sub&gt;1&lt;/sub&gt;, d&lt;sub&gt;2&lt;/sub&gt;, d&lt;sub&gt;3&lt;/sub&gt;) to prostopadłościan, który jest ich przecięciem to: (max{a&lt;sub&gt;1&lt;/sub&gt;, c&lt;sub&gt;1&lt;/sub&gt;}, max{a&lt;sub&gt;2&lt;/sub&gt;, c&lt;sub&gt;2&lt;/sub&gt;}, max{a&lt;sub&gt;3&lt;/sub&gt;, c&lt;sub&gt;3&lt;/sub&gt;}) oraz (min{b&lt;sub&gt;1&lt;/sub&gt;,d&lt;sub&gt;1&lt;/sub&gt;}, min{b&lt;sub&gt;2&lt;/sub&gt;,d&lt;sub&gt;2&lt;/sub&gt;}, min{b&lt;sub&gt;3&lt;/sub&gt;,d&lt;sub&gt;3&lt;/sub&gt;}).&lt;br /&gt;Tak jak nauczyliśmy się w poprzedniej części - możemy teraz obliczyć sumę objętości prostopadłościanów na podstawię ich przecięć.&lt;br /&gt;&lt;br /&gt;Drugie zadanie jest następujące. Mamy dany zbiór S = {1, 2, 3, ..., 10&lt;sup&gt;9&lt;/sup&gt;}. Pytamy ile jest liczb w tym zbiorze, które są podzielne przez 9, 11 lub 15?&lt;br /&gt;Oznaczmy przez D&lt;sub&gt;k&lt;/sub&gt; zbiór tych wszystkich liczb należących do S, które są podzielne przez k. Nie trudno zauważyć, że |D&lt;sub&gt;k&lt;/sub&gt;| = 10&lt;sup&gt;9&lt;/sup&gt; / k. Przy czym dzielenie tutaj rozumiemy jako dzielenie całkowitoliczbowe.&lt;br /&gt;Tak samo łatwo można policzyć przecięcie dwóch zbiorów. Wystarczy tylko zauważyć, że:&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://3.bp.blogspot.com/_dMhinKIQ0wM/SNd7vTBErpI/AAAAAAAAADA/L8w731qRE2o/s1600-h/wlwl.PNG"&gt;&lt;img style="display:block; margin:0px auto 10px; text-align:center;cursor:pointer; cursor:hand;" src="http://3.bp.blogspot.com/_dMhinKIQ0wM/SNd7vTBErpI/AAAAAAAAADA/L8w731qRE2o/s200/wlwl.PNG" border="0" alt=""id="BLOGGER_PHOTO_ID_5248799943212445330" /&gt;&lt;/a&gt;Gdzie lcm(k, l) oznacza najmniejszą wspólną wielokrotność liczb k oraz l.&lt;br /&gt;Zgodnie z opisaną w poprzedniej części metodą włączeń i wyłączeń możemy obliczyć sumę zdefiniowanych wzorów.&lt;br /&gt;&lt;br /&gt;Dobrym ćwiczeniem będzie dla każdego implementacja powyższych algorytmów. Nie powinno to nikomu sprawić większych problemów, ale warto się oswoić z tą techniką.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/8336144765189037467-3724349985830203890?l=npb-algorytmy.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://npb-algorytmy.blogspot.com/feeds/3724349985830203890/comments/default' title='Komentarze do posta'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=8336144765189037467&amp;postID=3724349985830203890' title='Komentarze (0)'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/8336144765189037467/posts/default/3724349985830203890'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/8336144765189037467/posts/default/3724349985830203890'/><link rel='alternate' type='text/html' href='http://npb-algorytmy.blogspot.com/2008/09/metoda-wcze-i-wycze-cz-ii.html' title='Metoda włączeń i wyłączeń cz II.'/><author><name>npb</name><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://3.bp.blogspot.com/_dMhinKIQ0wM/SNd7vTBErpI/AAAAAAAAADA/L8w731qRE2o/s72-c/wlwl.PNG' height='72' width='72'/><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-8336144765189037467.post-7858714786629809651</id><published>2008-09-20T08:58:00.009+02:00</published><updated>2008-09-21T15:39:49.101+02:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='metody'/><title type='text'>Metoda włączeń i wyłączeń cz I.</title><content type='html'>Zdarza się, że prosto jest policzyć liczbę elementów przecięcia kilku zbiorów, natomiast trudno liczbę elementów sumy tychże zbiorów. Przedstawimy metodę, dzięki której problem wyznaczenia sumy zbiorów sprowadzimy do wyznaczenia ich przecięć.&lt;br /&gt;&lt;br /&gt;Dla dwóch zbiorów sytuacja wygląda prosto. Dodajemy ilość elementów zbioru pierwszego do ilości elementów zbioru drugiego i odejmujemy ilość elementów przecięcia obu zbiorów.&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://2.bp.blogspot.com/_dMhinKIQ0wM/SNTAiIdr-6I/AAAAAAAAACg/vJwQ6SKP10I/s1600-h/ww2.PNG"&gt;&lt;img style="display:block; margin:0px auto 10px; text-align:center;cursor:pointer; cursor:hand;" src="http://2.bp.blogspot.com/_dMhinKIQ0wM/SNTAiIdr-6I/AAAAAAAAACg/vJwQ6SKP10I/s200/ww2.PNG" border="0" alt=""id="BLOGGER_PHOTO_ID_5248031158413556642" /&gt;&lt;/a&gt;Dla trzech zbiorów sprawa się nieco komplikuje, ale wciąż wzór wygląda przystępnie. Najpierw sumujemy liczbę elementów poszczególnych zbiorów. Następnie odejmujemy liczbę elementów w przecięciach każdych dwóch zbiorów. Na końcu dodajemy liczbę elementów znajdujących się we wszystkich zbiorach.&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://2.bp.blogspot.com/_dMhinKIQ0wM/SNTAiBeHk1I/AAAAAAAAACo/jl7sJ7VQt-0/s1600-h/ww3.PNG"&gt;&lt;img style="display:block; margin:0px auto 10px; text-align:center;cursor:pointer; cursor:hand;" src="http://2.bp.blogspot.com/_dMhinKIQ0wM/SNTAiBeHk1I/AAAAAAAAACo/jl7sJ7VQt-0/s200/ww3.PNG" border="0" alt=""id="BLOGGER_PHOTO_ID_5248031156536316754" /&gt;&lt;/a&gt;Dla czterech zbiorów wzór robi się już nieczytelny. Bardzo niemiły jest też wzór dla dowolnego n:&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://3.bp.blogspot.com/_dMhinKIQ0wM/SNTAiTmnqTI/AAAAAAAAACw/h7YUJEnZO70/s1600-h/wwn.PNG"&gt;&lt;img style="display:block; margin:0px auto 10px; text-align:center;cursor:pointer; cursor:hand;" src="http://3.bp.blogspot.com/_dMhinKIQ0wM/SNTAiTmnqTI/AAAAAAAAACw/h7YUJEnZO70/s200/wwn.PNG" border="0" alt=""id="BLOGGER_PHOTO_ID_5248031161403812146" /&gt;&lt;/a&gt;Gdzie P&lt;sub&gt;+&lt;/sub&gt;(n) oznacza zbiór potęgowy zbioru {1, 2, ..., n} bez zbioru pustego.&lt;br /&gt;&lt;br /&gt;Nie przejmuj się jeśli tego wzoru nie rozumiesz. Przedstawię teraz o wiele prostszą definicję metody włączeń i wyłączeń, którą łatwiej zapamiętać i łatwiej zastosować.&lt;br /&gt;&lt;blockquote&gt;Aby znaleźć liczbę elementów sumy zbiorów A&lt;sub&gt;1&lt;/sub&gt;, A&lt;sub&gt;2&lt;/sub&gt;, ..., A&lt;sub&gt;n&lt;/sub&gt; znajdź liczby elementów wszystkich możliwych przecięć zbiorów spośród {A&lt;sub&gt;1&lt;/sub&gt;, A&lt;sub&gt;2&lt;/sub&gt;, ..., A&lt;sub&gt;n&lt;/sub&gt;}, dodaj do siebie wyniki uzyskane dla przecięć nieparzystej liczby zbiorów, a następnie odejmij wyniki uzyskane dla przecięć parzystej liczby zbiorów.&lt;/blockquote&gt;Dowód poprawności tej metody znajduje się na Wikipedii (http://pl.wikipedia.org/wiki/Zasada_w%C5%82%C4%85cze%C5%84_i_wy%C5%82%C4%85cze%C5%84).&lt;br /&gt;&lt;br /&gt;Wadą tej metody jest oczywiście złożoność. Gdy mamy N zbiorów policzymy tą metodą liczebność 2&lt;sup&gt;N&lt;/sup&gt;-1 zbiorów. Niestety, niekiedy jest to najszybszy sposób.&lt;br /&gt;&lt;br /&gt;W części drugiej przedstawię kilka przykładów zadań, które wymagają użycia tej metody.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/8336144765189037467-7858714786629809651?l=npb-algorytmy.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://npb-algorytmy.blogspot.com/feeds/7858714786629809651/comments/default' title='Komentarze do posta'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=8336144765189037467&amp;postID=7858714786629809651' title='Komentarze (0)'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/8336144765189037467/posts/default/7858714786629809651'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/8336144765189037467/posts/default/7858714786629809651'/><link rel='alternate' type='text/html' href='http://npb-algorytmy.blogspot.com/2008/09/metoda-wcze-i-wycze-cz-i.html' title='Metoda włączeń i wyłączeń cz I.'/><author><name>npb</name><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://2.bp.blogspot.com/_dMhinKIQ0wM/SNTAiIdr-6I/AAAAAAAAACg/vJwQ6SKP10I/s72-c/ww2.PNG' height='72' width='72'/><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-8336144765189037467.post-951226150326527651</id><published>2008-09-18T11:35:00.007+02:00</published><updated>2008-09-18T11:49:15.494+02:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='algorytmy'/><title type='text'>Wyszukiwanie interpolacyjne</title><content type='html'>Mamy daną posortowaną N-elementową tablicę zawierającą losowe liczby. Chcemy sprawdzić czy znajduje się wśród nich liczba &lt;span style="font-style:italic;"&gt;k&lt;/span&gt;. Niejeden programista w tym miejscu krzyknie: "Wyszukiwanie binarne!". Pytanie: Czy można szybciej? Można!&lt;br /&gt;&lt;br /&gt;Przypomnijmy może szybko implementację wyszukiwania binarnego:&lt;br /&gt;&lt;pre class="mycode"&gt;int bsearch(int* A, int N, int k)&lt;br /&gt;{&lt;br /&gt;  int l = 0, r = N-1;&lt;br /&gt;&lt;br /&gt;  while (l &lt;= r)&lt;br /&gt;  {&lt;br /&gt;    int m = (l + r) / 2;&lt;br /&gt;&lt;br /&gt;    if (A[m] == k) return m;&lt;br /&gt;    else if(A[m] &lt; k) l = m + 1;&lt;br /&gt;    else r = m - 1;&lt;br /&gt;  }&lt;br /&gt;&lt;br /&gt;  return -1;&lt;br /&gt;}&lt;/pre&gt;W poszukiwaniu interpolacyjnym korzystamy z następującego spostrzeżenia. Gdy przeszukujemy książkę telefoniczną szukając pana Wołodyjowskiego, to zazwyczaj nie otwieramy książki na stronie środkowej (jak to robi wyszukiwanie binarne) lecz na jej końcu. Z kolei gdy szukamy w książce pani Adamskiej to zaglądamy na początek książki. Aby zaimplementować ten algorytm, wystarczy w algorytmie wyszukiwania binarnego zamienić linijkę:&lt;br /&gt;&lt;pre class="mycode"&gt;int m = (l + r) / 2;&lt;/pre&gt;na następującą:&lt;br /&gt;&lt;pre class="mycode"&gt;int m = l + (k - A[l]) * (r - l) / (A[r] - A[l]);&lt;/pre&gt;Zaletą takiego rozwiązania jest złożoność. Algorytm dla tablicy wypełnionej losowymi wartościami używa mniej niż &lt;span style="font-style:italic;"&gt;lg lg N + 1&lt;/span&gt; porównań (dla przypomnienia - wyszukiwanie binarne wykonuje &lt;span style="font-style:italic;"&gt;lg N + 1&lt;/span&gt; porównań). Funkcja ta rośnie bardzo wolno. Dla przykładu lg lg 10&lt;sup&gt;308&lt;/sup&gt; &lt; 10. A w przypadku, gdy tablica jest jeszcze regularniej ułożona niż w sposób losowy to liczba wymaganych porównań jest jeszcze mniejsza!&lt;br /&gt;&lt;br /&gt;Wadą takiego rozwiązania jest koszt obliczenia wartości m (wykonujemy tutaj dużo operacji arytmetycznych) co dla nie wielkich wartości N może spowodować, że algorytm wyszukiwania binarnego będzie działał szybciej.&lt;br /&gt;&lt;br /&gt;Ponadto algorytm nie nadaje się do wyszukiwania w tablicach, o których nie wiemy czy elementy w niej zawarte są równomiernie rozłożone. Algorytm dla przypadków pesymistycznych może wymagać nawet czasu liniowego.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/8336144765189037467-951226150326527651?l=npb-algorytmy.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://npb-algorytmy.blogspot.com/feeds/951226150326527651/comments/default' title='Komentarze do posta'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=8336144765189037467&amp;postID=951226150326527651' title='Komentarze (2)'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/8336144765189037467/posts/default/951226150326527651'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/8336144765189037467/posts/default/951226150326527651'/><link rel='alternate' type='text/html' href='http://npb-algorytmy.blogspot.com/2008/09/wyszukiwanie-interpolacyjne.html' title='Wyszukiwanie interpolacyjne'/><author><name>npb</name><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>2</thr:total></entry><entry><id>tag:blogger.com,1999:blog-8336144765189037467.post-830825776071107142</id><published>2008-09-08T17:33:00.012+02:00</published><updated>2008-09-20T12:38:35.987+02:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='metody'/><title type='text'>Wyszukiwanie binarne po wynikach cz III.</title><content type='html'>W poprzedniej części pokazaliśmy, że czasami łatwiej jest powiedzieć czy dana wartość spełnia warunki zadania, niż znaleźć najmniejszą z nich. W tej części przedstawię metodę, którą można rozwiązać wszystkie przedstawione w tej serii zadania. Przyjrzyjmy się najpierw jakie warunki musi spełniać zadanie, aby można było skorzystać z &lt;span style="font-weight: bold;"&gt;wyszukiwania binarnego po wynikach&lt;/span&gt;.&lt;br /&gt;&lt;br /&gt;Aby móc skorzystać z opisanej poniżej metody, zadanie musi spełniać następujące warunki:&lt;br /&gt;&lt;ul&gt;&lt;li&gt;Szukamy element &lt;span style="font-style: italic;"&gt;e&lt;/span&gt; który:&lt;/li&gt;&lt;ul&gt;&lt;li&gt;Spełnia warunki zadania&lt;/li&gt;&lt;li&gt;Jest najmniejszym {największym} takim elementem&lt;/li&gt;&lt;/ul&gt;&lt;li&gt;Dla każdych elementów d oraz d' takich, że d &amp;lt; d' {d &amp;gt; d'} to jeśli d spełnia warunki zadania, to d' także&lt;/li&gt;&lt;/ul&gt;Drugi warunek może wydawać się dla niektórych skomplikowany. Dlatego rozpatrzymy go na przykładach:&lt;br /&gt;&lt;br /&gt;Zadanie o krowach (&lt;span style="font-style:italic;"&gt;d&lt;/span&gt; &amp;gt; &lt;span style="font-style:italic;"&gt;d'&lt;/span&gt;). Jeśli potrafimy tak rozdzielić krowy, aby każda z nich była oddalona o conajmniej &lt;span style="font-style:italic;"&gt;d&lt;/span&gt; jednostek od siebie, to potrafimy to też zrobić aby odległość między każdą z nich była większa o &lt;span style="font-style:italic;"&gt;d'&lt;/span&gt; (wystarczy wybrać te same obory).&lt;br /&gt;&lt;br /&gt;Zadanie o złodzieju (&lt;span style="font-style:italic;"&gt;d&lt;/span&gt; &amp;gt; &lt;span style="font-style:italic;"&gt;d'&lt;/span&gt;). Jeśli potrafimy tak wybrać przedmioty aby odpowiedni iloczyn był niemniejszy niż &lt;span style="font-style:italic;"&gt;d&lt;/span&gt;, to potrafimy też tak je wybrać aby był niemniejszy od &lt;span style="font-style:italic;"&gt;d'&lt;/span&gt; (wystarczy wybrać te same przedmioty).&lt;br /&gt;&lt;br /&gt;Zadanie o zabytkach (&lt;span style="font-style:italic;"&gt;d&lt;/span&gt; &amp;lt; &lt;span style="font-style:italic;"&gt;d'&lt;/span&gt;). Jeśli potrafimy znaleźć po &lt;span style="font-style:italic;"&gt;d&lt;/span&gt; dniach cykl w grafie, to potrafimy też znaleźć cykl po &lt;span style="font-style:italic;"&gt;d'&lt;/span&gt; dniach (wystarczy "znaleźć" ten sam cykl).&lt;br /&gt;&lt;br /&gt;Zatem drugi warunek mówi nam rzecz następującą. Podzielmy wszystkie elementy na dwa zbiory. W pierwszy zbiorze znajdą się wszystkie te liczby, które spełniają warunek zadania, a w drugim te które tego warunku nie spełniają. Każdy element w tym pierwszym zbiorze jest większy {mniejszy} niż każdy element w tym drugim. Prezentuje nam to poniższy rysunek:&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://1.bp.blogspot.com/_dMhinKIQ0wM/SM6MLEkojrI/AAAAAAAAACY/p2oeQ-tHUOw/s1600-h/binpowynik.PNG"&gt;&lt;img style="display:block; margin:0px auto 10px; text-align:center;cursor:pointer; cursor:hand;" src="http://1.bp.blogspot.com/_dMhinKIQ0wM/SM6MLEkojrI/AAAAAAAAACY/p2oeQ-tHUOw/s200/binpowynik.PNG" border="0" alt=""id="BLOGGER_PHOTO_ID_5246284737767050930" /&gt;&lt;/a&gt;Metoda wyszukiwania binarnego po wyniku przypomina zabawę w zgadywankę. Ja pomyślę o jakiejś liczbie. Ty będziesz zgadywał jaka to liczba, a ja będę mówił czy moja liczba jest większa czy mniejsza lub równa.&lt;br /&gt;&lt;br /&gt;Pierwszym krokiem będzie znalezienie 2 elementów. Pierwszy z nich ma spełniać warunki zadania, a drugi nie. Oznaczmy je jako &lt;span style="font-style: italic;"&gt;S&lt;/span&gt;&lt;sub style="font-style: italic;"&gt;min&lt;/sub&gt; oraz &lt;span style="font-style: italic;"&gt;S&lt;/span&gt;&lt;sub style="font-style: italic;"&gt;max&lt;/sub&gt;.&lt;br /&gt;&lt;br /&gt;Nasze rozwiązanie będzie znajdowało się gdzieś w środku (&lt;span style="font-style: italic;"&gt;S&lt;/span&gt;&lt;sub style="font-style: italic;"&gt;min&lt;/sub&gt;, &lt;span style="font-style: italic;"&gt;S&lt;/span&gt;&lt;sub style="font-style: italic;"&gt;max&lt;/sub&gt;). Policzmy średnią &lt;span style="font-style: italic;"&gt;S&lt;/span&gt;&lt;sub style="font-style: italic;"&gt;śr&lt;/sub&gt; = (&lt;span style="font-style: italic;"&gt;S&lt;/span&gt;&lt;sub style="font-style: italic;"&gt;min&lt;/sub&gt; + &lt;span style="font-style: italic;"&gt;S&lt;/span&gt;&lt;sub style="font-style: italic;"&gt;max&lt;/sub&gt;) / 2. W zależności od tego czy &lt;span style="font-style: italic;"&gt;S&lt;/span&gt;&lt;sub style="font-style: italic;"&gt;śr&lt;/sub&gt; spełnia czy nie spełnia warunków zadania, może zmniejszyć obszar naszych poszukiwań do (&lt;span style="font-style: italic;"&gt;S&lt;/span&gt;&lt;sub style="font-style: italic;"&gt;min&lt;/sub&gt;, &lt;span style="font-style: italic;"&gt;S&lt;/span&gt;&lt;sub style="font-style: italic;"&gt;śr&lt;/sub&gt;) lub (&lt;span style="font-style: italic;"&gt;S&lt;/span&gt;&lt;sub style="font-style: italic;"&gt;śr&lt;/sub&gt;, &lt;span style="font-style: italic;"&gt;S&lt;/span&gt;&lt;sub style="font-style: italic;"&gt;max&lt;/sub&gt;). Cały akapit powtarzamy dopóki nie będziemy pewni poprawnej odpowiedzi.&lt;br /&gt;&lt;br /&gt;Istnieje wiele niepoprawnych algorytmów do zadań, które tu omówiliśmy. W następnej notce zaprezentuję kontrprzykłady do niektórych z nich.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/8336144765189037467-830825776071107142?l=npb-algorytmy.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://npb-algorytmy.blogspot.com/feeds/830825776071107142/comments/default' title='Komentarze do posta'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=8336144765189037467&amp;postID=830825776071107142' title='Komentarze (0)'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/8336144765189037467/posts/default/830825776071107142'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/8336144765189037467/posts/default/830825776071107142'/><link rel='alternate' type='text/html' href='http://npb-algorytmy.blogspot.com/2008/09/wyszukiwanie-binarne-po-wynikach-cz-iii.html' title='Wyszukiwanie binarne po wynikach cz III.'/><author><name>npb</name><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://1.bp.blogspot.com/_dMhinKIQ0wM/SM6MLEkojrI/AAAAAAAAACY/p2oeQ-tHUOw/s72-c/binpowynik.PNG' height='72' width='72'/><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-8336144765189037467.post-4737423309020996560</id><published>2008-08-28T13:56:00.008+02:00</published><updated>2008-09-07T10:36:28.146+02:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='metody'/><title type='text'>Wyszukiwanie binarne po wynikach cz II.</title><content type='html'>Przypomnijmy, że wszystkie zadania z części pierwszej to zadania optymalizacyjne. Szukamy największej (najmniejszej) wartości, która spełnia pewne określone warunki. W drugiej części zamiast szukać takiej wartości, sprawdzimy czy konkretna wartość &lt;span style="font-style: italic;"&gt;k&lt;/span&gt; spełnia dane warunki.&lt;br /&gt;&lt;br /&gt;Zadanie o krowach. Napiszmy algorytm, który zwróci prawdę jeśli da się tak ustawić krowy, aby każde dwie z nich były oddalone od siebie o co najmniej k jednostek. Zadanie to daje się rozwiązać zachłannie. Dla pierwszej krowy wybieramy oborę położoną najbardziej na lewo.  Następnie usuwamy wszystkie obory, które znajdują się mniej niż &lt;span style="font-style: italic;"&gt;k&lt;/span&gt; jednostek od tej. Powtarzamy to do momentu, w którym zabraknie nam krów lub miejsc w oborach. Jeśli braknie nam krów to znaczy, że da się tak ułożyć w oborach, aby każde dwie były oddalone od siebie o &lt;span class="blsp-spelling-corrected" id="SPELLING_ERROR_0"&gt;co najmniej&lt;/span&gt; &lt;span style="font-style: italic;"&gt;k&lt;/span&gt;. Jeśli braknie nam obór, to oznacza że się nie da.&lt;br /&gt;&lt;br /&gt;Zadanie o złodzieju. Sprawdzamy czy da się wybrać tak &lt;span style="font-style: italic;"&gt;i&lt;/span&gt; przedmiotów, aby określony w zadaniu iloraz był większy bądź równy &lt;span style="font-style: italic;"&gt;k&lt;/span&gt;. Dokonując kolejnych modyfikacji ilorazu, dostajemy następujący wzór (jako &lt;span style="font-style: italic;"&gt;I&lt;/span&gt; rozumiemy w tym wzorze zbiór wybranych przez złodzieja przedmiotów):&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://3.bp.blogspot.com/_dMhinKIQ0wM/SMOKnNV1AdI/AAAAAAAAACI/zUkiSJZrWL4/s1600-h/zlodziej.gif"&gt;&lt;img style="margin: 0px auto 10px; display: block; text-align: center; cursor: pointer;" src="http://3.bp.blogspot.com/_dMhinKIQ0wM/SMOKnNV1AdI/AAAAAAAAACI/zUkiSJZrWL4/s200/zlodziej.gif" alt="" id="BLOGGER_PHOTO_ID_5243186797390135762" border="0" /&gt;&lt;/a&gt;Wzór ten można łatwo sprawdzić. Wybieramy &lt;span style="font-style: italic;"&gt;i&lt;/span&gt; przedmiotów, których wartość cena - k * waga jest najmniejsza wśród wszystkich przedmiotów. Jeśli suma tych wartości &lt;span style="font-style: italic;"&gt;i&lt;/span&gt; przedmiotów jest większa lub równa od zera to znaczy że da się wybrać &lt;span style="font-style: italic;"&gt;i&lt;/span&gt; przedmiotów aby iloczyn sumy cen do sumy wag był większy bądź równy niż &lt;span style="font-style: italic;"&gt;k&lt;/span&gt;. Jeśli jest mniejsza od zera to nie da się.&lt;br /&gt;&lt;br /&gt;Zadanie o zabytkach. Sprawdzamy czy po &lt;span style="font-style: italic;"&gt;k&lt;/span&gt; dniach będzie można wybrać jakiś zabytek, a następnie autostradami przejechać przez kilka innych zabytków i wrócić do pierwszego. To zadanie z tych trzech jest chyba najprostsze. Bierzemy zabytki jako wierzchołki, &lt;span style="font-style: italic;"&gt;k&lt;/span&gt; pierwszych autostrad jako krawędzie skierowane i sprawdzamy czy tak utworzony graf jest grafem cyklicznym.&lt;br /&gt;&lt;br /&gt;Mamy trzy procedury, które w czasie liniowym (czyli bardzo szybko) mówią nam, czy &lt;span style="font-style: italic;"&gt;k&lt;/span&gt; spełnia określone w zadaniach warunki. W następnej części napiszę, jak na podstawie tych funkcji napisać procedurę, która znajdzie najmniejsze (największe) takie &lt;span style="font-style: italic;"&gt;k&lt;/span&gt;, które spełnia warunki zadania.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/8336144765189037467-4737423309020996560?l=npb-algorytmy.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://npb-algorytmy.blogspot.com/feeds/4737423309020996560/comments/default' title='Komentarze do posta'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=8336144765189037467&amp;postID=4737423309020996560' title='Komentarze (0)'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/8336144765189037467/posts/default/4737423309020996560'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/8336144765189037467/posts/default/4737423309020996560'/><link rel='alternate' type='text/html' href='http://npb-algorytmy.blogspot.com/2008/08/wyszukiwanie-binarne-po-wynikach-cz-ii.html' title='Wyszukiwanie binarne po wynikach cz II.'/><author><name>npb</name><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://3.bp.blogspot.com/_dMhinKIQ0wM/SMOKnNV1AdI/AAAAAAAAACI/zUkiSJZrWL4/s72-c/zlodziej.gif' height='72' width='72'/><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-8336144765189037467.post-4510889874180880505</id><published>2008-08-26T12:21:00.008+02:00</published><updated>2008-08-28T15:26:11.296+02:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='metody'/><title type='text'>Wyszukiwanie binarne po wynikach cz I.</title><content type='html'>W części pierwszej przedstawię trzy zadania. Wszystkie zadanie można rozwiązać za pomocą metody zwanej wyszukiwaniem binarnym po wyniku. Oto i one:&lt;br /&gt;&lt;br /&gt;Zadanie o krowach. Farmer John wybudował nową oborę dla krów z &lt;span style="font-style: italic;"&gt;N&lt;/span&gt; boksami. Boksy są ulokowane w linii prostej na pozycjach &lt;span style="font-style: italic;"&gt;x&lt;/span&gt;&lt;sub style="font-style: italic;"&gt;1&lt;/sub&gt;, &lt;span style="font-style: italic;"&gt;x&lt;/span&gt;&lt;sub style="font-style: italic;"&gt;2&lt;/sub&gt;, ..., &lt;span style="font-style: italic;"&gt;x&lt;/span&gt;&lt;sub style="font-style: italic;"&gt;N&lt;/sub&gt;. John ma &lt;span style="font-style: italic;"&gt;C&lt;/span&gt; (&lt;span style="font-style: italic;"&gt;C &lt;= N&lt;/span&gt;) krów. Przy czym nie lubią one przebywać blisko ze sobą. Dlatego John chce tak umieścić krowy w boksach, aby odległość między dwoma najbliższymi krowami była możliwie jak największa.&lt;br /&gt;&lt;br /&gt;Zadanie o złodzieju. Mamy dane &lt;span style="font-style: italic;"&gt;n&lt;/span&gt; przedmiotów. Każdy przedmiot ma określoną cenę oraz określoną wagę. Złodziej chce ukraść &lt;span style="font-style: italic;"&gt;i&lt;/span&gt; przedmiotów. Przy czym chce wybrać tak przedmioty, aby stosunek sumy cen wszystkich ukradzionych przedmiotów do sumy ich wag była jak największa. Należy podać wartość iloczynu z dokładnością dwóch cyfr po przecinku.&lt;br /&gt;&lt;br /&gt;Zadanie o zabytkach. Mamy w mieście &lt;span style="font-style: italic;"&gt;n&lt;/span&gt; zabytków. Chcemy je połączyć &lt;span style="font-style: italic;"&gt;m&lt;/span&gt; jednokierunkowymi drogami. W każdym dniu będzie budowana jedna droga. Kolejność budowy dróg jest ustalona. Pytamy o najmniejsze takie &lt;span style="font-style: italic;"&gt;k&lt;/span&gt;, że po &lt;span style="font-style: italic;"&gt;k&lt;/span&gt; dniach będzie istnieć ścieżka zaczynająca się i kończąca przy tym samym zabytku.&lt;br /&gt;&lt;br /&gt;Proponuję, aby Czytelnik spróbował samodzielnie rozwiązać każde z powyższych zadań. W tym miejscu nie ważna jest złożoność Twoich rozwiązań, ale docelowo będziemy chcieli, aby rozwiązania działały w czasie liniowo-logarytmicznym.&lt;br /&gt;&lt;br /&gt;W II części wyjaśni się co te na pozór różne zadania mają ze sobą wspólnego.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/8336144765189037467-4510889874180880505?l=npb-algorytmy.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://npb-algorytmy.blogspot.com/feeds/4510889874180880505/comments/default' title='Komentarze do posta'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=8336144765189037467&amp;postID=4510889874180880505' title='Komentarze (0)'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/8336144765189037467/posts/default/4510889874180880505'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/8336144765189037467/posts/default/4510889874180880505'/><link rel='alternate' type='text/html' href='http://npb-algorytmy.blogspot.com/2008/08/wyszukiwanie-binarne-po-wynikach-cz-i.html' title='Wyszukiwanie binarne po wynikach cz I.'/><author><name>npb</name><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-8336144765189037467.post-1393446665369089231</id><published>2008-08-23T10:03:00.006+02:00</published><updated>2008-08-23T12:33:37.283+02:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='algorytmy'/><title type='text'>Wzory Cramera</title><content type='html'>Powiedzmy, że mamy dany układ 2 (3) równań liniowych z 2 (3) niewiadomymi o współczynnikach całkowitych. Wiemy, że układ ma dokładnie jedno rozwiązanie. Chcemy je obliczyć, przy czym chcemy liczyć na liczbach całkowitych tak długo jak tylko się da. Świetnie do tego nadają się wzory Cramera.&lt;br /&gt;Niech dany będzie następujący układ równań:&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://1.bp.blogspot.com/_dMhinKIQ0wM/SK_hlQHKtpI/AAAAAAAAABo/Lp56rSb5qgo/s1600-h/cramera1.gif"&gt;&lt;img style="margin: 0px auto 10px; display: block; text-align: center; cursor: pointer;" src="http://1.bp.blogspot.com/_dMhinKIQ0wM/SK_hlQHKtpI/AAAAAAAAABo/Lp56rSb5qgo/s200/cramera1.gif" alt="" id="BLOGGER_PHOTO_ID_5237652921751615122" border="0" /&gt;&lt;/a&gt;Macierzą &lt;span style="font-style: italic;"&gt;A&lt;/span&gt; nazywamy macierzą współczynników tego układu, a macierz &lt;span style="font-style: italic;"&gt;B&lt;/span&gt; macierzą wyrazów wolnych.&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://4.bp.blogspot.com/_dMhinKIQ0wM/SK_hvBhei2I/AAAAAAAAABw/JhcndLAAvlo/s1600-h/cramera2.gif"&gt;&lt;img style="margin: 0px auto 10px; display: block; text-align: center; cursor: pointer;" src="http://4.bp.blogspot.com/_dMhinKIQ0wM/SK_hvBhei2I/AAAAAAAAABw/JhcndLAAvlo/s200/cramera2.gif" alt="" id="BLOGGER_PHOTO_ID_5237653089634126690" border="0" /&gt;&lt;/a&gt;Macierz &lt;span style="font-style: italic;"&gt;G&lt;/span&gt;&lt;sub style="font-style: italic;"&gt;i&lt;/sub&gt; powstaje w ten sposób, że w macierzy &lt;span style="font-style: italic;"&gt;A&lt;/span&gt; kolumnę i-tą zastępujemy macierzą &lt;span style="font-style: italic;"&gt;B&lt;/span&gt;. Dla przykładu macierz &lt;span style="font-style: italic;"&gt;G&lt;/span&gt;&lt;sub style="font-style: italic;"&gt;2&lt;/sub&gt; będzie wyglądał następująco:&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://1.bp.blogspot.com/_dMhinKIQ0wM/SK_h4ClfgfI/AAAAAAAAAB4/1EgTovxCvpk/s1600-h/cramera3.gif"&gt;&lt;img style="margin: 0px auto 10px; display: block; text-align: center; cursor: pointer;" src="http://1.bp.blogspot.com/_dMhinKIQ0wM/SK_h4ClfgfI/AAAAAAAAAB4/1EgTovxCvpk/s200/cramera3.gif" alt="" id="BLOGGER_PHOTO_ID_5237653244538225138" border="0" /&gt;&lt;/a&gt;Rozwiązanie naszego równania wygląda teraz następująco:&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://1.bp.blogspot.com/_dMhinKIQ0wM/SK_iC_5ARMI/AAAAAAAAACA/VaKFEBeRTjI/s1600-h/cramera4.gif"&gt;&lt;img style="margin: 0px auto 10px; display: block; text-align: center; cursor: pointer;" src="http://1.bp.blogspot.com/_dMhinKIQ0wM/SK_iC_5ARMI/AAAAAAAAACA/VaKFEBeRTjI/s200/cramera4.gif" alt="" id="BLOGGER_PHOTO_ID_5237653432793318594" border="0" /&gt;&lt;/a&gt;Gdzie &lt;span style="font-style: italic;"&gt;det X&lt;/span&gt; oznacza wyznacznik macierzy X (http://pl.wikipedia.org/wiki/Wyznacznik_macierzy). Jeżeli wyznacznik macierzy &lt;span style="font-style: italic;"&gt;A&lt;/span&gt; jest równy zero to układ równań nie ma rozwiązania (lub ma ich nieskończenie wiele).&lt;br /&gt;Algorytm wyznacznika macierzy nie zawsze jest łatwa do implementacji. Jednak dla macierzy &lt;span style="font-style: italic;"&gt;2x2&lt;/span&gt; oraz &lt;span style="font-style: italic;"&gt;3x3&lt;/span&gt; obliczenie wyznacznika nie jest trudnym zadaniem.&lt;br /&gt;Co ważne: podczas obliczania wyznacznika korzystamy z operacji dodawania, odejmowania i mnożenia. Nie wychodzi zatem poza liczby całkowite. Operację dzielenia dokonujemy dopiero na samym końcu.&lt;br /&gt;Na koniec jeszcze powiem, że wzory Cramera działają dla każdego układu n równań z n niewiadomymi. Założenia o tym, że mamy tylko 2 (3) równania oraz że współczynniki są całkowite, poczyniliśmy aby pokazać w jakich sytuacjach najlepiej korzystać z metody tu przedstawionej.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/8336144765189037467-1393446665369089231?l=npb-algorytmy.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://npb-algorytmy.blogspot.com/feeds/1393446665369089231/comments/default' title='Komentarze do posta'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=8336144765189037467&amp;postID=1393446665369089231' title='Komentarze (0)'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/8336144765189037467/posts/default/1393446665369089231'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/8336144765189037467/posts/default/1393446665369089231'/><link rel='alternate' type='text/html' href='http://npb-algorytmy.blogspot.com/2008/08/wzory-cramera.html' title='Wzory Cramera'/><author><name>npb</name><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://1.bp.blogspot.com/_dMhinKIQ0wM/SK_hlQHKtpI/AAAAAAAAABo/Lp56rSb5qgo/s72-c/cramera1.gif' height='72' width='72'/><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-8336144765189037467.post-1324080772231048274</id><published>2008-08-21T10:50:00.000+02:00</published><updated>2008-08-21T13:07:20.326+02:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='wydarzenia'/><title type='text'>Zapowiedzi</title><content type='html'>W najbliższym czasie mam zamiar umieszczenie notek na następujące tematy:&lt;br /&gt;&lt;ul&gt;&lt;li&gt;Metoda węgierska&lt;/li&gt;&lt;li&gt;Twierdzenie Königa&lt;/li&gt;&lt;li&gt;Przewidywanie skoków w procesorze&lt;/li&gt;&lt;li&gt;Uproszczony algorytm Grahama&lt;/li&gt;&lt;li&gt;Wzory Cramera&lt;/li&gt;&lt;li&gt;Metoda włączeń i wyłączeń&lt;/li&gt;&lt;li&gt;Meet in the middle&lt;/li&gt;&lt;li&gt;Lemat Burnside’a&lt;/li&gt;&lt;/ul&gt;Jest to lista bardzo "luźna". Notki pojawią się prawdopodobnie w innej kolejności. Dopuszczam też możliwość umieszczenia w bliskiej przyszłości notek nie wymienionych w tym spisie.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/8336144765189037467-1324080772231048274?l=npb-algorytmy.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://npb-algorytmy.blogspot.com/feeds/1324080772231048274/comments/default' title='Komentarze do posta'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=8336144765189037467&amp;postID=1324080772231048274' title='Komentarze (0)'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/8336144765189037467/posts/default/1324080772231048274'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/8336144765189037467/posts/default/1324080772231048274'/><link rel='alternate' type='text/html' href='http://npb-algorytmy.blogspot.com/2008/08/zapowiedzi.html' title='Zapowiedzi'/><author><name>npb</name><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-8336144765189037467.post-7953388477022956184</id><published>2008-08-20T12:28:00.009+02:00</published><updated>2008-08-21T09:23:44.702+02:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='algorytmy'/><category scheme='http://www.blogger.com/atom/ns#' term='technikalia'/><title type='text'>Wierszami czy kolumnami? cz III. (Mnożenie macierzy)</title><content type='html'>W niniejszej notce omówię algorytm mnożenia macierzy. Jeśli czytelnik z mnożeniem macierzy spotyka się po raz pierwszy to odsyłam do wikipedii (http://pl.wikipedia.org/wiki/Mno%C5%BCenie_macierzy). Operacja mnożenia macierzy jest tam bardzo ładnie wytłumaczona.&lt;br /&gt;Przed napisaniem tej notki wyszukałem w googlach hasło "mnożenie macierzy C++". Pobieżne przejrzenie wyników potwierdziło moje przypuszczenia - zdecydowana większość programistów pisze pętle w złej kolejności. Przedstawmy najpierw typową implementację mnożenia macierzy:&lt;br /&gt;&lt;pre class="mycode"&gt;const int N = 1000;&lt;br /&gt;static int T[N][N];&lt;br /&gt;static int A[N][N];&lt;br /&gt;static int B[N][N];&lt;br /&gt;&lt;br /&gt;for (int i = 0; i &lt; N; i++)&lt;br /&gt;  for (int j = 0; j &lt; N; j++)&lt;br /&gt;  {&lt;br /&gt;    T[i][j] = 0;&lt;br /&gt;    for (int k = 0; k &lt; N; k++)&lt;br /&gt;      T[i][j] += A[i][k] * B[k][j];&lt;br /&gt;  }&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;Gdzie leży błąd można na pierwszy rzut oka nie zauważyć. Wytłumaczę to zatem, aby wszyscy mogli to zauważyć, a w razie innego algorytmu - powtórzyć rozumowanie.&lt;br /&gt;Z tablicą T nie ma problemów. Wewnątrz pętli odwołujemy się do elementu T[i][j]. Przy czym przechodzimy ją po wierszach. To znaczy, że pętla iterująca po j-tach znajduje się &lt;span style="font-weight:bold;"&gt;wewnątrz&lt;/span&gt; pętli iterującej po zmiennej i. Podobna sytuacja jest z tablicą A. Odwołujemy się do elementu A[i][k], czyli przechodzimy ją po wierszach (pętla iterująca po zmiennej k znajduje się &lt;span style="font-weight:bold;"&gt;wewnątrz&lt;/span&gt; pętli iterującej po zmiennej i). Problem jest z tablicą B.&lt;br /&gt;W przypadku tablicy B odwołujemy się do elementu B[k][j]. Przechodzimy ją zatem po kolumnach - pętla iterująca po j-tach znajduje się na &lt;span style="font-weight:bold;"&gt;zewnątrz&lt;/span&gt; pętli iterującej po zmiennej k. Procesor zatem nie będzie wczytywał optymalnie tablicy B do pamięci cache.&lt;br /&gt;Możemy to poprawić przestawiając miejscami pętle ze zmienną k z pętlą ze zmienną j. Musimy też stworzyć osobne pętle zerujące tablicę.&lt;br /&gt;&lt;pre class="mycode"&gt;const int N = 1000;&lt;br /&gt;static int T[N][N];&lt;br /&gt;static int A[N][N];&lt;br /&gt;static int B[N][N];&lt;br /&gt;&lt;br /&gt;for (int i = 0; i &lt; N; i++)&lt;br /&gt;  for (int j = 0; j &lt; N; j++)&lt;br /&gt;    T[i][j] = 0;&lt;br /&gt;&lt;br /&gt;for (int i = 0; i &lt; N; i++)&lt;br /&gt;  for (int k = 0; k &lt; N; k++)&lt;br /&gt;    for (int j = 0; j &lt; N; j++)&lt;br /&gt;      T[i][j] += A[i][k] * B[k][j];&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;Tutaj już wszystko powinno działać w porządku. Wszystkie tablice przechodzimy po wierszach.&lt;br /&gt;Przykład ten jest często wykorzystywany przy omawianiu przechodzenia tablicy po wierszach i kolumnach. Oba algorytmy mają nawet swoje nazwy potoczne. Pierwszy z nich nazywamy algorytmem ijk, natomiast drugi (jak nietrudno się domyślić) ikj.&lt;br /&gt;Czas na przetestowanie obu rozwiązań. Różnica jest odczuwalna:&lt;br /&gt;&lt;span style="font-size:85%;"&gt;&lt;span style="font-family: courier new;"&gt;algorytm ijk - 0:13.63&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family: courier new;"&gt;algorytm ikj - 0:10.45&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;Motto tego trzy częściowego kursu jest następujące: "Iterowanie po wierszach przyśpiesza program". Czasem o kilka sekund, czasem nawet ośmiokrotnie. Warto o tym pamiętać bo przestawianie dwóch pętli nas nic nie kosztuje.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/8336144765189037467-7953388477022956184?l=npb-algorytmy.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://npb-algorytmy.blogspot.com/feeds/7953388477022956184/comments/default' title='Komentarze do posta'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=8336144765189037467&amp;postID=7953388477022956184' title='Komentarze (2)'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/8336144765189037467/posts/default/7953388477022956184'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/8336144765189037467/posts/default/7953388477022956184'/><link rel='alternate' type='text/html' href='http://npb-algorytmy.blogspot.com/2008/08/wierszami-czy-kolumnami-cz-iii-mnoenie.html' title='Wierszami czy kolumnami? cz III. (Mnożenie macierzy)'/><author><name>npb</name><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>2</thr:total></entry><entry><id>tag:blogger.com,1999:blog-8336144765189037467.post-1997706452588181363</id><published>2008-08-20T09:15:00.007+02:00</published><updated>2008-08-20T16:57:46.417+02:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='technikalia'/><title type='text'>Wierszami czy kolumnami? cz II.</title><content type='html'>Szybkość działania programu nie zależy wyłącznie od ilości wykonanych operacji. Na to czy program zadziała szybko ma wpływ wiele innych czynników. Dzisiaj poznamy jeden z nich.&lt;br /&gt;Procesor posiada specjalną pamięć podręczną zwaną pamięcią cache. Jest ona o wiele szybsza od pamięci RAM. Gdy procesor potrzebuje jakiś danych to najpierw sprawdza czy są one dostępne w pamięci cache. Jeśli tak to świetnie! Dostaniemy do nich dostęp bardzo szybko. Jeśli nie - dostęp do tych danych potrwa nieco dłużej. Często będzie nam zależeć na tym, aby ten drugi przypadek starać się wykluczyć.&lt;br /&gt;Procesor stara się przewidzieć jakie dane będą potrzebne w najbliższej przyszłości. Dwa podstawowe warunki jakimi sugeruje się procesor to:&lt;br /&gt;&lt;ul&gt;&lt;li&gt;Jeśli jakiś obiekt był ostatnio używany, to istnieje duże prawdopodobieństwo, że będzie używany w najbliższej przyszłości&lt;/li&gt;&lt;li&gt;Jeśli jakiś obiekt był ostatnio używany, to istnieje duże prawdopodobieństwo, że w najbliższej przyszłości będą używane obiekty leżące blisko niego&lt;br /&gt;&lt;/li&gt;&lt;/ul&gt;Jako elementy "blisko niego" rozumiemy tutaj elementy, które znajdują się koło niego w pamięci RAM (mają podobny adres maszynowy). Zadeklarujmy tablicę dwuwymiarową i sprawdźmy które elementy znajdują się koło których w pamięci. Podejrzewamy, że bezpośrednio koło elementu T[0][0] znajduje się albo element T[0][1], albo T[1][0]. Poniższy program rozwieje nasze wątpliwości.&lt;br /&gt;&lt;pre class="mycode"&gt;const int N = 1000;&lt;br /&gt;static char T[N][N];&lt;br /&gt;&lt;br /&gt;printf("0x%08x\n0x%08x\n0x%08x\n0x%08x\n",&lt;br /&gt;  &amp;T[0][0], &amp;T[0][1], &amp;T[1][0], &amp;T[0][N-1]);&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;Po uruchomieniu programu dostałem następujące wyniki (zachęcam do uruchomienia programu na własnym sprzęcie):&lt;br /&gt;&lt;pre class="mycode"&gt;0x00404040&lt;br /&gt;0x00404041&lt;br /&gt;0x00404428&lt;br /&gt;0x00404427&lt;/pre&gt;&lt;br /&gt;Zatem koło adresu T[0][0] znajduje się element T[0][1]. Natomiast element T[1][0] znajduje się o 1000 adresów dalej. Zachęcam do dalszych eksperymentów, w których wykażemy, że koło elementu T[0][1] znajduje się element T[0][2] itd.&lt;br /&gt;Po analizie naszego programu możemy wywnioskować również, że w pamięci po elemencie T[0][N-1] występuje element T[1][0]. Najlepiej iterować tablicę dwuwymiarową w kolejności występowania elementów w pamięci - czyli w kolejności: T[0][0], T[0][1], ..., T[0][N-1], T[1][0], ..., T[N-1][N-1].&lt;br /&gt;Wyjaśniło się nam zatem dlaczego algorytm iterujący po wierszach działa szybciej niż program iterujący po kolumnach. Starajmy się iterować w ten sposób tablice wielowymiarowe zawsze wtedy, kiedy mamy taką możliwość!&lt;br /&gt;W następnej notce przedstawię często spotykany algorytm, w którym stosując poznaną tu sztuczkę zwiększymy szybkość jego działania o kilka sekund.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/8336144765189037467-1997706452588181363?l=npb-algorytmy.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://npb-algorytmy.blogspot.com/feeds/1997706452588181363/comments/default' title='Komentarze do posta'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=8336144765189037467&amp;postID=1997706452588181363' title='Komentarze (0)'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/8336144765189037467/posts/default/1997706452588181363'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/8336144765189037467/posts/default/1997706452588181363'/><link rel='alternate' type='text/html' href='http://npb-algorytmy.blogspot.com/2008/08/wierszami-czy-kolumnami-cz-ii.html' title='Wierszami czy kolumnami? cz II.'/><author><name>npb</name><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-8336144765189037467.post-4057105112296998161</id><published>2008-08-19T12:51:00.012+02:00</published><updated>2008-08-20T09:09:50.284+02:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='technikalia'/><title type='text'>Wierszami czy kolumnami? cz I.</title><content type='html'>Zaczniemy od czegoś bardzo prostego. Sztuczkę tą powinni znać wszyscy programiści. Przyjrzyjmy się poniższemu programowi, dynamicznie liczącemu wartość pewnej tablicy.&lt;br /&gt;&lt;pre class="mycode"&gt;const int N = 10000;&lt;br /&gt;static int t[N][N];&lt;br /&gt;&lt;br /&gt;for (int i = 1; i &lt; N; i++)&lt;br /&gt;  for (int j = 1; j &lt; N; j++)&lt;br /&gt;    t[i][j] = max(t[i-1][j], t[i][j-1], t[i-1][j-1]);&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;Poniżej prezentuję ten sam program, z przestawionymi dwoma pętlami. Wyniki obu programów są takie same. Dla wyniku w tym przypadku nie ma bowiem znaczenia która pętla jest zewnętrzna a która wewnętrzna&lt;br /&gt;&lt;pre class="mycode"&gt;const int N = 10000;&lt;br /&gt;static int t[N][N];&lt;br /&gt;&lt;br /&gt;for (int j = 1; j &lt; N; j++)&lt;br /&gt;  for (int i = 1; i &lt; N; i++)&lt;br /&gt;    t[i][j] = max(t[i-1][j], t[i][j-1], t[i-1][j-1]);&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;Policzmy jednak czasy działania obu programów (jak zwykle w tym miejscu polecam własne eksperymenty w domu). Wynik być może niektórych zaskoczy. Pierwszy program działa 3-4 razy szybciej. Oto przykładowe czasy działania algorytmów na moim sprzęcie:&lt;br /&gt;&lt;br /&gt;&lt;span style=";font-family:courier new;font-size:85%;"  &gt;Algorytm pierwszy - 0:26.26&lt;br /&gt;Algorytm drugi - 1:13.37&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;Mojemu znajomemu po drobnej modyfikacji kodu udało się uzyskać następujące czasy:&lt;br /&gt;&lt;br /&gt;&lt;span style="font-size:85%;"&gt;&lt;span style="font-family:courier new;"&gt;Algorytm pierwszy - 0:01.23&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family:courier new;"&gt;Algorytm drugi - 0:09.67&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;Czyli pierwszy program działał 8 razy szybciej niż drugi.&lt;br /&gt;Oba programy wykonują jednakową liczbę operacji i liczą dokładnie to samo (tylko w innej kolejności). Zatem dlaczego pierwszy z nich działa o wiele szybciej? Napiszę o tym w następnej notce.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/8336144765189037467-4057105112296998161?l=npb-algorytmy.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://npb-algorytmy.blogspot.com/feeds/4057105112296998161/comments/default' title='Komentarze do posta'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=8336144765189037467&amp;postID=4057105112296998161' title='Komentarze (0)'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/8336144765189037467/posts/default/4057105112296998161'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/8336144765189037467/posts/default/4057105112296998161'/><link rel='alternate' type='text/html' href='http://npb-algorytmy.blogspot.com/2008/08/wierszami-czy-kolumnami-cz-i.html' title='Wierszami czy kolumnami? cz I.'/><author><name>npb</name><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-8336144765189037467.post-4423575920836435041</id><published>2008-08-17T21:33:00.000+02:00</published><updated>2008-08-17T21:43:44.728+02:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='wydarzenia'/><title type='text'>Zaczynamy!</title><content type='html'>Witam na moim nowym blogu poświęconym tematyce algorytmów. Wkrótce będziesz mógł przeczytać tutaj o algorytmach i strukturach danych, których nie znajdziesz w Cormenie, o sztuczkach programistycznych, o technikach projektowania algorytmów. Od czasu do czasu być może zamieszczę jakąś relację z konkursów programistycznych, w których będę brał udział. Albo umieszczę kody źródłowe jakiś większych programów.&lt;br /&gt;To już mój drugi blog poświęcony algorytmom. Pierwszy był zbyt formalny, przez co straciłem chęć do dalszego jego pisania. Mam nadzieję, że tym razem będzie inaczej.&lt;br /&gt;Pozdrawiam i życzę miłego czytania.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/8336144765189037467-4423575920836435041?l=npb-algorytmy.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://npb-algorytmy.blogspot.com/feeds/4423575920836435041/comments/default' title='Komentarze do posta'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=8336144765189037467&amp;postID=4423575920836435041' title='Komentarze (1)'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/8336144765189037467/posts/default/4423575920836435041'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/8336144765189037467/posts/default/4423575920836435041'/><link rel='alternate' type='text/html' href='http://npb-algorytmy.blogspot.com/2008/08/zaczynamy.html' title='Zaczynamy!'/><author><name>npb</name><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>1</thr:total></entry></feed>
