PROGRAMIRANJE II P06 Linearne strukture podataka doc dr

  • Slides: 32
Download presentation
PROGRAMIRANJE II P-06: Linearne strukture podataka doc. dr Dražen Brđanin 2014/15

PROGRAMIRANJE II P-06: Linearne strukture podataka doc. dr Dražen Brđanin 2014/15

P-06: Linearne strukture podataka n Sadržaj predavanja n Osnovni pojmovi o strukturama podataka n

P-06: Linearne strukture podataka n Sadržaj predavanja n Osnovni pojmovi o strukturama podataka n Osnovne linearne strukture n n sekvencijalne ulančane: n jednostruko povezana lista n dvostruko povezana lista n kružna lista n stek n red

Osnovni pojmovi o strukturama podataka program = algoritam + struktura podataka n n Osnovni

Osnovni pojmovi o strukturama podataka program = algoritam + struktura podataka n n Osnovni gradivni elementi za implementaciju programskih sistema n struktura podataka (eng. data structure): opisuje način organizacije podataka n algoritam: opisuje način obrade podataka Struktura podataka: modeluje objekte i podatke u problemu koji rješavamo n n n elementarni/primitivni tipovi n ugrađeni u programske jezike (reprezentacija i manipulacija elementarnim podacima) složeni/strukturirani n nisu ugrađeni u programske jezike, nego korisnički definisani n složeni podatak je kolekcija elementarnih podataka n osim definicije strukture, programer mora da implementira operacije za manipulaciju složenim podatkom (primjena operacija nad elementarnim podacima) Osnovni načini strukturiranja podataka n homogeno: niz (kolekcija podataka istog tipa) n heterogeno: zapis /slog (zapis je kolekcija logički povezanih podataka različitih tipova)

Klasifikacije n Klasifikacija struktura prema vezama između elemenata: n n linearna: n kolekcija podataka

Klasifikacije n Klasifikacija struktura prema vezama između elemenata: n n linearna: n kolekcija podataka u kojoj svaki element nema više od jednog neposrednog prethodnika niti više od jednog neposrednog sljedbenika n svaki element u kolekciji može biti povezan sa najviše druga dva elementa nelinearna: n kolekcija podataka u kojoj elementi mogu da imaju više neposrednih prethodnika (predaka) i/ili više neposrednih sljedbenika (nasljednika) n svaki element u kolekciji može biti povezan sa više od druga dva elementa Klasifikacija struktura prema mogućnosti promjene veličine: n statička: inicijalno zadata i nepromjenljiva veličina kolekcije tokom životnog vijeka n dinamička: kolekcija može da mijenja veličinu tokom životnog vijeka (dodavanje, izbacivanje, . . . ) Klasifikacija struktura prema mjestu čuvanja: n unutrašnja: kolekcija se nalazi u operativnoj memoriji n spoljašnja: kolekcija se nalazi u sekundardnoj memoriji (datoteka)

Memorijska reprezentacija Sekvencijalna reprezentacija: n n fizički i logički poredak elemenata u kolekciji je

Memorijska reprezentacija Sekvencijalna reprezentacija: n n fizički i logički poredak elemenata u kolekciji je identičan pristup elementima je direktan (moguće je direktno pristupiti svakom elementu kolekcije) uobičajeno se koristi za reprezentaciju linearnih struktura n n n fizički i logički poredak elemenata u kolekciji se razlikuju pristup elementima je indirektan (koristi se pokazivački mehanizam) uobičajeno se koristi za reprezentaciju nelinearnih struktura logički poredak p 0 p 1 p 2 pn-1 ulančani fizički poredak pn-1 . . . n Ulančana reprezentacija: sekvencijalni fizički poredak p 2 p 1 adrese memorij a p 0 pi-1 pi pi+1 fizički poredak: razmještaj elemenata u memoriji logički poredak: prethodnik sljedbenik / predak potomak

Linearne strukture podataka n Linearna struktura podataka: n n n kolekcija podataka u kojoj

