Temat: Dynamiczne liniowe struktury danych

Transkrypt

Temat: Dynamiczne liniowe struktury danych
Temat: Dynamiczne liniowe struktury danych - stos,
kolejka, lista.
1. Wady i zalety struktury tablicy
Wady
• ograniczony rozmiar maksymalny
• konieczno okre lenia stałego rozmiaru tablicy
• statyczna alokacja
Zalety
• prosty indeksowy dost p do elementów tablicy
2. Deklaracja wska nika. Alokacja zmiennych dynamicznych
a)Rodzaje pami ci u ywanej w programach
Pami komputera, dost pna 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 mo na tworzy i usuwa w
dowolnym momencie pracy programu) → w pami ci wolnej
komputera → tzw. STERTA (ang. heap)
Zmienne dynamiczne → s to zmienne tworzone przez programist
w pami ci wolnej komputera (na stercie)
→ dost p do takiej zmiennej mo liwy jest
jedynie poprzez jej adres w pami ci
(przechowywany w zmiennej
wska nikowej).
1
b) Funkcje przydziału i zwalniania pami ci
W j zyku C do dynamicznego przydzielania pami ci (tworzenia
zmiennych dynamicznych) słu specjalne funkcje z biblioteki
< alloc.h > albo <stdlib.h>.
void ∗malloc( size_t rozmiar ); // przydział bloku o zadanej wielko ci
void ∗calloc( size_t il_elementow, size_t rozmiar); // przydział //
pami ci dla tablicy dynamicznej
void free( void ∗wskaznik);
// zwolnienie wskazywanego obszaru
unsigned coreleft( void ); // sprawdzenie wolnego miejsca na stercie
Przykład 1
// przydział i zwolnienie pami ci na stercie
int main( )
{
int ∗wsk; // zmienna wska nikowa do zapami tania
// adresu liczby int
int x=5;
• • •
wsk = (int∗) malloc( sizeof(int) ); // przydzielenie pami ci
if( wsk == NULL )
printf( ”Bł d przydziału pami ci” );
else
{
∗wsk = 10;
// przykładowe operacje na dynamicznej liczbie
∗wsk ∗= 2;
printf( ”%d”, ∗wsk );
scanf( ”%d”, wsk );
• • •
free( wsk );
// zwolnienie pami ci
• • • // dane spod wska nika wsk ju nie s dost pne, a
2
}
return 0;
}
// dane ze zmiennej x s w dalszym ci gu widoczne
wsk
20
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ł pami ci dla tablicy dynamicznej
{
for( int i = 0; i < rozmiar_tablicy, i++ );
∗( T+i ) = i*2; // albo T[ i ] =i*2;
• • •
}
free(T); // zwolnienie pami ci przeznaczonej na tablic
3
Przykład 3
// struktura dynamiczna
struct Osoba{
char nazwisko[30];
char imie[20];
float zarobki;
};
Osoba ∗wsk_osoby;
wsk_osoby = (Osoba∗) malloc( sizeof(Osoba) );
// przydział pami ci dla danych typu Osoba,
// dane s dost pne przez wska nik wsk_osoby
if( wsk_osoby ) // if( wsk_osoby != NULL )
{
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 pami ci przeznaczonej
// dla danych typu Osoba
}
Je eli pod wska nikiem zapami tana jest struktura, to dost p do jej
pól jest mo liwy przez u ycie 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ł pami ci dla tablicy dynamicznej
if( T == NULL )
printf( ”Bł d przydziału pami ci” );
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 pami ci przeznaczonej dla tablicy
// dynamiczne
5
3. Stos
Stos to struktura umo liwiaj ca wstawianie i usuwanie danych
dost pnych 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 definiuj cego element struktury stosu
struct Element{
typ_danych dane; // typ danych przechowywanych w stosie
Element *nastepny; // adres na nast pny element stosu
};
W dalszej cz ci wykładu b dziemy 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)
S
16
dane
nastepny
Po wywołaniu push(S, d)
S
d
20
16
8
20
NULL
8
NULL
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)
16
S
dane
nastepny
Po wywołaniu pop(S)
20
S
20
8
8
NULL
NULL
7
Element *pop(Element *S)
{
Element *temp;
if (S!=NULL)
{
temp=S->nastepny;
free(S);
S=temp;
}
return S;
}
d) Operacja top zwracaj ca 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 sprawdzaj ca, czy stos jest niepusty
int empty(Element *S)
{
if (S==NULL) return 1; else return 0;
}
8
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 mo na wstawi element za tym, który
trafił do struktury jako ostatni, a usuwa ten, który został wstawiony
jako pierwszy.
a) Deklaracja typu definiuj cego element struktury kolejki
struct Element{
typ_danych dane; // typ danych przechowywanych w stosie
Element *nastepny; // adres na nast pny element stosu
};
struct Kolejka
{
Element *first, *last;
}
W dalszej cz ci wykładu b dziemy 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 )
Przed wywołaniem in(Q, d)
16
first
Q
Po wywołaniu in(Q, d)
dane
nastepny
16
first
20
20
Q
last
8
last
NULL
8
d
NULL
Kolejka in(Kolejka Q, int d)
{
Element *temp;
temp=Q.last;
Q.last=(Element *)malloc(sizeof(Element));
Q.last->dane=d;
Q.last->nastepny=NULL;
if (temp!=NULL) temp->nastepny=Q.last;
else Q.first=Q.last;
return Q;
}
10
c)
Operacja out usuwania z kolejki
Kolejka out(Kolejka Q)
Przed wywołaniem out(Q)
16
Q
first
20
Po wywołaniu out(Q)
dane
nastepny
20
first
Q
8
last
last
8
NULL
NULL
Kolejka out(Kolejka Q)
{
Element *temp;
if (Q.first!=NULL)
{
temp = Q.first->nastepny;
free(Q.first);
Q.first = temp;
if (Q.first==NULL) Q.last=NULL;
}
return Q;
}
11
d)Operacja first zwracaj ca 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 sprawdzaj ca, czy kolejka jest niepusta
int empty(Kolejka Q)
{
if (Q.first==NULL) return 1; else return 0;
}
Przykład 6
// wyznaczanie sumy liczb zapami tanych 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
ci le ustalonego miejsca, tzn. mo emy wstawia (usuwa ) element z
pocz tku, ko ca lub rodka listy.
a) Deklaracja typu definiuj cego element struktury kolejki
struct Element{
typ_danych dane; // typ danych przechowywanych w li cie
Element *nastepny; // adres na nast pny element listy
};
W dalszej cz ci wykładu b dziemy 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
current
20
8
NULL
dane
nastepny
Po add(first, d, current)
F
16
20
current
d
8
NULL
13
Gdy parametr current=NULL, to nowy element jest wstawiany
jako pierwszy na li cie (pod adres first).
Element *add(Element *F, int d, Element **current)
{
Element *temp;
if (*current == NULL)
{
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)
F
16
current
20
dane
nastepny
Po wywołaniu delete(F, d, current)
F
current
16
8
d = 20
8
NULL
NULL
Gdy parametr current == NULL, to wywołanie operacji delete nie
zmienia listy.
Element *delete(Element *F, int *d, Element **current)
{
Element *temp;
if (F!=NULL && *current!=NULL)
if (*current == F)
{
temp=F->nastepny;
*d=F->dane;
free(F);
F=temp;
*current=F;
}
else {
temp=F;
while (temp!=NULL && *current!=temp->nastepny)
{
15
}
}
return F;
temp=temp->nastepny;
if (temp!=NULL)
{
temp->nastepny=(*current)->nastepny;
*d=(*current)->dane;
free(*current);
*current=temp->nastepny;
}
}
c)Funkcja get_address zwracaj ca adres danej warto ci
Funkcja zwraca adres pusty, gdy szukanego elementu nie ma na li cie
albo adres podanej warto ci danych, o ile ta warto wyst puje na
li cie.
Element *get_address(Element *F, int d)
{
Element *temp;
temp=F;
while (temp!=NULL && temp->dane!=d)
temp=temp->nastepny;
return temp;
}
16
Przykład 7
// wstawianie na list liczb od 0 do 8
// sprawdzenie, czy na li cie wyst puje liczba 9
// drukowanie elementów listy poł czone z ich usuwaniem
Element *F=NULL,*current=NULL;
int d;
F=add(F,0,&current);
current=F;
for (int i=1;i<9;i++) F=add(F,i,&current);
Element *tmp=get_address(F,9);
if (tmp!=NULL) printf("%d\n",tmp->dane);
else printf("NULL\n");
current=F;
while (F!=NULL)
{
F=delete(F,&d,&current);
printf("%d\n",d);
}
17