Miskolci Egyetem Informatikai Intézet Általános Informatikai Tanszé k Pance Miklós Adatstruktúrák, algoritmusok előadásvázlat Miskolc, 2004 Technikai közreműködő: Imre Mihály, műszaki informatikus hallgató
Scan line Adatok: 31, -42, 59, 26, -53, 58, 97, -93, -103, 84, 80
Scan line metakód Function maxsum(X,N) sm=0; bm=0; For i=1 To N If (sm+X[i] > 0) sm=sm+X[i]; Else sm=0; End bm= maximum (bm,sm); End Return bm End
Max. részletösszeg hatékonyság
Listák Logikailag összetartozó elemek véges, rendezett sorozata. L= : a felsorolt elemeket tartalmazó lista : üres lista L[1], L[2], …, L[n] : a lista 1., 2., …, n. eleme L[i].kulcs A listákhoz, mint minden adatstruktúrához speciális műveleteket értelmezhetünk (Abstract Data Type): init(L), olvas(p, L), beszúr(x, p, L), töröl(p, L), keres(x, L) Megvalósítása szekvenciális listával (tömbbel), vagy láncolt listával, pointerek segítségével.
Szekvenciális lista Statikus adatszerkezet: beszúrás, törlés több lépésben. Keresés a1a1 a2a2 anan FUNCTION kereses1(L,N,E) i=1 WHILE ( i E ) i = i + 1 END IF i > N return Ø ELSE return i END
Szekvenciális lista Keresés javított változata FUNCTION kereses2(L,N,E) L[N+1].kulcs = E i = 1 WHILE ( L[i].kulcs <> E ) i=i+1 END IF i > N return Ø ELSE return i END
Szekvenciális lista Beszúrás: a pozícióra ugrás, majd a hátralévő elemek eltolása előre, végül új elem beírása. A beszúrás hatékonysága átlagosan O(N), ha a lista végére szúrjuk az új elemet akkor O(1). FUNCTION beszur(L,N,E,I) FOR j = N DOWNTO I L[j+1] = L[j] END L[I] = E N = N +1 {ellenőrzés!} END
Szekvenciális lista Törlés : pozícióra ugrás, majd a hátralévő elemek előre tolása: FUNCTION torol(L,N,I) FOR j = I TO N-1 L[j] = L[j+1] END N = N – 1 END A törlés hatékonysága átlagosan O(N) Speciális szekvenciális listák: verem, várakozó sor
Verem (stack) LIFO (Last In First Out) Csak a lista utolsó eleme érhető el, műveletek: - elem a verem tetejére: push - elem a verem tetejéről: pop ← push pop →
Verem műveletek FUNCTION pop_st(L) IF (st_p > 0) RETURN L(st_p) st_p = st_p –1 ELSE error ( ) END FUNCTION push_st(L, X) IF (st_p < st_p_max) st_p = st_p + 1 L(st_p) = X ELSE error ( ) END
Rekurzív kifejezések kiértékelése veremmel Fibonacci-számok: F 1 = F 2 = 1 F i = F i F i - 2 i > 2 Binomiális együttható:
Binomiális együttható kiértékelése 1. FUNCTION binomegy( n, m ) init L[st_p_max] st_p = 0 push_st( L, n ) push_st( L, m ) eredmeny = 0 WHILE ( st_p > 0) m = pop_st(L) n = pop_st(L)
Binomiális együttható kiértékelése 2. IF (m = 0 OR m = n) eredmeny = eredmeny + 1 ELSE push_st(L, n-1) push_st(L, m-1) push_st(L, n-1) push_st(L, m) END RETURN eredmeny END
Postfix kifejezés kiértékelése hagyományos: 4,5 + 4,9 / 2,3 – 2 (infix) postfix: 4,9 2,3 / 4,5 + 2 –
Postfix kifejezés kiértékelése FUNCTION Postfix(S){S:a kifejezés stringje} WHILE( nincsvége(S)) t = olvastag(S) IF (operator_e(t)) IF (t = ’+’) X1 = pop_st(L) X2 = pop_st(L) push_st(L, X1 + X2) END [... további műveletek] ELSE push_st(X,t) END RETURN pop_st(L) END
infix -> postfix átalakítás verem inicializálása beolvassuk a kifejezés elemeit (operátor, operandus, zárójelek) ha az elem operandus: kiírjuk ha az elem operátor: ha ez ’(’ akkor be a verembe ha ez ’)’ akkor a verem tartalmát az első kezdőzárójelig kiírjuk (a zárójelet nem!) különben: kiírjuk a verem tartalmát, míg benne nála >= precedenciájú operátort találunk, utána ezt az operátort betesszük a verembe - ha nincs több elem kiíratjuk a verem tartalmát
infix -> postfix átalakítás példa * (2 + 1) (* | * + | * * + 1 +
Várakozósor (queue) FIFO (First In First Out) Az új elem és az olvasható elem pozíciója különbözik egymástól. Műveletek: elem behelyezése a sor végére: push O(1) elem levétele a sor tetejéről (elejéről): pop O(N)
Várakozósor (queue) A sor eleje mindig csökken, a vége pedig növekszik. Az átmozgatás elkerülésére ciklikus tömbstruktúrát alkalmazunk. Az elemek a helyükön maradnak csak a lista eleje, vége vándorol körbe-körbe. szabad végeeleje push →pop →
Várakozósor (queue) műveletek FUNCTION pop_qu(L) IF (qu_s > 0) r = L[qu_s] IF (qu_s = qu_e) qu_s = 0 ELSE qu_s = qu_s + 1 IF (qu_s > LMAX) qu_s = 1 END RETURN r ELSE error() END FUNCTION push_qu(L, x) r = qu_e qu_e = qu_e + 1 IF (qu_e < LMAX) qu_e = 1 END IF (qu_e = qu_s) qu_e = r error ( ) ELSE L[qu_e] = x IF (qu_s = 0) qu_s = qu_e END
Láncolt lista L[1] L[2] L[3] L[4] L[5]
Keresés láncolt listában FUNCTION kereses_ll (KP, VP, E) n = alloc(){hiba ellenőrzés!} VP → mutato = n n → kulcs = E p = KP WHILE (p → kulcs <> E) p = p → mutato END IF (p = n) return Null ELSE return p END Hatékonysága: O(N)
Beszúrás láncolt listába FUNCTION beszuras_ll(KP, E, I) p = KP FOR j = 1 TO I – 1 p = p → mutato END n = alloc(){hiba ellenőrzés!} n → kulcs = E n → mutato = p → mutato p → mutato = n END Hatékonysága: O(N) Kétszeresen láncolt listánál O(1), ha megadjuk az új elem pozicióját.
Keresés rendezett szekvenciális listában FUNCTION binkereso(L, N, x) IF (L[1].kulcs > x OR L[N].kulcs < x) RETURN nincs_benne END i = 1; j = N WHILE ( i < j ) k = (i + j) / 2 IF (L[k].kulcs = x) RETURN k END IF (L[k].kulcs < x) i = k ELSE j = k END RETURN nincs_benne END
A bináris keresés hatékonysága Az intervallum felezések száma míg az 1 hosszú intervallumot elérjük, avagy hányszor kell az 1-et duplázni, hogy N-et kapjunk? 2 x = N → x = log 2 (N) → O(log(N))
Fibonacci keresés A Fibonacci számok arányában osztja szét az intervallumot, így lesz egy kedvezőbb és egy kedvezőtlenebb eset : bc (best case) = n / 2, wc (worst case) = n
Interpolációs keresés Ha az érték a pozíciótól közel lineárisan függ, akkor igen gyors: O(1). Szélsőséges helyzet: 1, 1, 1, ………….., 1, 2, Például a fenti 1000 elem esetén, x = 2 –t keresve: !!! worst case: O(N), átlagosan O(log(log(N))), vagy igazítsuk az interpoláció típusát az eloszlás jellegéhez.