Linearne strukture podataka n Linearna struktura podataka: n n n kolekcija podataka u kojoj svaki element nema više od jednog neposrednog prethodnika niti više od jednog neposrednog sljedbenika n svaki element u kolekciji može biti povezan sa najviše druga dva elementa n strukturno svojstvo: JEDNODIMENZIONALNOST Implementacija: n sekvencijalna: niz (statički, dinamički) n ulančana: povezana (ulančana) lista (jednostruko povezana, dvostruko povezana, kružna) Operacije na linearnim strukturama: n n n n dodavanje umetanje brisanje pretraživanje pristup elementu obilazak po poretku sortiranje Cijena (složenost) operacije zavisi od vrste implementacije strukture

Nizovi n Niz = homogeni strukturirani tip n sekvencijalna fizička reprezentacija n n statički

Nizovi n Niz = homogeni strukturirani tip n sekvencijalna fizička reprezentacija n n statički niz n fiksna, unaprijed zadata veličina niza n ako kompajler ne podržava nizove promjenljive dužine, često imamo prostornu neiskorišćenost dinamički niz n veličina niza nije fiksna (može da se mijenja, ali cijena mijenjanja veličine može biti skupa, ako cijeli niz mora da se kopira) n bolja prostorna iskorišćenost, nego kod statičkih elementi su indeksirani (pomjeraj u odnosu na početak) višedimenzioni niz = nizova n n pristup elementima niza n direktan (niz[i]) i efikasan n složenost pristupa O(1) umetanje (npr. održavanje uređenog poretka) n neefikasno (najgori slučaj: svi elementi se pomjeraju jedno mjesto prema kraju) složenost umetanja O(n) brisanje (izbacivanje elementa) n n neefikasno (najgori slučaj: svi se pomjeraju jedno mjesto prema početku) složenost brisanja O(n)

Povezane (ulančane) liste n n n Povezana (ulančana) lista (eng. linked list) = ulančana

Povezane (ulančane) liste n n n Povezana (ulančana) lista (eng. linked list) = ulančana implementacija linearne strukture dinamička struktura n dinamička alokacija n pristup elementima je indirektan (pokazivači) osnovni element: ČVOR (eng. node) n informacioni sadržaj n pokazivač(i) Čvor u jednostruko povezanoj listi info typedef struct node { n Prema načinu povezanosti n jednostruko povezane liste n dvostruko povezane liste Čvor u dvostruko povezanoj listi info typedef struct node { <tip> info; struct node *next; struct node *left; } NODE; Samoreferišuća struktura = struktura koja posjeduje pokazivač na istu strukturu struct node *right; } NODE;

Jednostruko povezana lista info next lista početak liste: n pokazivač na prvi čvor n

Jednostruko povezana lista info next lista početak liste: n pokazivač na prvi čvor n uobičajeni nazivi (head, list) n na početku je lista prazna n pristup elementima jednostruko povezane liste n čvorovi: n n n čvorovi se dinamički alociraju kad treba da se doda novi element čvorovi se dinamički dealociraju kad se element briše n n završetak/rep (eng. tail): n pokazivač u posljednjem čvoru ima vrijednost null indirektan (preko pokazivača) neefikasno (najgori slučaj: da bi se pristupilo posljednjem čvoru, mora da se redom prođe kroz sve čvorove – od glave do repa, jer se adresa sljedećeg čvora nalazi isključivo u prethodnom čvoru) složenost pristupa O(n) umetanje i brisanje (npr. održavanje uređenog poretka) n efikasnije nego kod nizova – nema pomjeranja čvorova – samo se ažuriraju pokazivači

Jednostruko povezana lista Formiranje liste: n na početku je lista prazna . . .

Jednostruko povezana lista Formiranje liste: n na početku je lista prazna . . . lista NODE *lista = NULL; . . . n n dodavanje prvog čvora u listu prolazak kroz listu i dodavanje novog čvora na kraj lista = (NODE *) malloc(sizeof(NODE)); lista->info = ’A’; lista->next = NULL; . . . NODE *tmp = lista; while (tmp->next) tmp = tmp->next; NODE *novi = (NODE *) malloc(sizeof(NODE)); novi->info = 'B'; novi->next = NULL; tmp->next = novi; lista A info next B info next

