Informatyka MPDI2 Wykład 10 DELPHI cd. - zmienne tablicowe, zmienne rekordowe zmienne plikowe
Typ tablicowy (array) Pojęcie: - skończony zbiór elementów tego samego typu składowego (tablice są homogeniczne) - o położeniu (selekcji) określanym przez indeks(-y) (numery) składowej Opis: array [ lista typów indeksów ] of typ bazowy (składowych) typ porządkowy (o ograniczonym zakresie): okrojony integer (najczęściej) okrojony char wyliczeniowy boolean dowolny: prosty strukturalny (bez plików) tablica tablic,napisów, rekordów
Uwagi tablice służą do gromadzenia wielu wartości tego samego typu (nietrwałe – tylko w pamięci operacyjnej – później poznamy jak zapisywać do plików) wymiar tablicy 1-wymiarowa -wektor 2-wymiarowa (prostokątna) 3-wymiarowa (przestrzenna) itd.. rozmiar – w każdym wymiarze! zawartość – dowolna – także inna tablica! np. array [1..5,1..5] of array [1..2,1..2] of integer;
przykłady: var tab1: array[ 1..50 ] of integer; var tab2: array[ 1..20, 1..30] of real;
rozmiar w każdym wymiarze Tablica ma: wymiar rozmiar w każdym wymiarze mogą być indeksy ujemne var tab: array [ -10 .. 0 ] of real;
Zmienne tablicowe całościowe indeksowane (składowe) x x[k]
Z [ W1, ..., Wn ] y := 10*x[ k ] - 5.2; //użycie w wyrażeniu zmienne indeksowane (składowe) - dostęp do składowych Z [ W1, ..., Wn ] Wtypu składowego nazwa tablicy indeksy wyrażenia typu zgodnego z typem indeksów zgodne co do liczby, typu i kolejności z deklaracją użycie - w wyrażeniach lub instrukcjach, jak zmienne typu składowego Przykłady: var x: array[ 1..100 ] of real; begin x[ 2 ] := 10.5; //nadanie wartości y := 10*x[ k ] - 5.2; //użycie w wyrażeniu z:=sin( sqrt( x[ 5 ] - 5.2 ) ) //użycie w wyrażeniu if x[5] >0 then .... //sprawdzenie
var x, y: array[ 1..5] of integer ; begin y[1] := 35 ; zmienne całościowe - tylko przypisanie - dla typów tożsamych! brak: + - * / porównania np: var x, y: array[ 1..5] of integer ; begin y[1] := 35 ; x := y; //przepisz całą zawartość tablicy y do tablicy x ..... end
Przykłady operacji tablicowych type tab = array [1..2, 1..5] of real; var t1, t2 : tab; wie,kol: integer; begin write ('Podaj element 1,1:'); readln(t1[1,1]); //itd. // najczęściej operacje w pętli zagnieżdżanej jeśli tablica 2-wymiarowa for wie:=1 to 2 do for kol:= 1 to 5 do t1[wie, kol] :=1; //wyświetlenie na ekranie też w pętli zagnieżdżanej write(t1[wie, kol]); writeln; end; readln; end. cała tablica wypełniona jedynkami pętla zewnętrzna po wierszach pętla wewnętrzna po kolumnach każdego wiersza po wypisaniu wiersza tabeli przejdź do nowego wiersza
Zadanie: w wektorze zsumować co drugi element (nieparzyste indeksy) program test; const N=12; type zakres = 1..N; var k: zakres; suma: real; x: array [ 1 .. N ] of real= ( 3, 4, 4.5, 5, 2, 3.5, 5.0, 4.5, 5.0, 4, 3.5, 2); //tak też można wstępnie zdefiniować zawartość tablicy begin suma := 0; for k := 1 to N do if (k mod 2) = 1 then suma := suma + x [k]; writeln ( suma :10:3) ; readln end. zastanowić się! albo można tak: for k := 1 to ( N+1 ) div 2 do suma := suma + x [ 2*k - 1 ];
Pamiętajmy: Nie ma gotowych operacji macierzowych (mnożenie, obliczanie wyznacznika, znajdowanie macierzy odwrotnej itp.), trzeba samemu stworzyć algorytm lub posiadać odpowiednie biblioteki z gotowymi podprogramami Przykładowo mnożenie tablic: program mn24; var t1:array[1..2, 1..4] of real = ((1,2,4,-1),(0, -1, 8, 1)); t2 :array[1..4,1..2] of real = ((1,1.1),(4,-2.0),(0, -1),(-3,-2.5)); wyn: array[1..2,1..2] of real; i:1..4; begin // obliczanie elementu 1,1 wyn[1,1]:=0; for i:=1 to 4 do wyn[1,1]:= wyn[1,1]+ t1[1,i]*t2[i,1]; writeln(wyn[1, 1]:10:2); readln; end. 1 2 4 -1 8 1 1.1 4 -2 -1 -3 -2.5
Całość: program mn24; const N=2; M=4; var t1:array[1..N, 1..M] of real = ((1,2,4,-1),(0, -1, 8, 1)); t2 :array[1..M,1..N] of real= ((1,1.1),(4,-2.0),(0, -1),(-3,-2.5)); wyn: array[1..N,1..N] of real; wie,kol, i:1..4; begin //potrójna pętla! for wie:=1 to N do for kol:=1 to N do for i:=1 to M do wyn[wie,kol]:= wyn[wie,kol]+ t1[wie,i]*t2[i,kol]; //wyswietlenie wyniku for kol:= 1 to N do write(wyn[wie, kol]:10:2); //wypisanie wiersza writeln; //zmiana wiersza end; readln; end.
string[20] tożsame z array[0..20] of char; Pamiętamy typ string – typ łańcuchowy – zmienna zawiera ciąg znaków Można typ string traktować jako wektor znaków string[20] tożsame z array[0..20] of char; var zmienna:string[20]; begin zmienna:= 'lokomotywa'; writeln (zmienna[3]); { wyświetli literę k } {…..} end.
Przeszukiwanie tablic jednowymiarowych Algorytm przeszukiwania tablic polega na porównywaniu podanego wzorca z kolejnymi elementami tablicy. Pseudokod algorytmu wygląda następująco. 1. Start. 2. Wczytaj tablicę i wzorzec przeszukiwań (czyli czego szukamy). 3. Ustaw zmienną licznika na wartość 1. 4. Sprawdź czy wzorzec jest równy elementowi tablicy o indeksie równym licznikowi. Jeżeli tak to przejdź do punktu 7, jeśli nie to kontynuuj. 5. Zwiększ licznik o 1. 6. Sprawdź czy licznik nie jest większy od rozmiaru tablicy. Jeśli tak, to napisz, że nie znaleziono wzorca i przejdź do punktu 8, jeśli nie to przejdź do punktu 4. 7. Wypisz licznik i element o indeksie równym aktualnemu licznikowi. 8. Stop. Oczywiście algorytm znajdzie tylko pierwsze wystąpienie – co zrobić gdy w tablicy elementy się powtarzają?
Wyznaczanie minimum (maksimum) Algorytm przeszukiwania tablic polega na początkowym założeniu, że minimum (maksimum) X jest pierwszym elementem tablicy. Następnie kolejno sprawdzamy elementy od 2 do N - jeśli analizowany element jest mniejszy (większy) od aktualnego X ustawiane jest nowe X. Pseudokod algorytmu wygląda następująco. 1. Start. 2. Wczytaj tablicę. 3. Przypisz pierwszy element tablicy do Emin. 4. Zwiększ licznik o 1. Sprawdź czy licznik nie jest większy od rozmiaru tablicy. Jeśli tak, przejdź do punktu 9. Sprawdź czy aktualny element jest mniejszy od Emin.Jeśli tak wstaw go do Emin. Przejdź do punktu 4. 9. Wypisz Emin. 10. Stop.
if x[k]>max then max:=x[k]; program maximum; {$APPTYPE CONSOLE} uses SysUtils; var x:array[1..20] of integer; k,max:1..20; begin randomize; for k:=1 to 20 do // losowe wypełnienie tablicy x[k]:= random(100); write(x[k]:5); end; max:= x[1]; for k:=2 to 20 do if x[k]>max then max:=x[k]; writeln; writeln(max:10); readln; end.
Sortowanie bąbelkowe Algorytm polega porównywaniu kolejnych par elementów sąsiadujących i zamianie miejscami w przypadku niewłaściwej kolejności. Po wykonaniu pierwszego przebiegu porównań i ewentualnych zamian miejscami, element największy znajdzie się na końcu (w przypadku porządku sortowania według kolejności rosnącej). Następnie wykonujemy kolejny przebieg porównań par i tak dalej…
Sortowanie Sortowanie bąbelkowe Algorytm polega porównywaniu kolejnych par elementów sąsiadujących i zamianie miejscami w przypadku niewłaściwej kolejności 1 2 3 4 ..... N N-1 porównań w każdym przebiegu Wykonujemy N przebiegów
N=6 zauważamy nadmiarowe porównania 1 przebieg 12 5 11 4 7 2 zamiana 1 5 11 4 7 2 12 efekt ostatniej zamiany – największy na końcu 2 przebieg 5 11 4 7 2 12 5 11 4 7 2 12 zmiana 6 5 4 11 7 2 12 zmiana 7 5 4 7 11 2 12 zmiana 8 5 4 7 2 11 12 3 przebieg 5 4 7 2 11 12 zamiana 9 4 5 7 2 11 12 4 5 7 2 11 12 zamiana 10 4 5 2 7 11 12 4 przebieg 4 5 2 7 11 12 zamiana 11 4 2 5 7 11 12 N=6 zauważamy nadmiarowe porównania
30 operacji= (N-1)*N=6*5 5 przebieg 4 2 5 7 11 12 zmiana 12 2 4 5 7 11 12 6 przebieg 30 operacji= (N-1)*N=6*5
Sortowanie bąbelkowe skrócone Algorytm polega na porównywaniu kolejnych par elementów sąsiadujących, z tym, że: - w każdym kolejnym przebiegu liczba analizowanych par jest zmniejszana o 1 - przebiegów wykonujemy N-1
15 operacji 5 4 3 2 1 1 przebieg 12 5 11 4 7 2 zamiana 1 5 11 4 7 2 12 efekt 2 przebieg 5 11 4 7 2 12 5 11 4 7 2 12 zamiana 6 5 4 11 7 2 12 zamiana 7 5 4 7 11 2 12 zamiana 8 5 4 7 2 11 12 efekt 3 przebieg 5 4 7 2 11 12 zamiana 9 4 5 7 2 11 12 4 5 7 2 11 12 zamiana 10 4 5 2 7 11 12 efekt 4 przebieg 4 5 2 7 11 12 4 5 2 7 11 12 zamiana 11 4 2 5 7 11 12 efekt 5 przebieg 4 2 5 7 11 12 zamiana 12 2 4 5 7 11 12 efekt 5 4 15 operacji 3 2 1
lop=90 const N=10; k, m:1..N; Sortowanie bąbelkowe pom, lop:integer; var tab:array [1..N] of integer; k, m:1..N; pom, lop:integer; begin randomize; //wypełnienie losowe tablicy 1-wymiarowej for k:=1 to N do tab[k]:=random(100); //sortowanie for m:=1 to N-1 do begin lop:=lop+1; if tab[m]>tab[m+1] then pom:=tab[m]; tab[m]:=tab[m+1]; tab[m+1]:=pom; end; //wypisanie wyniku for k:= 1 to N do write(tab[k]:6); writeln;writeln(lop); readln; end. Sortowanie bąbelkowe zamiana wartości tab[m] i tab[m+1] lop=90
lop=45 szybsze const N=10; k,m:1..N; Sortowanie bąbelkowe skrócone var tab:array [1..N] of integer; k,m:1..N; pom,lop:integer; begin randomize; //wypełnienie losowe tablicy 1-wymiarowej for k:=1 to N do tab[k]:=random(100); //sortowanie for k:=1 to N-1 do for m:=1 to N-k do begin lop:=lop+1; if tab[m]>tab[m+1] then pom:=tab[m]; tab[m]:=tab[m+1]; tab[m+1]:=pom; end; //wypisanie wyniku for k:= 1 to N do write(tab[k]:6); writeln;writeln(lop); readln; end. Sortowanie bąbelkowe skrócone różnice! lop=45 szybsze
Typ rekordowy (record) pojęcie: - skończony zbiór elementów dowolnego typu składowego tak zwane pola - ułożone jednowymiarowo - o położeniu (selekcji) określanym przez nazwę składowej (pola) - tzw. dostęp kwalifikowany Czyli zestaw nazwanych pól dowolnego typu (i różnego rozmiaru)
liczbą, tekstem, tablicą, napisem, innym rekordem opis: record lista_nazw_pól: typ1; lista_nazw_pól: typ2; . . . end typ dowolny: prosty lub strukturalny (bez plików) pole rekordu może być: liczbą, tekstem, tablicą, napisem, innym rekordem
Przykłady: type data = record rok: 1900 .. 2100; mies: 1..12; dzien: 1..31 end; var student : record nazw: string[ 20 ]; imie: array[1..2] of string[ 15 ]; data_ur: data; stypend: real end; St. Wołek - Podst. Progr. Komput.
Porównanie: jednakowe składowe selektor typu indeks dostęp bezpośredni statyczny rozmiar różne składowe selektorem jest nazwa pola dostęp bezpośredni statyczny rozmiar Uwaga: Rekord to jeden zestaw danych (np. dane jednego studenta), jeśli potrzebujemy analizy większej liczby to tworzymy tablicę rekordów
Deklaracje (opis) zmiennych Zmienna tablicowa var t1:array [1..5, 1..6] of real; Zmienna rekordowa var student : record nazw: string[ 20 ]; imie: array[1..2] of string[ 15 ]; stypend: real end; type dane = record nazw: string[ 20 ]; imie: array[1..2] of string[ 15 ]; stypend: real end; var student: dane; lub
Wykorzystanie zmiennych rekordowych w programie zmienne całościowe - tylko przypisanie – możliwe jedynie dla typów tożsamych czyli dokładnie takie same składowe! brak: + - * / porównania wejścia/wyjścia – wczytać lub wypisać można tylko składową (pole) np: var r1, r2: record ..definicja... end ; begin //… ustalenie zawartości zmiennej r1 r2 := r1; //przepisz zawartość r1 do r2
Z . p Ztypu składowego UWAGA: kropka oddzielająca! desygnator pola (składowa) - dostęp do pola Z . p Ztypu składowego nazwa zmiennej rekordowej nazwa pola UWAGA: kropka oddzielająca!
dzien, miesiac, rok:integer end; Przykład1 type data= record dzien, miesiac, rok:integer end; var student: record nazw: string[ 20 ]; imie: array[1..2] of string[ 15 ]; data_ur: data;//zdefiniowany typ rekordowy stypend: real begin student.nazw:= 'Kowalski'; student.stypend:= 300; student.data_ur.dzien:= 3; student.data_ur.rok := 1993; student.imie[1]:= 'Jan'; writeln(student.imie[1][2] ) ; //to 2-ga litera 1-go imienia //itd. definicje użycie: w wyrażeniach lub instrukcjach, w zależności od typu składowej program
Przykład2: program test; type data= record dzien, miesiac, rok:integer; end; var student: record nazw: string[ 20 ]; imie: array[1..2] of string[ 15 ]; data_ur: data; stypend: real begin write('Podaj imię1:'); readln(student.imie[1]); write('Podaj drugie imię:'); readln(student.imie[2]); write('Podaj dzien urodzenia:'); readln(student.data_ur.dzien); //itd. writeln(student.imie[1]); //wypisz na ekranie end. Przykład2:
rekord student.nazwisko student.imie[1] student.data_ur.rok Użycie elementów tablicy i rekordu w części wykonawczej programu: tablica t1[5, 6] indeks (-y) rekord student.nazwisko student.imie[1] student.data_ur.rok w zależności od typu nazwy pól zmienna
var os1: osoba; // zmienna rekordowa pomocnicza TABLICE REKORDÓW Tablice rekordów służą do gromadzenia wielu danych typu rekordowego (zwykle 1-wymiarowe) type data = record rok: 1900 .. 2100; mies: 1..12; dzien: 1..31 end; osoba = record nazw: string[ 20 ]; imie: array[1..2] of string[ 15 ]; data_ur: data; var os1: osoba; // zmienna rekordowa pomocnicza grupa: array[1..100] of osoba; //tablica rekordów !!!!
grupa – zmienna typu tablicowego grupa[k] – zmienna typu rekordowego grupa[1].nazw - zmienna typu string grupa[2].imie – zmienna typu tablicowego grupa[k].imie[1] - zmienna typu string grupa[k].data_ur - zmienna typu rekordowego grupa[k].data_ur.rok – zmienna typu integer grupa[2].imie[2][5] – zmienna typu char Użycie zależne od typu: writeln( grupa[3].nazw); os1.nazw := 'Nowak'; grupa[50]:=os1; os1:= grupa[51]; writeln (grupa[k].imie[1]); writeln(length(grupa[30].nazw)) if grupa[k].data_ur.rok>1970 then…
Instrukcja wiążąca - with dotyczy tylko zmiennych rekordowych (obiektowych) upraszcza zapis !! Opis: with lista_zmiennych_rekordowych do instrukcja; najczęściej begin . . . end można tu używać nazw pól bez specyfikowania zmiennej rekordowej przykład: with student do begin nazw :='Kowalski'; imie[1] := 'Jan'; data_ur.rok := 1988; stypendium := 420.0; end; student.nazw :='Kowalski'; student.imie[1] := 'Jan'; student.data_ur.rok := 1988; student.stypendium := 420.0;
Obsługa plików Pojęcie i istota stosowania elementy Pojęcie i istota stosowania składowe takiego samego dowolnego typu - prostego, strukturalnego - nie pliki dostęp sekwencyjny - operacje np.: czytaj pierwszy | czytaj następny zapisz na początku | zapisz na końcu brak selektora (adresacji) rozmiar dynamiczny istnieje wewnętrzny wskaźnik elementu bieżącego, automatycznie modyfikowany po każdej operacji odczyt | zapis fizycznie - w pamięci zewnętrznej: dysk, dyskietka, CD-ROM, - znakowe urządzenia wej/wyj: (monitor), drukarka
Uwagi: Po otwarciu do odczytu wskaźnik ustawia się na początku pliku, każdy odczyt lub zapis przesuwa wskaźnik o jedną pozycję. Otwarcie nowego (nieistniejącego) pliku powoduje utworzenie pustego pliku, jeśli plik istniał jego zawartość zostaje usunięta, Można sprawdzić czy wskaźnik jest na końcu pliku Można przewinąć wskaźnik na początek – jeśli wtedy stwierdzimy, że jesteśmy na końcu pliku to plik jest pusty, Zapis nowego elementu zalecany tylko na końcu pliku (w środku można, ale wtedy zmienimy (nadpiszemy) wartość elementu). Dopisanie „w środku” pliku wykonuje się przez etapowe przepisywanie do innego pliku.
textFile - plik tekstowy czyli file of string istotne cele - gromadzenie dużej ilości informacji w sposób trwały - przenoszenie danych między programami | komputerami Opis typu plikowego file of Tb - plik elementowy ( binarny, zdefiniowany ) o składowych typu Tb textFile - plik tekstowy czyli file of string Wprowadza się tzw. zmienne plikowe służące do komunikowania programu z plikami fizycznymi deklaracja: var lista_nazw_zmiennych: Tp; - Tp jest opisem typu plikowego lub nazwą typu są zmienne całościowe - reprezentują cały plik nie ma zmiennych składowych - brak selektora są operacje dotyczące składowych pliku (procedury, funkcje), korzystamy ze zmiennych odpowiadających składowym plików
Przykłady deklaracji zmiennych plikowych: type osoba = record nazw: string[ 20 ]; imie: array[1..2] of string[ 15 ]; data_ur: data; pensja: real end; dwa_napisy = array[1..2] of string[15]; //definiujemy zmienne typu plikowego var oceny: file of real; nazwiska: file of string[20]; zaloga: file of osoba; adresy: file of dwa_napisy; wyniki: textFile;
!!! skojarzenie zmiennej plikowej z plikiem fizycznym Kolejność operacji plikowych: !!! skojarzenie zmiennej plikowej z plikiem fizycznym otwarcie pliku (do zapisu lub odczytu) operacje (czytanie, zapis) zamknięcie
Reguły obsługi plików W części deklaracyjnej opis zmiennych plikowych type osoba = .....; var grupa: file of osoba; W bloku wykonawczym skojarzenie - f ’d:\ścieżka\plik’ otwarcie pliku f do - zapisu - odczytu - dodawania (tylko tekstowe) operacje - zapis | odczyt zamknięcie pliku f usunięcie pliku f | zmiana położenia (nazwy)
..istnieje grupa standardowych procedur i funkcji, m.in. procedura: assignFile( f, Wt ) - skojarzenie f zmienna plikowa stała tekstowa – ścieżka i nazwa pliku na dysku np.: assignFile( grupa, ' C:\ROK_II\grupa_1.bin ' ); procedura : reset( f ) - otwarcie do odczytu /zapisu (zastępowanie) - jeśli plik istnieje!!! - plik staje się aktywny - wskaźnik na początku pliku - gdy plik nie istnieje błąd wykonania procedura : rewrite( f ) - otwarcie do zapisu - gdy plik nie istniał jest tworzony - gdy plik istniał jest zerowany - wskaźnik na początku-końcu pliku pustego procedura: append( f ) - otwarcie do zapisu na końcu pliku (tylko dla pliku typu texfile)
Odczyt z pliku f zmienna plikowa zapis do pliku procedura : read( f, zmienna) f zmienna plikowa zmienna takiego samego typu jak element pliku zapis do pliku procedura : write( f, zmienna ) Można korzystać z readln i writeln, ale tylko dla zmiennych plikowych typu Textfile
procedura : closeFile( f ) - zamknięcie pliku - dopisuje zawartość bufora do pliku, zwalnia go - powinno się odbyć przed zakończeniem programu funkcja: eof( f ) - badanie końca pliku (end of file) - wartość logiczna: true - wskaźnik po ostatniej wartości (na końcu) false - wskaźnik w środku Także operacje systemu plików – np. procedura erase(plik) – usunięcie pliku
Przykład: Zapis liczby do pliku tekstowego program test; var p1:TextFile; z:real; begin z:=7.5; assignfile(p1,'d:\dane\a.txt'); rewrite(p1); //otwarcie do zapisu writeln(p1,z:2:0); //wpisze do pliku 8 closeFile(p1); end. nazwa fizycznego pliku (wraz z ewentualną ścieżką dostępu)
Przykład: odczyt jednej liczby z pliku tekstowego program test; var p1:TextFile; z:real; begin assignFile(p1,'a.txt'); //plik w tym samym folderze co program reset(p1); readln(p1,z); //czytanie z pliku do zmiennej CloseFile(p1); writeln(z:10:3); //wypisanie na konsoli readln end.
Jeśli więcej liczb w wierszach w pliku i nie wiemy ile, zwykle stosuje się konstrukcję while..do program test; var p1:TextFile; z:real; begin assignFile(p1,'a.txt'); reset(p1); while not eof(p1) do readln(p1,z); //czytanie z pliku do zmiennej writeln(z:10:3); //wypisanie na konsoli end; CloseFile(p1); readln end. pętla - dopóki nie ma końca pliku wykonuj...
Prosty zapis do pliku elementowego program pliki; type osoba = record nazw, imie: string[ 20 ]; stypendium: real end; var student:osoba; plik:file of osoba; begin assignfile(plik,'spis.bin'); //skojarzenie rewrite(plik); //utworzenie pliku readln(student.nazw); //użytkownik podaje elementy readln(student.imie); readln(student.stypendium); write(plik,student); //zapis do pliku całego rekordu!!!! closeFile(plik); readln end.
Prosty odczyt z pliku elementowego program pliki2; type osoba = record nazw, imie: string[ 20 ]; stypendium: real; end; var student:osoba; plik:file of osoba; begin assignfile(plik,'spis.bin'); //skojarzenie reset(plik); //otwarcie pliku read(plik,student); //odczyt z pliku całego rekordu!!!! writeln(student.nazw); //wypisujemy na ekranie writeln(student.imie); writeln(student.stypendium); closeFile(plik); readln; end.