Upload
hanhu
View
223
Download
3
Embed Size (px)
Citation preview
PROGRAMIRANJE 2
VEŽBE
JEDNOSTRUKO I DVOSTRUKO
POVEZANE LISTE. STEKOVI.
Staša Vujičić Stanković
JEDNOSTRUKO POVEZANE LISTE. REKURZIVNO
#include <stdio.h>
#include <stdlib.h>
typedef struct cvor{
int vrednost;
struct cvor * sledeci;
} Cvor;
2
void prikazi_elemente(Cvor *glava){
if(glava == NULL)
return;
printf(" %d",glava->vrednost);
prikazi_elemente(glava->sledeci);
}
void prikazi_listu(Cvor* glava){
putchar('[');
prikazi_elemente(glava);
printf("]\n");
} 3
Cvor* oslobodi_listu(Cvor* glava){
if(glava == NULL)
return NULL;
oslobodi_listu(glava->sledeci);
free(glava);
return NULL;
}
4
Cvor* napravi_cvor(int x){
Cvor* novi = (Cvor *)malloc(sizeof(Cvor));
if(novi == NULL)
return NULL;
novi->vrednost = x;
novi->sledeci = NULL;
return novi;
} 5
Cvor* dodaj_na_pocetak(Cvor* glava, int x){
Cvor *novi = napravi_cvor(x);
if(novi == NULL){
fprintf(stderr,"malloc() greska u funkciji
napravi_cvor()!\n");
glava = oslobodi_listu(glava);
exit(EXIT_FAILURE);
}
/* uvezujemo ga na pocetak */
novi->sledeci = glava;
return novi;
}
6
Cvor* dodaj_na_kraj(Cvor* glava, int x){
if (glava == NULL){
Cvor* novi = napravi_cvor(x);
if(novi == NULL){
fprintf(stderr,"malloc() greska u funkciji
napravi_cvor()!\n");
glava = oslobodi_listu(glava);
exit(EXIT_FAILURE);
}
return novi;
}
glava->sledeci = dodaj_na_kraj(glava->sledeci,x);
return glava;
}
7
Cvor* dodaj_sortirano(Cvor* glava, int x){
if(glava == NULL || glava->vrednost >= x )
return dodaj_na_pocetak(glava, x);
glava->sledeci = dodaj_sortirano(glava->sledeci, x);
return glava;
}
8
Cvor* pretrazi_listu(Cvor* glava, int x){
if(glava->vrednost == x)
return glava;
return pretrazi_listu(glava->sledeci, x);
}
9
Cvor* obrisi_element(Cvor* glava, int x){
if(glava == NULL)
return NULL;
glava->sledeci = obrisi_element(glava->sledeci,x);
if(glava->vrednost == x ){
Cvor* tekuci = glava->sledeci;
free(glava);
glava = tekuci;
}
return glava;
}… test program …
10
JEDNOSTRUKO POVEZANE LISTE. ITERATIVNO
Prilikom promene liste (dodavanje novog elementa,
brisanje elementa, premeštanje elemenata, itd.)
postoji mogućnost da glava liste bude promenjena,
tj.
da to postane neki drugi čvor (sa drugom adresom).
U tom slučaju se pokazivač na glavu liste mora
ažurirati.
11
Kada promenu liste obavljamo u posebnoj funkciji
(kao što je bio slučaj u prethodnom primeru, gde
smo za dodavanje i brisanje imali posebne funkcije)
onda je potrebno da se
pozivajućoj funkciji vrati informacija o promeni
adrese glave,
kako bi pozivajuća funkcija mogla da ažurira svoju
pokazivačku promenljivu.
12
Ovo može da se uradi na dva načina:
1. Pozvana funkcija koja vrši promenu na listi
vraća kao povratnu vrednost adresu glave
nakon promene.
Ova adresa može biti ista kao i pre promene
(ako glava nije dirana) a može se i razlikovati.
U svakom slučaju, ta adresa treba da se dodeli
pokazivačkoj promenljivoj koja čuva adresu
glave u pozivajućoj funkciji.
Zbog toga se funkcija za promenu liste uvek
poziva na sledeći način:
pok = funkcija_za_promenu(pok, ...);
tj. promenljivoj čija se vrednost predaje kao
adresa glave u pozivu mora se dodeliti povratna
vrednost funkcije, za slučaj da je adresa glave
interno promenjena.
13
2. Pozvana funkcija koja vrši promenu na listi prihvata
kao argument pokazivač na pokazivačku
promenljivu koja u pozivajućoj funkciji čuva adresu
glave i koju eventalno treba ažurirati.
Sada pozvana funkcija može interno da preko
dobijenog pokazivača promeni promenljivu
pozivajuće funkcije direktno. Npr:
funkcija_za_promenu(&pok, ...);
Funkcija koja se poziva je po pravilu void tipa.
Prednost drugog metoda je jednostavnije pozivanje,
dok je prednost prvog metoda jednostavnija sintaksa
unutar pozvane funkcije. 14
JEDNOSTRUKO POVEZANE LISTE. ITERATIVNO
/* Struktura koja predstavlja cvor liste */
typedef struct cvor {
int vrednost; /* podatak koji cvor sadrzi */
struct cvor *sledeci; /* pokazivac na sledeci cvor */
} Cvor;
15
/* Pomocna funkcija koja kreira cvor.
Funkcija vrednost novog cvora inicijalizuje na broj,
dok pokazivac na sledeci cvor u novom cvoru
postavlja na NULL.
Funkcija ispisuje poruku o gresci i prekida program u
slucaju da malloc() funkcija ne uspe da alocira
prostor.
Funkcija vraca pokazivac na novokreirani cvor */
Cvor *napravi_cvor(int broj)
{
Cvor *novi = (Cvor *) malloc(sizeof(Cvor));
if(novi == NULL) return NULL;
novi->vrednost = broj;
novi->sledeci = NULL;
return novi;
}
16
/* Funkcija oslobadja dinamicku memoriju zauzetu
od strane liste. */
void oslobodi_listu(Cvor ** glava)
{
Cvor *pomocni;
while (*glava != NULL) {
/* moramo najpre zapamtiti adresu sledeceg
elementa, a tek onda osloboditi glavu */
pomocni = (*glava)->sledeci;
free(*glava);
*glava = pomocni;
}
} 17
/* Funkcija dodaje novi cvor na pocetak liste. Funkcija kreira
novi cvor koriscenjem funkcije napravi_cvor(). */
void dodaj_na_pocetak_liste(Cvor ** glava, int broj)
{
Cvor *novi = napravi_cvor(broj);
/* provera greske prilikom alokacije */
if(novi == NULL){
fprintf(stderr,"malloc() greska u funkciji napravi_cvor()!\n");
oslobodi_listu(glava);
exit(EXIT_FAILURE);
}
/* uvezujemo novi cvor na pocetak */
novi->sledeci = *glava;
*glava = novi;
}
18
/* Funkcija dodaje novi cvor na kraj liste. Funkcija
kreira novi cvor koriscenjem funkcije napravi_cvor(). */
void dodaj_na_kraj_liste(Cvor ** glava, int broj)
{
Cvor *novi = napravi_cvor(broj);
Cvor *tekuci = *glava;
/* provera greske prilikom alokacije memorije */
if(novi == NULL){
fprintf(stderr,"malloc() greska u funkciji
napravi_cvor()!\n");
oslobodi_listu(glava);
exit(EXIT_FAILURE);
}
19
/* slucaj prazne liste. U tom slucaju je glava nove liste
upravo novi cvor. */
if (*glava == NULL) {
*glava = novi;
return;
}
/* Ako lista nije prazna, tada se krecemo duz liste sve
dok ne dodjemo do poslednjeg cvora (tj. do cvora ciji
pokazivac na sledeci pokazuje na NULL) */
while (tekuci->sledeci != NULL)
tekuci = tekuci->sledeci;
/* Dodajemo novi element na kraj preusmeravanjem
pokazivaca */
tekuci->sledeci = novi;
}
20
/* Funkcija dodaje novi element u sortiranu listu tako da i
nova lista ostane sortirana. Funkcija kreira novi cvor
koriscenjem funkcije napravi_cvor(). */
void dodaj_sortirano(Cvor ** glava, int broj)
{
Cvor *novi = napravi_cvor(broj);
Cvor *tekuci = *glava;
/* Proveravamo da li je doslo do greske prilikom alokacije
memorije */
if(novi == NULL){
fprintf(stderr,"malloc() greska u funkciji napravi_cvor()!\n");
oslobodi_listu(glava);
exit(EXIT_FAILURE);
}
21
/* u slucaju prazne liste glava nove liste je upravo
novi element */
if (*glava == NULL) {
*glava = novi;
return;
}
/* ako je novi element manji ili jednak od glave,
tada novi element mora da bude nova glava */
if ((*glava)->vrednost >= novi->vrednost) {
novi->sledeci = *glava;
*glava = novi;
return;
} 22
/* u slucaju da je glava manja od novog elementa, tada
se krecemo kroz listu sve dok se ne dodje do elementa
ciji je sledeci element veci ili jednak od novog elementa,
ili dok se ne dodje do poslednjeg elementa. */
while (tekuci->sledeci != NULL
&& tekuci->sledeci->vrednost < novi->vrednost)
tekuci = tekuci->sledeci;
/* U svakom slucaju novi element dodajemo IZA tekuceg
elementa */
novi->sledeci = tekuci->sledeci;
tekuci->sledeci = novi;
} 23
/* Funkcija trazi u listi element cija je vrednost
jednaka datom broju.
Funkcija vraca pokazivac na cvor liste u kome je
sadrzan trazeni broj ili NULL u slucaju da takav
element ne postoji u listi */
Cvor *pretrazi_listu(Cvor * glava, int broj)
{
for (; glava != NULL; glava = glava->sledeci)
if (glava->vrednost == broj)
return glava;
return NULL;
} 24
/* Funkcija brise iz liste sve cvorove koji sadrze
dati broj.
Funkcija vraca pokazivac na glavu liste (koji moze
biti promenjen u slucaju da se obrise stara glava) */
void obrisi_element(Cvor ** glava, int broj)
{
Cvor *tekuci;
Cvor *pomocni;
25
/* Brisemo sa pocetka liste sve eventualne cvorove koji su
jednaki datom broju, i azuriramo pokazivac na glavu */
while (*glava != NULL && (*glava)->vrednost == broj) {
pomocni = (*glava)->sledeci;
free(*glava);
*glava = pomocni;
}
/* Ako je nakon toga lista ostala prazna prekidamo
funkciju */
if (*glava == NULL)
return;
26
/* Od ovog trenutka se u svakom koraku nalazimo na
tekucem cvoru koji je razlicit od trazenog broja (kao i svi
levo od njega).
Poredimo vrednost sledeceg cvora (ako postoji) sa
trazenim brojem i brisemo ga ako je jednak, a prelazimo
na sledeci cvor ako je razlicit.
Ovaj postupak ponavljamo dok ne dodjemo do poslednjeg
cvora. */
tekuci = *glava;
while (tekuci->sledeci != NULL)
if (tekuci->sledeci->vrednost == broj) {
pomocni = tekuci->sledeci;
tekuci->sledeci = tekuci->sledeci->sledeci;
free(pomocni);
} else
tekuci = tekuci->sledeci;
return;}
27
/* Funkcija prikazuje elemente liste pocev
od glave ka kraju liste */
void ispisi_listu(Cvor * glava)
{
putchar('[');
for (; glava != NULL; glava = glava->sledeci)
printf("%d ", glava->vrednost);
putchar(']');
putchar('\n');
} ...test program ...
28
DVOSTRUKO POVEZANE LISTE.
#include <stdio.h>
#include <stdlib.h>
/* struktura kojom je predstavljen svaki element
liste */
typedef struct cvor{
int vrednost;
struct cvor *sledeci;
struct cvor *prethodni;
} Cvor; 29
/* Funkcija koja pravi nov cvor, inicijalizuje polje
vrednost u strukturi na broj i vraca pokazivac na
nov cvor */
Cvor* napravi_cvor(int broj)
{
Cvor* novi = (Cvor*)malloc(sizeof(Cvor));
if(novi == NULL)
return NULL;
/* inicijalizacija polja u novom cvoru */
novi->vrednost = broj;
novi->sledeci = NULL;
novi->prethodni = NULL;
return novi;
}
30
/* Funkcija oslobadja prostor koji smo alocirali za
elemente liste. */
Cvor* oslobodi_listu(Cvor* glava)
{
Cvor* pomocni;
while( glava != NULL )
{ pomocni = glava->sledeci;
free(glava);
glava = pomocni;
}
return NULL;
} 31
/* Fukcija kreira nov cvor sa poljem vrednost
postavljenim na broj i stavlja ga na pocetak liste. Nov
cvor je nova glava liste i vracamo pokazivac na nov
cvor. */
Cvor* dodaj_na_pocetak_liste(Cvor* glava, int
broj)
{
Cvor* novi = napravi_cvor(broj);
/* provera da li je doslo do greske prilikom alokacije */
if(novi == NULL)
{ fprintf(stderr, "malloc() greska u funkciji
napravi_cvor(%d)!\n",broj);
glava = oslobodi_listu(glava);
exit(EXIT_FAILURE);
}
32
/* sledeci od novog cvora je glava stare liste */
novi->sledeci = glava;
/* ako stara lista nije bila prazna, onda njena glava
nije NULL i moramo postaviti da prethodni od
glave bude nov cvor. */
if(glava != NULL)
glava->prethodni=novi;
return novi;
} 33
/* Funkcija nov cvor dodaje na kraj liste. */
Cvor* dodaj_na_kraj_liste( Cvor* glava, int broj)
{
Cvor* novi = napravi_cvor(broj);
Cvor* tekuci =glava;
/* provera da li je doslo do greske prilikom alokacije */
if(novi == NULL)
{ fprintf(stderr, "malloc() greska u funkciji
napravi_cvor(%d)!\n",broj);
glava = oslobodi_listu(glava);
exit(EXIT_FAILURE);
} 34
/* ako je lista u koju dodajemo prazna. Nov cvor je
jedini cvor u novoj listi i time je i glava nove liste.
Pa vracamo novi. */
if(glava == NULL)
return novi;
/* tekuci pokazivac pomeramo da na sledeci
element liste dok ne dodjemo do poslednjeg
elementa u listi (tj. elementa koji ima NULL
pokazivac na polju sledeci). */
while( tekuci->sledeci != NULL)
tekuci = tekuci->sledeci;
35
/* tada uvezujemo nov cvor na kraj, tako sto mu
azuriramo pokazivac na prethodni da pokazuje na
tekuci. A sledeci od tekuceg treba da bude nov cvor. */
tekuci->sledeci = novi;
novi->prethodni = tekuci;
return glava;
}
36
/* Fukcija dodaje u listu nov cvor na odgovarajuce
mesto. Tj. Funkcija pronalazi odgovarajuci cvor u listi
iza kod treba uvezati nov cvor. */
Cvor* dodaj_sortirano(Cvor* glava, int broj)
{
Cvor* novi = napravi_cvor(broj);
Cvor* tekuci = glava;
/* provera da li je doslo do greske prilikom alokacije */
if(novi == NULL)
{ fprintf(stderr, "malloc() greska u funkciji
napravi_cvor(%d)!\n",broj);
glava = oslobodi_listu(glava);
exit(EXIT_FAILURE);
}
37
/* ako je lista u koju ubacujemo nov cvor prazna,
nov cvor upravo i jedini cvor u novoj listi,
pa je i glava nove liste.*/
if( glava == NULL)
return novi;
/* Lista nije prazna*/
/* Ukoliko je vrednost glave liste veca od nove
vrednosti onda nov cvor treba da uvezati pre glave,
tj. staviti na pocetak liste. */
if( glava->vrednost >= broj)
{
novi->sledeci = glava;
glava->prethodni = novi;
return novi;
}
38
/* Pomeramo pokazivac tekuci da pokazuje na svoj
sledeci sve dok su vrednosti njegovog sledeceg manji od
nove vrednosti ili dok ne dodjemo do poslednjeg
elementa u listi.*/
while(tekuci->sledeci != NULL && tekuci->sledeci-
>vrednost < novi->vrednost)
tekuci = tekuci->sledeci;
novi->sledeci = tekuci->sledeci;
novi->prethodni = tekuci;
39
/* ako smo iz prethodne petlje izasli zato sto je
tekuci pokazivac na poslednji element u listi */
if( tekuci->sledeci != NULL )
tekuci->sledeci->prethodni = novi;
tekuci->sledeci = novi;
/* vracamo pokazivac na glavu cele liste*/
return glava;
}
40
/* Fukcija prolazi kroz listu od glave do kraja liste
u potrazi za cvorom koji na polju vrednost ima
trazenu vrednost broj. */
Cvor* pretrazi_listu(Cvor* glava, int broj)
{
for( ; glava!=NULL; glava = glava->sledeci)
if( glava->vrednost == broj)
/* nasli smo cvor sa trazenom vrednoscu i vracamo
pokazivac na njega. */
return glava;
/* dosli smo do kraja liste i nismo nasli trazeni
element. pa vracamo NULL. */
return NULL;
}
41
/* Funckija brise u listi na koju pokazuje pokazivac
glava bas onaj cvor na koji pokazuje pokazivac
tekuci. Obratiti paznju da je kod dvostruke liste
ovo mnogo lakse uraditi jer cvor tekuci sadrzi
pokazivace na svog sledbenika i prethodnika u listi.
Pre nego sto fizicki obrisemo tekuci obavezno
moramo azurirati sve pokazivace sledbenika i
prethodnika. */
Cvor* obrisi_tekuci(Cvor* glava, Cvor*
tekuci)
{
/* ako je tekuci NULL pokazivac nema sta da se
brise. */
if(tekuci == NULL)
return glava; 42
/* Ako postoji prethodnik od tekuceg onda se
postavlja da njegov sledeci bude sledeci od tekuceg */
if( tekuci->prethodni != NULL)
tekuci->prethodni->sledeci = tekuci->sledeci;
/* Ako postoji sledbenik tekuceg (cvora koji bismo
obrisali) onda njegov prethodnik treba da bude
prethodnik od tekuceg */
if(tekuci->sledeci != NULL)
tekuci->sledeci->prethodni =
tekuci->prethodni;
43
/* ako je glava element koji se brise. Glava nove
liste postaje sledbenik od glave. */
if( tekuci == glava)
glava = tekuci->sledeci;
/* oslobadjamo dinamicki alociran prostor za cvor
tekuci*/
free(tekuci);
return glava;
} 44
/* Brisemo element u listi cije polje vrednost je
trazeni broj */
Cvor* obrisi_element(Cvor* glava, int broj)
{
Cvor* tekuci = glava;
Cvor* pomocni;
while((tekuci = pretrazi_listu(glava,broj)) != NULL)
{ pomocni = tekuci->sledeci;
glava = obrisi_tekuci(glava, tekuci);
tekuci = pomocni;
}
return glava;
} 45
/* Funkcija ispisuje vrednosti iz liste. */
void ispisi_listu(Cvor* glava)
{
putchar('[');
for( ;glava != NULL; glava = glava->sledeci)
printf("%d ",glava->vrednost);
putchar(']');
putchar('\n');
}
46
/* Funkcija prikazuje elemente liste pocev od kraja
ka glavi liste. Kod dvostruko povezane to je jako
jednostavno jer svaki cvor ima pokazivac na
prethodni element u listi. */
void ispisi_listu_u_nazad(Cvor* glava)
{
putchar('[');
if(glava == NULL )
{ printf("]\n");
return;
}
47
/* pomeramo pokazivac glava sve dok ne pokazuje
na poslednji element u listi*/
while(glava->sledeci != NULL)
glava = glava->sledeci;
/* ispisujemo element po element liste unazad.
Pristupamo elementu liste i nakon ispisa
pomeramo pokazivac glava da pokazuje na
prethodnika */
for( ;glava != NULL; glava = glava->prethodni)
printf("%d ", glava->vrednost);
printf("]\n");
} ... test program ... 48
STEKOVI
Stek (eng. stack) je struktura podataka nad
kojom su definisane sledeće operacije:
1. Dodavanje elementa –
kažemo da je element potisnut na vrh steka
(eng. push() operacija)
2. Uklanjanje elementa koji je poslednji dodat –
kažemo da je element skinut sa vrha steka
(eng. pop() operacija)
3. Očitavanje vrednosti elementa koji je poslednji
dodat
(eng. top() operacija) 49
Stek spada u LIFO strukture
(eng. Last In First Out).
Može se implementirati na više načina.
Najjednostavniji način je da se definiše kao niz.
Međutim, tada je ograničen maksimalan broj elemenata
na steku dimenzijom niza.
Zbog toga se obično koriste liste za implementaciju steka,
gde se push() operacija svodi na dodavanje na početak, a
pop() operacija se svodi na uklanjanje glave liste.
Obe operacije se izvode u konstantnom vremenu.
50
/* Program proverava da li su etikete u datom
HTML fajlu dobro uparene */
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <ctype.h>
#define MAX 100
#define OTVORENA 1
#define ZATVORENA 2
#define VAN_ETIKETE 0
#define PROCITANO_MANJE 1
#define U_ETIKETI 2 51
/* Struktura koja predstavlja cvor liste */
typedef struct cvor {
char etiketa[MAX]; /* Sadrzi ime etikete */
struct cvor *sledeci; /* pokazivac na sledeci cvor */
} Cvor;
52
/* Funkcija kreira novi cvor, upisuje u njega etiketu
i vraca njegovu adresu */
Cvor *napravi_cvor(char *etiketa)
{
Cvor *novi = NULL;
if ((novi = (Cvor *) malloc(sizeof(Cvor))) == NULL) {
fprintf(stderr, "malloc() greska!\n");
exit(1);
}
53
if (strlen(etiketa)>=MAX) {
fprintf(stderr, "Etiketa koju pokusavamo staviti na
stek preduga.\n");
exit(1);
}
strcpy(novi->etiketa, etiketa);
novi->sledeci = NULL;
return novi;
} 54
/* Funkcija postavlja na vrh steka novu etiketu */
void potisni_na_stek(Cvor ** vrh, char *etiketa)
{
Cvor *novi = napravi_cvor(etiketa);
novi->sledeci = *vrh;
*vrh = novi;
}
55
/* Funkcija skida sa vrha steka etiketu. Ako je
drugi argument pokazivac razlicit od NULL,
tada u niz karaktera na koji on pokazuje upisuje
ime etikete koja je upravo skinuta sa steka dok u
suprotnom ne radi nista.
Funkcija vraca 0 ako je stek prazan (pa samim tim
nije bilo moguce skinuti vrednost sa steka)
ili 1 u suprotnom. */
int skini_sa_steka(Cvor ** vrh, char *etiketa)
{
Cvor *pomocni;
56
/* pokusavamo da skinemo vrednost sa vrha
praznog steka i imamo gresku. */
if (*vrh == NULL)
return 0;
/* Ako adresa na koju zelimo da smestamo etiketu
nije NULL kopiramo tamo etiketu sa vrha steka. */
if (etiketa != NULL)
strcpy(etiketa, (*vrh)->etiketa);
/* oslobadjamo element sa vrha steka */
pomocni = *vrh;
*vrh = (*vrh)->sledeci;
free(pomocni);
return 1;
}
57
/* Funkcija vraca pokazivac na string koji sadrzi
etiketu na vrhu steka. Ukoliko je stek prazan,
vraca NULL */
char *vrh_steka(Cvor * vrh)
{
if (vrh == NULL)
return NULL;
return vrh->etiketa;
}
58
/* Funkcija prikazuje stek pocev od vrha prema dnu */
void prikazi_stek(Cvor * vrh)
{
for ( ; vrh != NULL; vrh = vrh->sledeci)
printf("<%s>\n", vrh->etiketa);
}
59
/* Funkcija prazni stek */
void oslobodi_stek(Cvor ** vrh)
{
Cvor *pomocni;
while (*vrh != NULL) {
pomocni = *vrh;
*vrh = (*vrh)->sledeci;
free(pomocni);
}
} 60
/* Funkcija iz fajla na koji pokazuje f cita sledecu
etiketu, i njeno ime upisuje u niz na koji pokazuje
pokazivac etiketa.
Funkcija vraca EOF u slucaju da se dodje do kraja fajla
pre nego sto se procita etiketa,
vraca OTVORENA ako je procitana otvorena etiketa,
odnosno ZATVORENA ako je procitana zatvorena etiketa.
*/
int uzmi_etiketu(FILE * f, char *etiketa)
{
61
int c; /* prihvata karakter iz datoteke*/
int stanje = VAN_ETIKETE; /* stanje nam cuva
informaciju dokle smo citali sa citanjem etikete
inicijalno smo ga postavili na vrednost
VAN_ETIKETE jer jos uvek nismo poceli da
citamo.*/
int i = 0;
int tip;
/* cuva informaciju o tipu etikete uzima vrednosti
OTVORENA, ZATVORENA */
62
while ((c = fgetc(f)) != EOF) {
switch (stanje) {
case VAN_ETIKETE:
if (c == '<')
stanje = PROCITANO_MANJE;
break;
63
case PROCITANO_MANJE:
if (c == '/')
/* citamo zatvarac */
tip = ZATVORENA;
else if (isalpha(c)) {
/* citamo otvarac */
tip = OTVORENA;
etiketa[i++] = tolower(c);
/* HTML je CaseInsensitive. U HTML-u etikete BODY i
body imaju isto znacenje, dok to u C-u nece vaziti.*/
}
stanje = U_ETIKETI;
/* poceli smo sa citanjem etikete, pa menjamo i stanje */
break; 64
case U_ETIKETI:
/* citamo etiketu */
if (isalpha(c) && i < MAX - 1)
/* ako je procitani karakter slovo i nismo premasili maksimalnu
dozvoljenu duzinu za etiketu*/
etiketa[i++] = tolower(c);
/* smestamo procitani karakter u etiketu*/
else {
stanje = VAN_ETIKETE;
/* u suprotnom, prestajemo sa citanjem etikete i menjamo stanje. */
etiketa[i] = '\0';
return tip;
/* zavrsili smo sa citanjem etikete i vracamo tip etikete koju smo
procitali, a ona nam je sacuvana nisci etiketa*/
}
break;}
65
}
/* dosli smo do kraja datoteke pre nego sto smo
zavrsili sa citanjem etikete , stoga imamo gresku i
vracamo EOF*/
return EOF;
}
66
/* Test program */
int main(int argc, char **argv)
{
Cvor *vrh = NULL;
char etiketa[MAX];
int tip;
int uparene = 1; /* na pocetku su nam etikete
upare, jer nismo nijednu jos uvek procitali. */
FILE *f; 67
/* Ime datoteke zadajemo na komandnoj liniji */
if (argc < 2) {
fprintf(stderr, "Koriscenje: %s ime_html_datoteke\n",
argv[0]);
exit(0);
}
/* Otvaramo datoteku */
if ((f = fopen(argv[1], "r")) == NULL) {
fprintf(stderr, "fopen() greska!\n");
exit(1);
} 68
/* Dokle god ima etiketa, uzimamo ih jednu po jednu
sa ulaza */
while ((tip = uzmi_etiketu(f, etiketa)) != EOF) {
/* Ako je otvorena etiketa, dodajemo je na stek.
Izuzetak su etikete <br>, <hr> i <meta> koje nemaju
sadrzaj, tako da ih nije potrebno zatvoriti.
NAPOMENA: U html-u postoje jos neke etikete koje
koje nemaju sadzaj (npr link). Pretpostavimo da njih
nema u dokumentu, zbog jednostavnosti */
if (tip == OTVORENA) {
if (strcmp(etiketa, "br") != 0 &&
strcmp(etiketa, "hr") != 0 &&
strcmp(etiketa, "meta") != 0)
potisni_na_stek(&vrh, etiketa);
} 69
/* Ako je zatvorena etiketa, tada je uslov dobre
uparenosti da je u pitanju zatvaranje etikete koja
je poslednja otvorena, a jos uvek nije zatvorena.
Ova etiketa se mora nalaziti na vrhu steka.
Ako je taj uslov ispunjen, tada je skidamo sa steka,
jer je zatvorena.
U suprotnom, obavestavamo korisnika da etikete
nisu pravilno uparene. */
70
else if (tip == ZATVORENA) {
if (vrh_steka(vrh) != NULL &&
strcmp(vrh_steka(vrh), etiketa) == 0)
skini_sa_steka(&vrh, NULL);
else {
printf(vrh_steka(vrh) != NULL ?
"Etikete nisu pravilno uparene\n(nadjena etiketa </%s> a
poslednja otvorena etiketa je <%s>)\n"
:
"Etikete nisu pravilno uparene\n(nadjena etiketa </%s>
koja nije otvorena)\n", etiketa, vrh_steka(vrh));
uparene = 0;
break; }
}
}
71
/* Zatvaramo fajl */
fclose(f);
/* Ako nismo pronasli pogresno uparivanje... */
if (uparene) {
/* Nakon zavrsetka citanja etiketa uslov je da stek
mora biti prazan. Ako nije, tada znaci da postoje jos
neke etikete koje su otvorene ali nisu zatvorene. */
72
if (vrh_steka(vrh) == NULL)
printf("Etikete su pravilno uparene!\n");
else
printf("Etikete nisu pravilno
uparene\n(etiketa <%s> nije zatvorena)\n",
vrh_steka(vrh));
}
/* Oslobadjamo stek */
oslobodi_stek(&vrh);
return 0;
} 73