Jednostruko povezana lista Generalizovana procedura formiranja jednostruko povezane liste (dodavanje na kraj) void formiranje.

Jednostruko povezana lista Generalizovana procedura formiranja jednostruko povezane liste (dodavanje na kraj) void formiranje. Liste(NODE **lista, <tip> info) { NODE *novi = (NODE *) malloc(sizeof(NODE)); novi->info = info; novi->next = NULL; if (*lista == NULL) *lista = novi; else { NODE *tmp = *lista; while (tmp->next) tmp = tmp->next; tmp->next = novi; } } lista = pokazivač na adresu pokazivača koji pokazuje na početak liste novi = pokazivač na novi čvor koji se kreira u dinamičkoj zoni memorije novi čvor se indirektno inicijalizuje (informacioni sadržaj + pointer na sljedeći čvor kojeg nema) ako je lista prazna (*lista == NULL), treba dodati prvi čvor, tj. treba inicijalizovati pokazivač početka liste (indirektna inicijalizacija adresom novog čvora) ako lista nije prazna, treba proći kroz listu do posljednjeg čvora (sve dok trenutni čvor ima sljedbenika) na kraju se pokazivač u posljednjem čvoru setuje da pokazuje novi čvor

Jednostruko povezana lista Ubacivanje čvora iza zadatog čvora info next p info q algoritam

Jednostruko povezana lista Ubacivanje čvora iza zadatog čvora info next p info q algoritam insert_after(p, info) { q = novi. Cvor(info) next(q) = next(p) = q } implementacija void insert_after(NODE *p, <tip> info) { NODE *q = (NODE *) malloc(sizeof(NODE)); q->info = info; q->next = p->next; p->next = q; }

Jednostruko povezana lista Ubacivanje čvora ispred zadatog čvora info next y info next z

Jednostruko povezana lista Ubacivanje čvora ispred zadatog čvora info next y info next z info next x p z p y x q algoritam insert_before(p, info) { q = novi. Cvor(info(p)) next(q) = next(p) = q info(p) = info } implementacija void insert_before(NODE *p, <tip> info) { NODE *q = (NODE *) malloc(sizeof(NODE)); q->info = p->info; q->next = p->next; p->info = info; p->next = q; }

Jednostruko povezana lista Brisanje čvora iza zadatog čvora info next x info next y

Jednostruko povezana lista Brisanje čvora iza zadatog čvora info next x info next y p z q info next x z p algoritam delete_after(p) { q = next(p) = next(q) delete(q) } implementacija int delete_after(NODE *p) { NODE *q = p->next; if (q) { p->next = q->next; free(q); return 1; } return 0; }

Jednostruko povezana lista Brisanje zadatog čvora info next x p info next y q

Jednostruko povezana lista Brisanje zadatog čvora info next x p info next y q y p implementacija algoritam delete(p) { q = next(p) info(p) = info(q) next(p) = next(q) delete(q) } int delete_node(NODE *p) { NODE *q = p->next; if (q) { p->next = q->next; p->info = q->info; free(q); return 1; } free(p); return 0; }

Jednostruko povezana lista Pretraživanje neuređene liste Pretraživanje uređene liste Informacioni sadržaj u čvorovima nije

Jednostruko povezana lista Pretraživanje neuređene liste Pretraživanje uređene liste Informacioni sadržaj u čvorovima nije uređen, pa je neophodno pretraživanje cjelokupne liste Informacioni sadržaj u čvorovima je uređen, pa nije neophodno pretraživanje cjelokupne liste Lista se pretražuje sve dok pokazivač na tekući nije NULL i dok je informacioni sadržaj (ključ) različit od ključa pretrage Lista se pretražuje sve dok pokazivač na tekući nije NULL i dok je informacioni sadržaj manji od ključa pretrage Po izlasku iz petlje, ili je dostignut kraj ili je pronađen traženi čvor – dovoljno je vratiti vrijednost koju pokazuje pokazivač trenutne pozicije u listi Po izlasku iz petlje: § ako je dostignut kraj ili ako je informacioni sadržaj veći od ključa pretrage – nije pronađen traženi čvor pa treba vratiti NULL § Inače je pronađen traženi čvor i treba vrijednost pokazivača trenutne pozicije u listi NODE *search(NODE *lista, <tip> info) { while (lista && lista->info != info) lista = lista->next; return lista; } NODE *search_sort(NODE *lista, <tip> info) { while (lista && lista->info < info) lista = lista->next; if (!lista || lista->info > info) return NULL; return lista; }

