Wstęp do informatyki Wykład 7 Prosty schemat organizacji pamięci
Transkrypt
Wstęp do informatyki Wykład 7 Prosty schemat organizacji pamięci
Wstęp do informatyki Wykład 7 Prosty schemat organizacji pamięci operacyjnej podczas działania programu. program źródłowy -> translator -> program wynikowy dane -> program wynikowy -> wyniki W uproszczonym schemacie organizacji pamięci operacyjnej wyróżniamy m.in. • segment (kodu) programu – stąd pobiera się rozkazy do wykonania. Rozkazy mają odpowiednie adresy w pamięci. • segment danych (zmienne globalne). • stos, ang. stack (miejsce na zmienne lokalne obsługiwane na zasadzie stosu) • sterta lub skład, ang. heap (miejsce na zmienne dynamiczne) Ilustrowanie działania procedur rekurencyjnych 1. Ilustracja polegająca na powielaniu treści procedury z parametrami aktualnymi zamiast formalnych Przykładowa procedura rekurencyjna licz (z rekurencją końcową) i ilustracja jej działania void licz(int n) { if (n>=1) { printf("%d",n); licz(n-1); } } Ilustracja wykonywania instrukcji licz(3) przez powielanie treści procedury z aktualnymi parametrami wywołania. Dojście sterowania do ostatniego nawiasu podczas wykonania procedury oznacza powrót z treści procedury w miejsce wywołania tej procedury (dokładniej w miejsce tuż po instrukcji wywołania tej procedury). Podczas wycofywania się z rekurencji w tej procedurze nie są wykonywane żadne obliczenia. {if (3>=1) {printf("%d",3); licz(2); } {if (2>=1) {printf("%d",2); licz(1); } itd. 2. Ilustracja wykonania procedury rekurencyjnej licz1 (bez rekurencji końcowej) z wykorzystaniem stosu (zob. np. Struktury danych w języku C, Adam Dryzek, Donald L. Simon, WNT, Warszawa, 1996.) Symboliczne adresy przekładu funkcji są oznaczane przez ai, i=1, 2, 3, 4. symboliczne adresy przekładu void licz1(int n) { /*a1*/ if (n>=1) { /*a2*/ licz1(n–1); /*a3*/ printf(''%d",n); } /*a4*/ } /*ostatni nawias w funkcji*/ wywołanie /*a5*/ licz1(3); /*a6*/ • • Po wywołaniu funkcji, np. /*a5*/ licz1(3); /*a6*/ ... na szczyt stosu jest zapisywany rekord wywołania (ang. activation record) lub ramka stosu (ang. stack frame) zawierający: " wartość parametru aktualnego i adres powrotu", czyli “3,a6”. Liczba 3 na szczycie stosu jest wartością lokalnej zmiennej n. Przy kolejnych wywołaniach rekurencyjnych jest podobnie. Po dojściu sterowania do końca przekładu treści procedury licz1 (ostatniego nawiasu w kodzie źródłowym funkcji), następuje zdjęcie rekordu wywołania ze stosu i przejście do wykonywania instrukcji o adresie wskazywanym przez "adres powrotu"; np. jeśli na szczycie stosu był rekord "2,a3”, to ten rekord jest usuwany ze stosu i program rozpoczyna działanie od instrukcji o adresie a3 (dla printf(...n) wartość n jest na szczycie stosu). Wywołanie 3 3 licz1(3); a6 Wywołanie licz1(2); a6 2 2 a3 Wywołanie licz1(1); a3 1 1 a3 Wywołanie licz1(0); a3 0 a3 Przykładowa funkcja rekurencyjna silnia (z adresami przekładów jej fragmentów) i ilustracje jej działania long silnia(int n) { /*a1*/ if (n==0) /*a2*/ return 1; else /*a3*/ return n * silnia( n-1); } int main() {... /*a4*/ y=silnia(2); ...} 3. Ilustracja obliczania wartości funkcji rekurencyjnej silnia (bez stosu). Obliczanie wartości wyrażenia silnia(2) (podkreślone są wywołania rekurencyjne) silnia(2) 2 --------↑ 2*silnia(1) 2*1=2 --------↑ 1*silnia(0) 1*1=1 wynik powstaje przy wycofywaniu z rekurencji ---------↑ 1 1 (Krótka uwaga - wyrażenia arytmetyczne są tłumaczone na postać beznawiasową; podczas tłumaczenia i obliczania wartości wyrażeń też jest wykorzystywany stos. 4. Ilustracja obliczania wartości funkcji rekurencyjnej silnia ze stosem. W rekordzie wywołania poza polami na parametr i adres powrotu jest miejsce na wynik funkcji. Wywołanie 2 2 silnia(2) a4 a4 ? 2 Wywołanie 1 1 silnia(1) a3 a3 ? 1 Wywołanie 0 0 silnia(0) a3 a3 ? 1 Złożoność czasowa T(n) i pamięciowa S(n) algorytmu rekurencyjnego silnia(n). Dla T(n) liczymy mnożenia (operacje dominujące) oraz stały czas r potrzebny na sprawdzenie: • czy jest wolne miejsce na stosie, • zarezerwowanie miejsca na nowy rekord wywołania, • usunięcie rekordu wywołania przy wycofywaniu się z rekurencji. Równanie rekurencyjne T(0)=r, T(n)=1+r+T(n-1) dla n>=1 Dla S(n) zakładamy, że podczas obliczania wartości funkcji każdy rekord umieszczany na stosie ma stałą liczbę komórek c. Równanie rekurencyjne S(0)=c, S(n)=c+S(n–1) dla n>=1.