Temat: Dynamiczne liniowe struktury danych - stos, kolejka, lista. 1. Wady i zalety struktury tablicy Wady ograniczony rozmiar maksymalny konieczno okrelenia stałego rozmiaru tablicy statyczna alokacja Zalety prosty indeksowy dostp do elementów tablicy 2. Deklaracja wskanika. Alokacja zmiennych dynamicznych a)rodzaje pamici uywanej w programach Pami komputera, dostpna dla programu, dzieli si na cztery obszary: kod programu, dane statyczne ( np. stałe i zmienne globalne programu), dane automatyczne (zmienne lokalne funkcji - tworzone i usuwane automatycznie przez kompilator) tzw. STOS (ang. stack) dane dynamiczne (zmienne, które mona tworzy i usuwa w dowolnym momencie pracy programu) w pamici wolnej komputera tzw. STERTA (ang. heap) Zmienne dynamiczne s to zmienne tworzone przez programist w pamici wolnej komputera (na stercie) dostp do takiej zmiennej moliwy jest jedynie poprzez jej adres w pamici (przechowywany w zmiennej wskanikowej). 1
b) Funkcje przydziału i zwalniania pamici W jzyku C do dynamicznego przydzielania pamici (tworzenia zmiennych dynamicznych) słu specjalne funkcje z biblioteki < alloc.h > albo <stdlib.h>. void malloc( size_t rozmiar ); // przydział bloku o zadanej wielkoci void calloc( size_t il_elementow, size_t rozmiar); // przydział // pamici dla tablicy dynamicznej void free( void wskaznik); // zwolnienie wskazywanego obszaru unsigned coreleft( void ); // sprawdzenie wolnego miejsca na stercie Przykład 1 // przydział i zwolnienie pamici na stercie int main( ) int wsk; // zmienna wskanikowa do zapamitania // adresu liczby int int x=5; wsk = (int ) malloc( sizeof(int) ); // przydzielenie pamici if( wsk == ) printf( Błd przydziału pamici ); else wsk = 10; // przykładowe operacje na dynamicznej liczbie wsk = 2; printf( %d, wsk ); scanf( %d, wsk ); free( wsk ); // zwolnienie pamici // dane spod wskanika wsk ju nie s dostpne, a 2
return 0; // dane ze zmiennej x s w dalszym cigu widoczne wsk x Stack (stos) Heap (sterta) Przykład 2 // tablica dynamiczna int rozmiar_tablicy; double T; printf( Ile liczb chcesz wprowadzi: ); scanf( %d, &rozmiar_tablicy ); if( T = (double ) calloc( rozmiar_tablicy, sizeof(double) ) ) // przydział pamici dla tablicy dynamicznej for( int i = 0; i < rozmiar_tablicy, i++ ); ( T+i ) = i*2; // albo T[ i ] =i*2; free(t); // zwolnienie pamici przeznaczonej na tablic 3
Przykład 3 // struktura dynamiczna struct Osoba char nazwisko[30]; char imie[]; float zarobki; ; Osoba wsk_osoby; wsk_osoby = (Osoba ) malloc( sizeof(osoba) ); // przydział pamici dla danych typu Osoba, // dane s dostpne przez wskanik wsk_osoby if( wsk_osoby ) // if( wsk_osoby!= ) printf( Podaj nazwisko: ); gets(wsk_osoby > nazwisko ); printf( Podaj imie: ); gets(wsk_osoby > imie); printf( Podaj zarobki: ); scanf( %f,&(wsk_osoby > zarobki));... wsk_osoby->zarobki+=100.50;... free( wsk_osoby ); // zwolnienie pamici przeznaczonej // dla danych typu Osoba Jeeli pod wskanikiem zapamitana jest struktura, to dostp do jej pól jest moliwy przez uycie operatora -> 4
Przykład 4 //dynamiczna tablica struktur int rozmiar_tablicy; Osoba T; printf( Ile liczb chcesz wprowadzi: ); scanf( %d, &rozmiar_tablicy ); T = (Osoba ) calloc( rozmiar_tablicy, sizeof(osoba)); // przydział pamici dla tablicy dynamicznej if( T == ) printf( Błd przydziału pamici ); else for( int i = 0; i < rozmiar_tablicy, i++ ); printf( Podaj nazwisko: ); gets(( T+i ) > nazwisko ); // albo gets(t[i].nazwisko); printf( Podaj imie: ); gets((t+i)->imie); // albo gets(t[i].imie); printf( Podaj zarobki: ); scanf( %f,&((t+i)->zarobki)); // albo scanf( %f,&t[i].zarobki); free( T ); // zwolnienie pamici przeznaczonej dla tablicy // dynamiczne 5
3. Stos Stos to struktura umoliwiajca wstawianie i usuwanie danych dostpnych jedynie w tzw. wierzchołku stosu. W wierzchołku stosu znajduj si zawsze dane, które zostały wstawione do stosu w trakcie ostatnio wykonanej operacji wstawiania. a) Deklaracja typu definiujcego element struktury stosu struct Element typ_danych dane; // typ danych przechowywanych w stosie Element *nastepny; // adres na nastpny element stosu ; W dalszej czci wykładu bdziemy dla uproszczenia zakładali, e przechowujemy w strukturze liczby całkowite (typ_danych=int) b) Operacja push wstawiania do stosu Element *push(element *S, int d) Przed wywołaniem push(s, d) Po wywołaniu push(s, d) S 16 dane nastepny S d 16 6
Element *push(element *S, int d) Element *temp; temp=s; S=(Element *)malloc(sizeof(element)); S->dane=d; S->nastepny=temp; return S; c) Operacja pop usuwania ze stosu Element *pop(element *S) Przed wywołaniem pop(s) S 16 dane nastepny Po wywołaniu pop(s) S 7
Element *pop(element *S) Element *temp; if (S!=) temp=s->nastepny; free(s); S=temp; return S; d) Operacja top zwracajca dane przechowywane w wierzchołku stosu int top(element *S) return S->dane; Uwaga!!! Operacja top powinna by wywołana tylko wtedy, gdy stos jest niepusty e) Operacja empty sprawdzajca, czy stos jest niepusty int empty(element *S) if (S==) return 1; else return 0;
Przykład 5 // drukowanie liczb ze stosu z jednoczesnym jego kasowaniem Element *drukuj_i_usun(element *S) while (!empty(s)) printf( %d\n, top(s)); S=pop(S); return S; 4. Kolejka Kolejka, to struktura w której mona wstawi element za tym, który trafił do struktury jako ostatni, a usuwa ten, który został wstawiony jako pierwszy. a) Deklaracja typu definiujcego element struktury kolejki struct Element typ_danych dane; // typ danych przechowywanych w stosie Element *nastepny; // adres na nastpny element stosu ; struct Kolejka Element *first, *last; W dalszej czci wykładu bdziemy dla uproszczenia zakładali, e przechowujemy w strukturze liczby całkowite (typ_danych=int) 9
b) Operacja in wstawiania do kolejki Kolejka in(kolejka Q, int d ) Q Przed wywołaniem in(q, d) Po wywołaniu in(q, d) first last 16 dane nastepny Q first last 16 d Kolejka in(kolejka Q, int d) Element *temp; temp=q.last; Q.last=(Element *)malloc(sizeof(element)); Q.last->dane=d; Q.last->nastepny=; if (temp!=) temp->nastepny=q.last; else Q.first=Q.last; return Q; 10
c) Operacja out usuwania z kolejki Kolejka out(kolejka Q) Q Przed wywołaniem out(q) first last 16 dane nastepny Q Po wywołaniu out(q) first last Kolejka out(kolejka Q) Element *temp; if (Q.first!=) temp = Q.first->nastepny; free(q.first); Q.first = temp; if (Q.first==) Q.last=; return Q; 11
d)operacja first zwracajca dane przechowywane w pierwszym elemencie kolejki int first(kolejka Q) return Q.first->dane; Uwaga!!! Operacja first powinna by wywołana tylko wtedy, gdy kolejka jest niepusta e)operacja empty sprawdzajca, czy kolejka jest niepusta int empty(kolejka Q) if (Q.first==) return 1; else return 0; Przykład 6 // wyznaczanie sumy liczb zapamitanych w kolejce z jednoczesnym // kasowaniem kolejki long sumuj_i_usun(kolejka Q) long suma=0; while (!empty(q)) suma+= first(q); Q=out(Q); return suma; 12
5. Lista Lista jest struktur, w której operacja wstawiania i usuwania nie ma cile ustalonego miejsca, tzn. moemy wstawia (usuwa) element z pocztku, koca lub rodka listy. a) Deklaracja typu definiujcego element struktury kolejki struct Element typ_danych dane; // typ danych przechowywanych w licie Element *nastepny; // adres na nastpny element listy ; W dalszej czci wykładu bdziemy dla uproszczenia zakładali, e przechowujemy w strukturze liczby całkowite (typ_danych=int) a) Operacja add wstawiania do listy Element *add(element *first, int d, Element *current) Przed add(first, d, current) F 16 dane F 16 nastepny Po add(first, d, current) current current d 13
Gdy parametr current=, to nowy element jest wstawiany jako pierwszy na licie (pod adres first). Element *add(element *F, int d, Element **current) Element *temp; if (*current == ) temp=f; F=(Element *)malloc(sizeof(element)); F->dane=d; F->nastepny=temp; *current=f; else temp=*current; *current=(element *)malloc(sizeof(element)); (*current)->dane=d; (*current)->nastepny=temp->nastepny; temp->nastepny=*current; return F; 14
c)operacja delete usuwania z Listy Element *delete (Element *F, int *d, Element **current) Przed delete(f, d, current) Po wywołaniu delete(f, d, current) F 16 dane F 16 nastepny current current d = Gdy parametr current ==, to wywołanie operacji delete nie zmienia listy. Element *delete(element *F, int *d, Element **current) Element *temp; if (F!= && *current!=) if (*current == F) temp=f->nastepny; *d=f->dane; free(f); F=temp; *current=f; else temp=f; while (temp!= && *current!=temp->nastepny) 15
return F; temp=temp->nastepny; if (temp!=) temp->nastepny=(*current)->nastepny; *d=(*current)->dane; free(*current); *current=temp->nastepny; c)funkcja get_address zwracajca adres danej wartoci Funkcja zwraca adres pusty, gdy szukanego elementu nie ma na licie albo adres podanej wartoci danych, o ile ta warto wystpuje na licie. Element *get_address(element *F, int d) Element *temp; temp=f; while (temp!= && temp->dane!=d) temp=temp->nastepny; return temp; 16
Przykład 7 // wstawianie na list liczb od 0 do // sprawdzenie, czy na licie wystpuje liczba 9 // drukowanie elementów listy połczone z ich usuwaniem Element *F=,*current=; int d; F=add(F,0,¤t); current=f; for (int i=1;i<9;i++) F=add(F,i,¤t); Element *tmp=get_address(f,9); if (tmp!=) printf("%d\n",tmp->dane); else printf("\n"); current=f; while (F!=) F=delete(F,&d,¤t); printf("%d\n",d); 17