Jednostruko povezana kružna lista n pokazivač u posljednjem čvoru pokazuje na prvi čvor, što

Jednostruko povezana kružna lista n pokazivač u posljednjem čvoru pokazuje na prvi čvor, što omogućava kružno kretanje kroz listu info next Kružna lista sa zaglavljem na početku liste se nalazi poseban čvor – zaglavlje n zaglavlje se uglavnom koristi da označi prvi čvor u listi (ako se spoljašnji pokazivač pomjera, npr. ako spoljašnji pokazivač pokazuje na posljednji čvor) n info next lista n info next H spoljašnji pokazivač na listu ponekad pokazuje na posljednji čvor (a ne na prvi) n lista zaglavlje se nikad ne briše, pa lista nikad nije prazna info next lista H

Dvostruko povezana lista left info right glav a rep right(left(p)) = p = left(right(p))

Dvostruko povezana lista left info right glav a rep right(left(p)) = p = left(right(p)) početak i kraj liste: n uobičajeno postoje dva spoljašnja pokazivača na listu: n glava / head (na početak liste) n rep / tail (na kraj liste) formiranje liste: n na početku je lista prazna NODE *glava = NULL, *rep = NULL; n dodavanje prvog čvora u listu glava = rep = (NODE *) malloc(sizeof(NODE)); glava->info = info; glava->left = glava->right = NULL; čvorovi: n čvorovi se dinamički alociraju/dealociraju n svaki čvor ima dva pokazivača: n n dodavanje novih čvorova n left (na prethodni čvor) n n right (na sljedeći čvor) n dvostruki pokazivači omogućavaju lakše kretanje kroz listu (od početka prema kraju i od kraja prema početku) n n n add_front(&glava, info) add_back(&rep, info) insert_after(&cvor, info) insert_before(&cvor, info) brisanje čvorova n delete(cvor)

