Seminarski rad: Učenje algoritama u Pythonu Autor izvornog teksta koji sam koristio: Pai H. Chou (University of California, Irvine) U kojoj mjeri je Python pogodan za učenje izrade algoritama? Željko Čejvanović Prof. Fizike i Tehnike, F-3245 3. god. zeljkocej@gmail.com 5/3/2011 Sadržaj: Sažetak.......................................................................................2 Uvod............................................................................................2 Uvodna lekcija: Sortiranje............................................................3 HeapSort (gomila) poredaj i prioritet redovi.................................4 Binarna stabla i Hufmann kodiranje............................................5 Grafikon Algoritmi........................................................................7 Zaključak i zašto je Python pogodan za učenje izrade algoritama?!.................................................................................9 7. Literatura.....................................................................................9 0. 1. 2. 3. 4. 5. 6. 1 Sažetak Dizajn i analiza algoritama su temeljne teme u računalnoj znanosti i obrazovanju na tehničkim fakultetima. Mnogi tečajevi algoritama uključuju programske zadatke kako bi učenici bolje razumjeli algoritme. Nažalost, korištenje tradicionalnih programskih jezika prisiljava studente da se bave detaljima strukture podataka i prateće rutine, a ne dizajnom algoritama. Python predstavlja algoritam-orijentirani jezik koji je jako potreban u obrazovanju. Prednosti Pythona su njegovi udžbenici poput sintakse i interaktivnost koja potiče eksperimentiranje. Još važnije, Python se može koristiti za zastupanje agregatne strukture podataka kao što su grafovi i mreže protoka u sažetom tekstualnom obliku, koji ne samo da potiče studente da eksperimentiraju s algoritmima, ali takoĎer dramatično smanjuje vrijeme razvoja. Ove značajke su provedene u studiju algoritama naravno s uspješnim rezultatima. 1. Uvod Algoritmi su najvažniji alati za svakoga tko mora riješiti probleme pisanja računalnih programa. Algoritmi se koriste ne samo od strane računalnih znanstvenika i inženjera računala, nego i mnogi u drugim inženjerskim disciplinama i znanosti. Kao rezultat toga, studenti raznih smjerova koriste tečajeve algoritama. Iako je moguće proučavati algoritme samo čitajući knjige i gledajuće rješene primjere, učenici će ih najbolje shvatiti tako da sami provedu neki algoritam. Kao rezultat toga, to nije neuobičajeno za tečajeve algoritama da uključuju programske zadatke. Udžbenici koji uključuju programiranje kao sastavni dio algoritma obrazovanja takoĎer su od autora tražili da zadovolji taj zahtjev [4]. Gotovo svi tečajevi i udžbenici su se do sada provodili u tradicionalnim jezikom kao što su C ili C+ + i Java (nedavno je stekao popularnost) [5]. Argument za korištenje tih jezika je uglavnom praktična, jer su studenti vjerojatno već iskusni u tim jezicima i to im daje praktične vještine. 1.1 Programiranje vs Algoritam Design (dizajn algoritama) Nažalost, iskustva su pokazala da programski zadaci u klasi algoritma ne moraju uvijek biti pedagoški korisni. Iako je većina algoritama od nekoliko redaka do pola stranice u udžbeniku, njihove implementacije često zahtijevaju stotine redaka u C-u ili Javi. Jedan od razloga je da ti jezici zahtijevaju deklaraciju globalnih varijabli, lokalne varijable i parametre prije nego što oni mogu koristiti. Drugi razlog, što je još važnije, je da su mnogi strukturama podataka kao što su popisi, povezane strukture podataka, kao i specijalizirana polja moraju biti projektirani i izvedeni za podršku algoritama, i složenost ovih vježbi brzo raste kad agregatne strukture podataka kao što su grafikoni ili protok mreža uključeni. U stvari, većina objektno orijentiranih programera će potrošiti većinu svojih napora u projektiranju klase i sučelja, i trošiti relativno malo vremena za punjenje u kodu za metode. Kao rezultat toga, ovi zadaci za programiranje će prisiliti studente da provedu mnogo vremena uz pitanja o programiranju, nego pitanjima za algoritme. Zbog ovoga bi mogli imati problema studenti koji nisu informatićkog smjera. 2 Neki instruktori pokušavaju ublažiti ovaj teret dajući studentima knjižicu rutine za strukture podataka. MeĎutim, još uvijek postoje mnogi problemi koji su svojstveni ovim jezicima, uključujući ulaz/izlaz i ponovno. Npr. , biblioteka može pružiti API za izgradnju stabla ili grafa zazivajući algoritam iz strukture podataka. Studenti moraju shvatiti njihov slučaj uzastopna poziva na dodavanje jednog čvora na vrijeme graf, ili pročitati opis grafikona iz datoteke. Bivši pristup može biti neugodan, jer izvorni kod ne sliči strukturi podataka, ali smisao je vezan za API. Potonji pristup, koji koristi prilagoĎeni jezik za zastupanje graf, može biti više koncizan,ali to zahtijeva vježbanje rutine, što može smanjiti ponovnu uporabu i proširivost. Znaći, kada shvatimo graf, možemo mijenjati neke postavke kako bi ga promijenili. 1.2 Python Edge (rub) Python adrese tih problema i čini uvjerljiv jezik za algoritme obrazovanje. Prvo, njegove uvlake-based sintaksa je toliko slična većini udžbenika da čak i studenti, bez puno programiranja nemaju problema kodiranja algoritama samo slijedeći knjigu. Zbog toga, popularnost s drugim jezicima je dvojbena, osobito s obzirom na činjenicu da njegov interaktivni način potiče studente da eksperimentiraju s njim bez dugog ciklusa. Drugo, Python pruža temeljne strukture podataka kao što su popisi, torke, rječnici i može se koristiti izravno algoritmima. Čak je i složenija struktura podataka kao što su drveće i grafikoni sažeti u čitljivom obliku. Postoji nekoliko prednosti: test slučajeva za algoritme mogu biti napisani direktno u Pythonu bez poziva svih podataka, strukturu izgradnje API, i bez da se oslanjaju na bilo koji konvertor. U bilo kojem trenutku, podatkovne strukture mogu se takoĎer prikazati u tekstualnom obliku koji je čitljiv za ljude i za Python. 2. Uvodna Lekcija: Sortiranje Većina udžbenika poćinje sa sortiranjem kao način da uvedu algoritme i složene analize. Naša strategija je da prikažemo algoritme rame uz rame s Python kodom kako bi pokazali njihovu sličnost. Mi smo započeli s InsertionSort, koja kao rezultat prikazuje niz s desna na lijevo: Algoritam iz udžbenika [1] Insertion-Sort(A) (umetanje-poredaj) 1 for j <- 2 to length[A] 2 do key <- A[j] 3 i <- j - 1 4 while i > 0 and A[i] > key 5 do A[i+1] <- A[i] 6 i <- i - 1 7 A[i + 1] <- key 3 Python kod def InsertionSort(A): for j in range(1, len(A)): key = A[j] i = j - 1 while (i >=0) and (A[i] > key): A[i+1] = A[i] i = i - 1 A[i+1] = key Kada učenici vide sličnost, većina njihovog straha prema programiranju jednostavno nestaje. Ona takoĎer pomaže da pokažu interaktivne prirode Python. Mi koristimo računalo-projektor i zapravo tip u programu, što je samo 8 linija dugo. Najbolji dio je, možemo testirati algoritam jednostavno, upišete u slučaju teksta u obliku popisa: >>> >>> >>> [1, x = [2,7,3,8,1] # create test case (stvoriti test slučaj) InsertionSort(x) # call routine (poziva rutinu) x # look at result (pogled na rezultat) 2, 3, 7, 8] U smislu, Python daje udžbenik važnosti jer algoritmi predstavljaju u udžbeniku nisu višesamo pseudocode ili koraka teorijskih interesa samo, mogu vidjeti kako se lako ga jezapravo izvršiti algoritme koristeći podatke koje oni generiraju. U stvari, mi takoĎ erpokazuju da je isti broj, bez izmjena, radi sasvim u redu s drugim tipovima podataka,uključujući i žice, torke, itd. Sortiranje je dobra polazna primjer, jer ne samo dakonstruira karte izravno, bez komplikacija sa memory management (biti riječi kasnije),ali parametar semantika takoĎer odgovara: duži donosi vrijednosti, dok su polja don osireferencu. 3. HeapSort (gomila) poredaj i prioritet redovi Naš uvod nastavlja s HeapSort poredajem i prioritet redovima. Heap je struktura podataka koja predstavlja gotovo uravnoteženo binarno stablo koristeći niz A[1 .. n], gdje se lijevo i desno nalazi dječji element A[i] smješten na A[2i], A[2i+1], odnosno, i A[i]> = A[2i], A[2i+1]. HeapSort gradi sortirani niz redova iz stražnjeg dijela polja prema naprijed jedan element u vrijeme vaĎenja najvećeg elementa iz skupine. U početku sortirani dio je prazan, i poziv na BuildHeap pretvara A[1 .. n] u skupini. Budući da iz skupine stavlja najveći element u A[1], u prvoj iteraciji smo ga izvaditi i staviti ga u A[n], koji je njegov ispravan sortirani položaj. Sljedeća iteracija ekstrakti drugi najveći element (iz A[1] opet) i stavlja ga u A[n-1], i sl., a to se nastavlja sve dok se sve ne sortira. Imajte na umu da se Heapify zove kao dio svakog koraka ekstrakcije. To je zato što ako mi razmijenimo A[1] i A[h], a zatim A[1 .. h1] više ne zadovoljava hrpu nekretnina, ali budući da je još uvijek "skoro" hrpa to jest, sve osim korijena položaj je još uvijek ispod gomile - to 4 može biti fiksno učinkovito u O(lg h) vrijeme pozivom Heapify bez mogućnosti obnavljanja u gomili O(h) na vrijeme. Jedna od razlika je da algoritam u udžbeniku poprima 1-na temelju niza pokazatelja,dok Python pretpostavlja 0-temeljen polja. Python kod je: def Parent(i): return i/2 def Left(i): return 2*i def Right(i): return 2*i+1 def Heapify(A, i, n): # A is "almost a heap" (except root); fix it so all of A is a heap l = Left(i) r = Right(i) if l <= n and A[l] > A[i]: largest = l else: largest = i if r <= n and A[r] > A[largest]: largest = r if largest != i: A[i], A[largest] = A[largest], A[i] Heapify(A, largest, n) def HeapLength(A): return len(A)-1 def BuildHeap(A): # build a heap A from an unsorted array n = HeapLength(A) for i in range(n/2,0,-1): Heapify(A,i,n) def HeapSort(A): # use a heap to build sorted array from the end BuildHeap(A) HeapSize=HeapLength(A) for i in range(HeapSize,1,-1): A[1],A[i]=A[i],A[1] # largest element is a root of heap, put it at the end of array HeapSize=HeapSize-1 # shrink heap size by 1 to get next largest element Heapify(A,1,HeapSize) Gomila i prioritet redovi su usko povezani, jer gomila može implementirati prioritetne redove učinkovito sa O(lg n)-vrijeme umetanja i vaĎenja. Jedna od razlika je, meĎutim, dinamička memorija upravljanja: u gomilu vrsta, veličina polja ostaje ista, dok u prioritet redovima veličina reda raste i smanjuje. Koristimo ovu priliku da se uvedu dvije konstrukti. Prvo, mi pokazuju da A.append () i A.pop () može se koristiti za rast i smanjiti liste A, dok su len (A) vraća trenutnu duljinu popisa. Drugo, u slučaju ispod granice (i prelijevanje po želji), pokazuju studentima kako podići i uhvatiti izuzetak. Ovi konstrukti ne mogu biti jedinstveni za Python, no Python olakšava eksperiment. 4. Binarna stabla i Huffman kodiranje Huffman algoritam proizvodi prefiks-free, promjenjive duljine kodne riječi na temelju frekvencije svakog lika. Često se koriste slova kodirana pomoću kraćeg niza bitova, a manje često korištenih pomoću dužeg niza 5 bitova. Pohlepni algoritam koristi prioritet red za izdvajanje dva čvora (list ili interni), s najnižim frekvencijama, dodjeljuje novi čvor čija težina je zbroj dva, i umeće novi čvor natrag u red prioriteta. Algoritam završava kad prioritet red uklanja zadnji čvor, koji postaje korijen stabla Huffman. Niz bitova za svako slovo može biti proizveden od strane poprijeko Huffman binarno stablo, gdje je uzimanje lijevoga kraka rezultat u '0',i desna grana rezultat u '1'. Na primjer, pretpostavimo da je naš ulaz skup znakova s pripadajućim frekvencija: 'a': 45% 'b': 13% 'c': 12% 'd': 16% 'e': 9% 'f': 5% Huffman algoritam konstruira stablo usporeĎujući dva elementa s najmanje frekvencije, stvara novi unutarnji čvor čija je frekvencija jednaka njihovom zbroju, u red prioriteta. Rezultat je stablo (sl. 1) koje definira promjenljive duljine koda za svaki znak. Lijevo grane su označene 0, a desno grane su označeni 1, a Huffman kod za znak se jednostavno niz stazu natpiše iz korijena do listova. Npr., kodiranje: 'a': 'b': 'c': 'd': 'e': 'f': 0 1 1 1 1 1 0 0 1 1 1 0 1 0 1 0 1 1 Slika 1 Primjer Huffman stabla Budući da smo stablo. Zahtjevi su: već prioritet red, ono što nam nedostaje je specijalizirano binarno čvor nultog stupnja mora biti u stanju da predstavlja pismo, bude kodirana, a njegova učestalost. unutarnji čvor mora imati dvoje djece, i ona takoĎer mora imati težinu koja je jednaka zbroju za svoju djecu. red prvenstva mora biti u stanju „enqueue“ i „dequeue“ i lišće i unutarnje čvorove i usporediti ih na temelju težine 6 Ako smo za provedbu ovog s tradicionalnim jezikom kao što je C ili Java, trebali bismo naučiti kako definirati strukturu ili klasu s nazivom polja težina; list čvorova, potrebno karakter polje, dok unutarnji čvorovi zahtijevaju leftchild i rightchild polja. Budući da je prioritet red, mora biti u mogućnosti da ih usporedi, to će biti potrebno modificirati prioritet reda i pozvati odgovarajuću metodu usporedbe umjesto koristeći izgraĎen-u odnosu na operatora, i oba lišća i unutarnji čvorovi moraju biti ili u istoj klasi ili biti podrazred u istoj bazi klase koja implementira usporedna metoda. MeĎutim, ni postojeće ispravljanje pogrešaka nema znanja da može automatski ispisati čvorove zajedno kao stablo, i stoga je rutina pisati naredbu print, što zapravo može biti prilično lukav i biti još jedan veliki izvor bugova. Python implementacija može biti učinjeno elegantno, bez potrebe za pisanjem dodatne rutine ili definiranje nove klase ili strukture za stabla čvorova. Predstavljaje binarnih stabla u Pythonu, u duhu sličan Lisp: Leaf čvorovi su zastupljeni kao (frekvencija, karakter) torke: [(45, 'a'), (13, 'b'), (12, 'c'), (16, 'd'), (9, 'e'), (5, 'f')]. Unutarnji čvorovi su zastupljeni kao u nalog 3 torke: (frekvencija, lijevo, desno): Na primjer, u donjem desnom podstablu na slici 1 može se prikazati kao (14, (5, 'f'), (9, 'e')) koja predstavlja unutarnji čvor čija težina je 14%, čija je lijevo dijete (5, 'F'), te čije je pravo dijete (9, 'e'). Stablo je konstruirano funkcionalno s torka stvaranje, bez potrebe da se koristi bilo koji čvor stabla strukture podataka, i nema potrebe da manipuliraju lijevo/desno. Štoviše, to je lako koristiti s postojećim prioritetnim redom strukture podataka, bez izmjena! To je zato što se torke može usporediti na leksikografski poredak koristeći istu usporedbu operatora. Na taj način, unutarnji čvorovi i lišće može biti u odnosu, iako oni kodiraju različite informacije. Razlika izmeĎu njih je da je len () = 2 za leaf (list), i = 3 za unutarnji čvor. 5. Grafikon Algoritmi Graf ima više prikaza, a većina algoritama može pretpostaviti ili susjedstva liste ili matrice susjedstva reprezentacije. Za provedbu graf u tradicionalnom sustavu programskog jezika kao što su C ili Java, prvo bi morao definirati strukture podataka za vrhove, za rubove, a za graf, koji služi kao front-end za stvaranje i brisanje svoje vrhove i rubove. Dizajn takvih podataka struktura lako može dominirati kodiranje vrijeme i nije lako za višekratnu upotrebu, uglavnom zato što ti tipovi podataka moraju biti projektirani kao „kontejneri“. Iako paketi poput LEDA [3] kako bi se poboljšao pokušaj ponovne upotrebe objektno orijentiranog izvorni kod u C++ predloške, oni i dalje zahtijevaju da učenici usvoje cijeli paket prije nego što mogu početi raditi nešto korisno. Kontejneri su često dizajnirani za zaobilaženje problema s jakim, statički tipkanje, ali to zahtijeva reimplementaciju dinamičkog tipa provjere u kraj-korisnik kod. Čak i gori nedostatak da je uporaba C-pokazivača ili Java-reference čini neugodan da biste vidjeli ove predmete. Iako „debugger“ može prikazati te objekte u nekom tekstualnom obliku, to prikazuje previše informacija ili nije izravno od koristi u programu. Python nudi mnoge prednosti kao što je naglašeno od strane strukture grafa podataka. Mi 7 koristimo vrlo kompaktan, rječnik-of-rječnika (DD) provedbu zastupljenosti susjedstvo popis grafa. Uglavnom graf je prikazan kao Python rječnik, čije su tipke niz imena vrhova, a svaki vertex ime preslikanog na svoje susjedstvo popis. Npr., graf prikazan na slici. 2: Sl.2: Primjer usmjereni graf To može biti zastupljena sa sljedećim Python kodom: H = {'A': ['C', 'D'], 'B': ['D', 'A'], 'C': ['D', 'E'], 'D': ['E'], 'E': [] } Gore predstavlja jednostavan, usmjereni, neponderirani graf. Ako ponderirani graf kao što sl. 3 prikazuje, onda možemo jednostavno zamijeniti liste susjedstva vrha s rječnicima koji su na karti susjedna vrha njihove težine: Sl. 3: Primjer grafa ponderirane (težine) L = {'A': {'C':2, 'D':6}, 'B': {'D':8, 'A':3}, 'C': {'D':7, 'E':5}, 'D': {'E':-2}, 'E': {}} Popis vrhova V je jednostavno H.keys () ili L.keys (). Susjedstvo popis H [v] zaneponderirani m grafikone, i L [v]. tipke () za ponderirani grafova. Težina ruba mase w(u, v) je L[u] [v]. Da bi se olakšalo programiranje, možemo završiti pojedinosti provedbe unutar objekta. Grafikon klase: def __init__(self, g): self.g = g def V(self): return self.g.keys() def Adj(self,v): return self.g[v].keys() def w(self,u,v): return self.g[u][v] Možemo stvoriti grafikon objekt sa G = Graf (L). Prednosti s tim pristupom uključuju kompaktni tekstualni oblik i proširivost. Prvo, stvarno ne postoje strukture podataka za projektiranje. Tekstualni prikaz grafa je Python izvršna. Student može upisati u ovoj strukturi interaktivno ili u tekstualnoj datoteci bez korištenja posebnih graf-urednika. Struktura 8 podataka se može ispitati samo tako da upišete svoje ime. To onda može biti cut/lijepiti na drugi prozor Python tumača ili na drugi Python program, bez ikakvih sintaktičkih izmjena. Još važnije, ovaj prikaz je iznimno proširiv. Različiti algoritmi koriste dodatne atribute, ali se mogu dodati prema potrebi. Npr., jedan izvor, najkraći put algoritama ili breadth-first/depthfirst traversals zahtijevaju dodatne atribute, kao što prethodnik upućuje. U Python, algoritam jednostavno mogu dodati atribut prethodnik graf-objekt (kao što G.pred [v]), bez potrebe za definiranje podrazred za svaki algoritam. Ove novo dodano, atributi takoĎer mogu biti pregledani i izravno mijenjati bez potrebe nove rutine. 6. Zaključak i zašto je Python pogodan za učenje izrade algoritama?! Kao algoritam orijentirani jezik, Python omogućava učenje ključnih koncepata u dizajnu algoritama, umjesto da se bori s nama sa osebujnim obilježjima koje imaju konvencionalni programski jezici. Python način obraĎuje vrste podataka, predstavlja savršeno odgovarajućim načinom na koji potiče da sa sami zainteresiramo za njega i onda eksperimentiramo. Jednako je važno naše korištenje struktura podataka za drveće i grafove, koji su kao kompaktna što je više moguće i još ljudskih čitljiv i spremno prihvatio Python prevodioca. Sve u svemu, mislim da je Python jako dobar program za izradu algoritama, budući da nas on dosta često uči vještine rješavanja problema, a ne samo programiranje, kao što su dodatni moduli koje možemo koristiti bilo u matematici ili u fizici, crtanje svakakvih grafova i krivulja i puno toga. 7. Literatura 1. Thomas H. Cormen, Charles E. Leiserson, Ronald L. Rivest, and Clifford Stein, Introduction to Algorithms, Second Edition, McGraw-Hill Press, September 2001. ISBN 0-262-03293-7. 2. Pai H. Chou, ECE 235 Website, University of California, Irvine, Fall 2000. http://e3.uci.edu/00f/15545/ See also Fall 2001 edition at http://e3.uci.edu/01f/15545/. 3. Algorithmic Solutions Software GmbH, homepage, http://www.algorithmic-solutions.com/, 2001. 4. Sara Baase, Allen Van Gelder, Computer Algorithms: Introduction to Design and Analysis, Addison Wesley, 2000. 5. Mark Allen Weiss, Data Structures and Algorithm Analysis in JAVA, Addison-Wesley, 1999. 6. Algorithm Education in Python: http://www.ece.uci.edu/~chou/py02/python.html 7. 20.2.5. Funkcije: http://docs.python.org/release/2.6.6/library/cgi.html?highlight=making%20algorithms 8. The Python Profilers: http://docs.python.org/release/2.6.6/library/profile.html?highlight=making%20algorithms 9. bisect — Array bisection algorithm: http://docs.python.org/release/2.6.6/library/bisect.html?highlight=making%20algorithms 10. decimalni - Decimalni fiksne točke i s pomičnim zarezom aritmetika: http://docs.python.org/release/2.6.6/library/decimal.html?highlight=making%20algorithms 9
© Copyright 2024 Paperzz