Dvostruko povezana lista Dodavanje čvora na početak left info right glav a void add_front(NODE

Dvostruko povezana lista Dodavanje čvora na početak left info right glav a void add_front(NODE **glava, int info) { NODE *q = (NODE *) malloc(sizeof(NODE)); q->info = info; if (*glava == NULL) { q->left = q->right = NULL; *glava = q; } else { q->right = *glava; q->left = NULL; (*glava)->left = q; *glava = q; } info left info right glav a info q left right }

Dvostruko povezana lista Dodavanje čvora na kraj void add_back(NODE **rep, int info) { NODE

Dvostruko povezana lista Dodavanje čvora na kraj void add_back(NODE **rep, int info) { NODE *q = (NODE *) malloc(sizeof(NODE)); q->info = info; left info right rep if (*rep == NULL) { q->left = q->right = NULL; *rep = q; } else { q->left = *rep; q->right = NULL; (*rep)->right = q; *rep = q; } info left info right info left rep right }

Dvostruko povezana lista Ubacivanje čvora iza zadatog čvora left info right r p int

Dvostruko povezana lista Ubacivanje čvora iza zadatog čvora left info right r p int insert_after(NODE *p, int info) { NODE *r = p->right; if (r == NULL) return 0; info NODE *q = (NODE *) malloc(sizeof(NODE)); q->info = info; q->right = r; q->left = p; r left info right return 1; } p info q left right r->left = q; p->right = q;

Dvostruko povezana lista Ubacivanje čvora ispred zadatog čvora left info right r p int

Dvostruko povezana lista Ubacivanje čvora ispred zadatog čvora left info right r p int insert_before(NODE *r, int info) { NODE *p = r->left; if (p == NULL) return 0; info NODE *q = (NODE *) malloc(sizeof(NODE)); q->info = info; q->right = r; q->left = p; r left info right return 1; } p info q left right r->left = q; p->right = q;

Dvostruko povezana lista Brisanje zadatog čvora left info right p left info right q

Dvostruko povezana lista Brisanje zadatog čvora left info right p left info right q left info right p left info right r int delete_node(NODE *q) { if (q->left && q->right) { NODE *p = q->left; NODE *r = q->right; p->right = r; r->left = p; free(q); return 1; } return 0; }

Stek n STEK = linearna struktura sa LIFO disciplinom pristupa n LIFO = Last

Stek n STEK = linearna struktura sa LIFO disciplinom pristupa n LIFO = Last In – First Out (Posljednji unutra – prvi napolje) n jedan pristupni kraj = VRH STEKA (Top of Stack – To. S) n operacije sa stekom: n push – stavljanje na stek n pop – skidanje sa steka push(A) push(B) push(C) C B A stanje steka nakon stavljanja podatka A To S A stanje steka nakon stavljanja podatka B To S B pop() To S B A A stanje steka nakon stavljanja C i D stanje steka nakon skidanja C To S A stanje steka nakon skidanja B To S

Stek n Sekvencijalna reprezentacija steka n implementacija pomoću niza n kapacitet steka je ograničen:

Stek n Sekvencijalna reprezentacija steka n implementacija pomoću niza n kapacitet steka je ograničen: niz[0] – niz[n-1] n sadržaj steka: niz[0] – niz[To. S] n kontrola pristupa: n na stek ne može da se doda novi podatak ako je stek pun (To. S=n-1) n sa steka ne može da se skine podatak ako je stek prazan (To. S=-1) push(A) push(B) pop() niz[3] niz[3] niz[2] niz[2] niz[1] B niz[1] niz[0] A prazan stek To. S =-1 A stanje steka nakon stavljanja podatka A To. S=0 To S stanje steka nakon stavljanja podatka B To. S=1 To S niz[0] A stanje steka nakon skidanja podatka B To. S=0 To S niz[0] prazan stek nakon skidanja podatka A To. S=-1

Stek Operacije na sekvencijalnom steku typedef struct stek { <tip> niz[MAX]; int tos; }

Stek Operacije na sekvencijalnom steku typedef struct stek { <tip> niz[MAX]; int tos; } STEK; /* provjera da li je stek pun */ /* provjera da li je stek prazan */ int is. Full(STEK *s) { return s->tos == MAX-1; } int is. Empty(STEK *s) { return s->tos == -1; } /* stavljanje na stek */ /* skidanje sa steka */ int push(STEK *s, <tip> info) { if (is. Full(s)) return 0; int pop(STEK *s, <tip> *info) { if (is. Empty(s)) return 0; } s->niz[++tos] = info; *info = s->niz[tos--]; return 1; }

Stek n Ulančana reprezentacija steka n implementacija pomoću (jednostruko) povezane liste n kontrola pristupa:

Stek n Ulančana reprezentacija steka n implementacija pomoću (jednostruko) povezane liste n kontrola pristupa: n sa steka ne može da se skine podatak ako je stek prazan (To. S=NULL) push(A) tos info prazan stek tos = NULL next A push(B) tos info B pop() tos A tos next info pop() prazan stek tos = NULL A next /* inicijalizacija */ /* stavljanje na stek */ /* skidanje sa steka */ NODE *tos = NULL; push(&tos, info); pop(&tos, &info); typedef struct node { <tip> info; struct node *next; } NODE;

Stek Operacije na ulančanom steku tos /* stavljanje na stek */ /* skidanje sa

Stek Operacije na ulančanom steku tos /* stavljanje na stek */ /* skidanje sa steka */ void push(NODE **tos, <tip> info) int pop(NODE **tos, <tip> *info) { { q NODE *q=(NODE*) malloc(sizeof(NODE)); } q->info = info; info if (*tos == NULL) { q->next = NULL; *tos = q; return; } next q->next = *tos; info *tos = q; next if (*tos == NULL) return 0; tos NODE *q = *tos; A *info = q->info; *tos = q->next; free(q); return 1; q info tos B } A next typedef struct node { <tip> info; struct node *next; } NODE;

Red n RED (Queue) = linearna struktura sa FIFO disciplinom pristupa n FIFO =

Red n RED (Queue) = linearna struktura sa FIFO disciplinom pristupa n FIFO = First In – First Out (Prvi unutra – prvi napolje) n dva pristupna kraja: čelo (front) i začelje (rear/back) n operacije sa stekom: n insert – dodavanje na začelje (na kraj reda) n delete – brisanje iz reda (brisanje na čelu) C Primjer početnog stanja B rear C Uzimanje podatka iz reda Dodavanje podatka u red front D rear C A B rear D A front B front

Red n Sekvencijalna reprezentacija reda n implementacija pomoću niza n kapacitet reda je veoma

Red n Sekvencijalna reprezentacija reda n implementacija pomoću niza n kapacitet reda je veoma ograničen: niz[0] – niz[n-1] n kontrola pristupa: n novi podatak ne može da se doda na kraj reda, ako začelje pokazuje izvan niza (rear=n) n iz reda podatak može da se uzme ako je 0<=front<n q[0] q[1] q[2] q[3] A q[0] q[1] q[2] q[3] A A q[0] q[1] q[2] q[3] F=0 B R=2 B F=1 R=4 q[0] q[1] q[2] q[3] C F=2 C q[0] q[1] q[2] q[3] D F=3 R=4 D B R=3 A q[0] q[1] q[2] q[3] B C D F=0 R=1 A C F=0 F=-1 R=0 B C D R=4 D q[0] q[1] q[2] q[3] F=R=4 Prosta sekvencijalna reprezentacija omogućava samo red za jednokratnu upotrebu!!!

Red n Kružni (cirkularni) bafer = kružna sekvencijalna reprezentacija reda n elementi niz[0] i

Red n Kružni (cirkularni) bafer = kružna sekvencijalna reprezentacija reda n elementi niz[0] i niz[n-1] su logički susjedne lokacije R=3 q[3] q[4] q[3] q[5] q[2] D q[2] q[1] q[6] q[0] q[1] q[7] Bafer PUN, ali na začelje dodat novi podatak, a čelo pomjereno za jedno mjesto (česta realizacija u realnom vremenu da se ne gube posljednji značajni podaci). Alternativa: u red se ne q[5] C B q[6] A q[4] D q[2] q[0] F=R=0 bafer PRAZAN q[3] q[4] q[1] E F C B G q[5] R=6 q[6] F=1 q[0] q[7] F=0 q[3] D F=2 q[2] q[1] R=1 q[4] E F C J I q[0] G H q[7] q[3] q[5] q[6] q[4] D q[2] q[1] F C B I F=1 bafer PUN E q[0] R=0 G H q[7] q[5] q[6]

Red Operacije na cirkularnom sekvencijalnom redu typedef struct red { <tip> niz[MAX]; int f,

Red Operacije na cirkularnom sekvencijalnom redu typedef struct red { <tip> niz[MAX]; int f, r; } RED; /* provjera da li je red pun */ int is. Full(RED *buf) { return (buf->r+1) % MAX == buf->f; } /* provjera da li je red prazan */ int is. Empty(RED *buf) { return buf->front == buf->rear; } /* dodavanje u red sa prepisivanjem */ int insert(RED *buf, <tip> info) { if (is. Full(buf)) buf->f = (buf->f + 1) % MAX; } /* brisanje iz reda */ int delete(RED *buf, <tip> *info) { if (is. Empty(buf)) return 0; buf->r = (buf->r + 1) % MAX; buf->f = (buf->f + 1) % MAX; buf->niz[buf->r] = info; *info = buf->niz[buf->f]; return 1; }