Wersja do druku

Transkrypt

Wersja do druku
Podstawy Informatyki
Języki programowania
Kompilacja – proces, w którym program w języku wysokiego poziomu jest
tłumaczony na język adresów symbolicznych (asembler). Program realizujący ten
proces nazywany jest kompilatorem.
Interpreter – program tłumaczący każdą instrukcję na instrukcje poziomu
maszyny i natychmiast ją wykonujący.
Wykład 4
Fortran
Cobol
do obliczeń numerycznych.
język dla przedsiębiorstw i handlu (mechanizmy definiowania
struktury pliku)
języki uniwersalne
manipulowanie tekstami i napisami
oparty na logice faktów
przetwarzanie list, obliczenia symboliczne
Struktury danych
Pascal, C++
Snobol
Prolog
Lisp
Delphi
Java
………
Struktura programu
Początek
deklaracje
komentarze
instrukcje
Koniec
Przykład:
Pascal:
Program nazwa;
begin
.
.
.
end.
Stałe i zmienne
Zmienne są różnych typów:
• całkowite (integer): 1, 2, 128
• rzeczywiste (real): 0.456, -734.129
• logiczne (logical): true, false
• znakowe (character): imie, adres
• itp.
Podstawowymi obiektami występującymi w programie są
stałe i zmienne. Ich znaczenie jest takie samo jak w
matematyce.
Stałe i zmienne muszą posiadać nazwę i posiadają
przypisaną wartość.
Nazwa jest ciągiem znaków, z których pierwszy musi być
literą, np.: x, alfa1, pierwiastek1,
Obowiązują tylko znaki ASCII (abc...z, ABC...XYZ). Nie ma
polskich liter ani greckich.
Charakter zmiennych jest deklarowany we wstępnej części
programu (zazwyczaj zaraz na początku, przed
instrukcjami właściwymi programu)
Tablice
Tablica jest to struktura danych zawierająca uporządkowany
zbiór obiektów tego samego typu i odpowiada
matematycznemu pojęciu wektora, macierzy, zmiennych
indeksowych, itp.
1
2
3
4
5
a
S = a 1 + a 2 + ... + a n
6
7
Dlaczego tablice?
Jeśli n=3, to nie tak ważne.
A jeśli n=100?
- deklarujemy jedną zmienną tablicową a nie 100
zwykłych.
- w programie można łatwo odwołać się do elementu,
którego numer jest wyliczany, np.: k=2*i-1
Dla i=5 mamy k=9
Do zmiennej tablicowej A odwołujemy się: x:=A[9], lub
x:=A[k], a nawet x:=A[2*i-1]
Proste?
A gdyby nie było zmiennych tablicowych?
Dlaczego tablice, cd.
Przykład programu:
k=2*i-1
wybierz k z:
1: x:=A1
2: x:=A2
3: x:=A3
...
9: x:=A9
...
100: x:=A100
Bez sensu!
Wyrażenia
Wyrażenia są zapisem operacji, które wykonywane są na
zmiennych i stałych.
Wyrażenie składa się ze stałych, zmiennych i łączących
je operatorów.
Operatory: + , - , *, /
Kolejność wykonywania działań określają nawiasy i
priorytet operatorów.
Np.: x1 = 2.5 a - x y
x1 = 2.5*a - x*y
y = (a+b)*(x-2*y)+2.5/(x-5)
W poszczególnych językach mogą występować różnice w
operatorach.
Podprogram – fragment programu wykonujący te same
działania dla różnych argumentów.
• Podprogramy mogą być wywoływane z argumentami (parametrami):
podprogram (argument_1, argument_2, ..., argument_3)
• Procedura – podprogram, który nie zwraca wartości
procedura(lista_argumentów){
........
}
• Funkcja – podprogram, który zwraca wartość
typ_wartości_zwracanej funkcja(lista_argumentów){
typ_wartości_zwracanej wynik;
........
return wynik; //zwróć wynik
}
Instrukcje wejścia/wyjścia
Umożliwiają komunikowanie się programu z
użytkownikiem.
Umożliwiają czytanie danych jak również
wypisywanie komunikatów i wyników prowadzonych
obliczeń.
Np.: Pascal • read(a,b);
{ z klawiatury wprowadzamy : np. 12 5 }
• writeln(a);
{drukujemy na ekranie wartość a (np. 12 }
Przykład wykorzystania podprogramu.
Program (analizator tekstu) – przetwarza i analizuje tekst pod kątem wyszukiwania
określonego ciągu znaków.
program analizator{
otwórz_plik_do_analizy(p,"nazwa");
int licznik_1, licznik_2=0; //zmienne typu całkowitego do
//przechowywania liczby wystąpień szukanych ciągów znaków
licznik_1=szukaj(p,"wektor"); //WYWOŁANIE PODPROGRAMU
licznik_2=szukaj(p,".");
wypisz("W pliku ",p," słowo wektor występuje ",licznik_1,"razy. ",
"W pliku jest ", licznik_2," zdań");
} //koniec programu
int szukaj(plik, ciąg_znaków){
int licznik=0;
wskaźnik=0; //wskazuje początek słowa w pliku
słowo – zmienna typu ciąg znaków
while( ¬koniec_pliku(plik) ){ //dopóki nie ma końca pliku
słowo=weź_słowo(plik,wskaźnik);
//funkcja zwraca słowo wskazywane przez wskaźnik w pliku
if(słowo == ciąg_znaków) licznik=licznik+1;
przesuń_wskaźnik(plik,wskaźnik);
//funkcja przesuwa wskaźnik w pliku na następne słowo
}
return licznik; //zwróć licznik
} //koniec funkcji szukaj
Zalety podprogramów
• zmniejszenie rozmiaru algorytmu
• dobrze napisany i przemyślany podprogram stanowi kolejną elementarną
instrukcję → zwiększenie czytelności i przejrzystości algorytmu
• Stosowanie podprogramów daje możliwość budowy złożonego algorytmu
stopniowo, a nie stosując od razu wyłącznie dozwolone instrukcje elementarne:
w pierwszym etapie tworzony jest algorytm wysokiego poziomu, zawierający
nie tylko instrukcje elementarne, ale także instrukcje, których szczegółowe
realizacje zostaną napisane później. Kolejny krok to uszczegółowienie tych
instrukcji.
instrukcja elementarna
instrukcja wp III
instrukcja wp II
instrukcja wp I
................
instrukcja wp III
................
instrukcja elementarna
................
instrukcja wp II
Typy proste:
• liczbowe: całkowite, zmiennoprzecinkowe,
w formacie dziesiętnym, dwójkowym, itp.
• znakowe: słowa zapisane w różnych alfabetach
• logiczne: prawda/fałsz
Zmienne
Służą do przechowywania w pamięci pojedynczych obiektów
instrukcja elementarna
................
instrukcja wp II
Typy danych
Typ danych określa zbiór wartości, do którego należy obiekt
Metoda zstępująca
(analityczna)
................
Odwoływanie się do zmiennych.
Przykład:
Niech X będzie zmienną całkowitą.
wypisz(X); //wypisz wartość zmiennej X
X ← -2; //przypisz zmiennej X wartość –2
X ← X + 5; //zwiększ wartość X o 5
Metoda wstępująca (syntetyczna) – przeciwieństwo metody zstępującej
Struktury danych
Struktury danych
W programowaniu struktura danych jest sposobem składowania danych na komputerze tak, by mogły być efektywnie wykorzystane. Często staranne dobranie struktury danych pozwala na zastosowanie wydajniejszego algorytmu .
Przykładowe struktury danych to:
Struktura danych – zbiór elementów. Każdy element składa
się z jednego lub więcej części (słów maszynowych),
zwanych polami.
Przykład elementu struktury danych
•rekord, zwany w niektórych językach po prostu strukturą
p1
•tablica
p2
•lista
p3
p4
•stos
Pole p1 jest wskaźnikiem (dowiązaniem)
Pola p2, p3, p4 – dowolnego typu
•kolejka
•drzewo i jego liczne odmiany (np. drzewo binarne)
•graf
Struktury danych
TOP
p2
p2
p2
p2
p3
p3
p3
p3
p4
p4
p4
p4
Wskaźnik (dowiązanie) – podstawowy sposób reprezentowania
złożonych struktur danych.
Dowiązanie puste – symbol Λ, symbol uziemienia
Na pierwszą wartość wskazuje wartość zapisana w zmiennej TOP
TOP to zmienna wskaźnikowa – zmienna, której wartościami
są wskaźniki (dowiązania).
Wszystkie odwołania do elementów struktury odbywają się
• bezpośrednio przez zmienne (lub stałe) wskaźnikowe
• pośrednio przez pola elementów struktury zawierające wskaźniki
Listy liniowe
Projekt reprezentacji struktury danych:
• zdefiniowanie informacji (danych), które będą przechowywane
• zdefiniowanie operacji wykonywanych na danych
Wybór struktury danych zależy od powyższych czynników
i determinuje funkcjonalność struktury.
Lista liniowa – ciąg n ≥ 0 elementów X[1], X[2], .., X[n],
w którym względna pozycja elementu zdefiniowana jest
w porządku liniowym.
Dla n > 0 X[1] jest pierwszym elementem, X[n] ostatnim
i jeśli 1 < k < n, to k-ty element X[k] leży za elementem X[k-1]
i przed elementem X[k+1].
Listy
Podstawowe operacje na liście:
• dostęp do k-tego elementu listy. Cel: odczyt lub modyfikacja
zawartości pól elementu
• wstawianie nowego elementu przed lub po k-tym elemencie
• usuwanie k-tego elementu
• wyznaczenie liczby elementów listy
• znajdowanie elementu listy o zadanej wartości jednego z pól
Stos (ang. LIFO)– lista liniowa, dla której operacje wstawiania i
usuwania (oraz odczytu) elementu dotyczą tylko jednego końca
listy
Kolejka (ang. FIFO)– lista liniowa, dla której operacje wstawiania
dotyczą jednego końca, a operacje usuwania (i odczytu) drugiego
końca
Kolejka dwustronna – lista liniowa, dla której wszystkie operacje
wstawiania i usuwania (i odczytu) dotyczą dowolnego końca listy
Wstawianie
lub
zdejmowanie
Usuwanie
Wstawianie
wierzchołek
pierwszy
ostatni
Kolejka
Wstawianie
lub usuwanie
Stos
Wstawianie
lub usuwanie
dno
lewy
prawy
Kolejka dwustronna
Tablice jednowymiarowe (wektory)
Służą do przechowywania w pamięci określonej (skończonej) liczby obiektów
tego samego typu
Tablice dwuwymiarowe (macierze)
Służą do przechowywania w pamięci określonej (skończonej) liczby obiektów
tego samego typu
Przykład:
Tablica o nazwie M, o 5-ciu wierszach i 10-ciu kolumnach i elementach całkowitych
Przykład:
10-cio elementowa tablica liczb całkowitych o nazwie T
element M[4][3]
kolumna
1
indeks elementu w tablicy T
2
3
4
5
6
7
8
9
10
1
1
2
3
4
5
6
7
8
9
10
-8
7
-20
1
7
9
-34
12
5
3
2
3
wiersz
4
27
5
element tablicy T
Odwołanie się do elementu o indeksie i i j tablicy M: M[i][j], np.
wypisz(M[i][j]); //wypisz wartość elementu z wiersza i i kolumny j
Odwołanie się do i-tego elementu tablicy T: T[i], np.
tablicy T
wypisz(T[i]); //wypisz wartość i-tego elementu tablicy T
T[i] ← 8;
//i-temu elementowi tablicy T przypisz wartość 8
Tablice dwuwymiarowe – cd.
Każdą tablicę dwuwymiarową można przekształcić w tablicę jednowymiarową:
Niech M – tablica dwuwymiarowa o n – wierszach i m – kolumnach,
T tablica jednowymiarowa o k = n*m elementach
Wtedy ∀ i=1..n, j=1..m M[i][j] = T[m*(i-1)+j]
Tablice wielowymiarowe
Niech wymiar tablicy X będzie równy 3. Tablica tworzy wtedy prostopadłościan,
a element jest wskazywany przez 3 indeksy: X[i][j][k]
Wektor wektorów – struktura złożona z wektora, którego elementy wskazują na
wektory różnej długości.
element
element
element
wskaźnik
element
element
element
element
element
.....
.....
...
wskaźnik
wskaźnik
element
element
element
M[i][j] ← 27;
//elementowi tablicy M o indeksie i i j przypisz
//wartość 27
•Jeżeli n = m, gdzie n – liczba wierszy, m – liczba kolumn tablicy
dwuwymiarowej, to tablicę nazywamy kwadratową.
Przekątna główna tablicy kwadratowej: indeksy wiersza i kolumny są równe
(i=j)
Realizacja listy liniowej – tablice (1)
Metoda najprostsza: umieszczenie elementów listy liniowej w
kolejnych komórkach (lokacjach) pamięci:
Add(X[i+1]) = Add(X[i]) + c
Add – funkcja zwracająca adres początku elementu listy
c – liczba słów na jeden element listy
Jeśli L0 – adres bazowy „hipotetycznego” elementu X[0], to
Add(X[i]) = L0 + ci
Najczęściej za pomocą tablicy realizowany jest stos.
Zmienna T nazywana jest wskaźnikiem stosu.
Operacje na stosie:
– stos pusty
T=0
T ← T + 1; X[T] ← Y – wkładanie elementu Y na stos
Y ← X[T]; T ← T – 1 – zdejmowanie elementu ze stosu,
gdy stos jest niepusty
Realizacja listy liniowej – tablice (3)
Realizacja listy liniowej – tablice (2)
Realizacja kolejki lub kolejki dwustronnej.
Przechowywane są dwa wskaźniki: F (front) i R (rear).
Operacje na kolejce dwustronnej:
F=R=0
– kolejka pusta
R ← R + 1; X[R] ← Y – wkładanie elementu Y na koniec kolejki
Y ← X[F]; F ← F + 1– usuwanie elementu z początku kolejki
Usprawnienie reprezentacji kolejki dwustronnej (lepsze
wykorzystanie pamięci, problem „przetaczającej się” kolejki):
X[1], .., X[M] – elementy ustawione w cykl, tak, że po X[M]
następuje element X[1]. Wtedy operacje mają postać:
jeśli R=M, to R ← 1, wpp R ← R + 1; X[R] ← Y
Y ← X[F]; jeśli F=M, to F ← 1, wpp F ← F + 1;
Lista – realizacja wskaźnikowa
First
p2
p2
p2
p2
p3
p3
p3
p3
p4
p4
p4
p4
Problem przepełnienia (overflow, nadmiar elementów)
Problem niedomiaru (underflow, brak elementów)
Postać operacji dla stosu i kolejki dwustronnej:
X ← Y (włóż na stos)
T ← T+1;
jeśli T > M, to przepełnienie;
X[T] ← Y;
Y ← X (usuń ze stosu)
jeśli T=0, to niedomiar;
Y ← X[T];
T ← T–1;
X ← Y (wstaw do kolejki)
jeśli R=M, to R ← 1, wpp R ← R+1;
jeśli F=R, to przepełnienie;
X[R] ← Y;
Y ← X (usuń z kolejki)
jeśli F=R, to niedomiar;
Y ← X[F];
jeśli F=M, to F ← 1, wpp F ← F+1;
Porównanie realizacji listy liniowej z wykorzystaniem tablicy i wskaźników
• Struktura ze wskaźnikami wymaga dodatkowego pola na przechowywanie
wskaźnika.
• Operacja usunięcia elementu z listy jest prosta – wymaga jedynie zmiany
wskaźnika w odpowiednim elemencie. W przypadku sekwencyjnego przydziału
pamięci operacja ta wymaga przemieszczenia całego fragmentu listy do innych
lokacji pamięci.
First
Program wykorzystujący listę wskaźnikową musi pamiętać wskaźnik do
pierwszego elementu list First.
p2
p3
p4
p2
p3
p4
p2
p3
p4
p2
p3
p4
p2
p3
p4
•Wstawianie elementu w środek listy wskaźnikowej jest prostą operacją.
Wymaga zmiany wskaźników w dwóch elementach.
p2
p3
p4
First
Porównanie realizacji listy liniowej z wykorzystaniem tablicy i wskaźników
– cd.
• Odwołania do dowolnego elementu listy jest szybsze w przypadku tablic.
Dostęp do k-tego elementu listy w postaci tablicy jest stały, dla listy
wskaźnikowej wymaga k przejść po wskaźnikach.
• Operacja łączenia list wskaźnikowych jest prostsza niż list przy użyciu tablic.
• Lista wskaźnikowa umożliwia budowę skomplikowanych struktur, np. zmienna
liczba list o zmiennej długości: element listy „głównej” jest wskaźnikiem do listy
podrzędnej, lub elementy struktury mają wiele dowiązań i połączone są
równocześnie w różnych porządkach, odpowiadając różnym listom.
• Operacje przeglądania kolejnych elementów listy są szybsze dla list
sekwencyjnych.
• Do tworzenia listy wskaźnikowej niezbędny jest mechanizm przydzielania,
zwalniania, sprawdzania, czy można pamięć przydzielić, czyli gospodarowania
pamięcią.
• Sterta – zbiór wszystkich elementów przeznaczonych do dynamicznego
przydzielania.
Uwaga: Zakłada się, że element listy ma postać:
info
link
p2
p3
p4
p2
p3
p4
p2
p3
p4
p2
p3
p4
p2
p3
p4
Stos – realizacja poprzez listę wskaźnikową.
Zmienna wskaźnikowa T – wskazuje na wierzchołek stosu.
T=Λ – stos pusty
Włożenie informacji Y na stos T (wykorzystanie dodatkowej
zmiennej wskaźnikowej P):
P ← new (element);
info(P) ← Y;
link(P) ← T;
T ← P;
T
Przypisanie informacji do Y z wierzchołka stosu i zdjęcie ze stosu tej informacji:
jeśli
T =Λ to niedomiar;
wpp{ P ← T;
T ← link(P);
Y ← info(P);
delete(P);
}
Kolejka – realizacja poprzez listę wskaźnikową.
Lista cykliczna – ostatni element listy wskazuje na pierwszy element.
F
PTR
R
Kolejka pusta:
F=Λ i R=Add(F);
Podstawowe operacje na listach cyklicznych:
PTR = Λ – lista pusta
Operacja wstawiania nowego elementu do kolejki:
P ← new(element);
F
info(P) ← Y;
link(P) ← Λ;
link(R) ← P;
R ← P;
R
P, nowy element
Operacja usuwania elementu z kolejki:
jeśli F=Λ to niedomiar;
F
wpp{ P ← F;
F ← link(P);
Y ← info(P);
delete(P);
jeśli F=Λ to R=Add(F);}
R
Drzewa
Drzewo jest hierarchicznym ułożeniem danych.
DEF. Drzewo jest to zbiór T jednego lub więcej elementów zwanych węzłami,
takich że:
1. istnieje jeden wyróżniony węzeł zwany korzeniem drzewa
2. pozostałe węzły (bez korzenia) są podzielone na m ≥ 0 rozłącznych zbiorów
T1, .., Tm, z których każdy jest drzewem. Drzewa T1, .., Tm są nazywane
poddrzewami korzenia.
Wstaw element Y z lewej strony:
P ← new(element);
info(P) ← Y;
jeśli PTR=Λ to PTR ← link(P) ←P;
wpp{ link(P) ← link(PTR);
link(PTR) ← P;
}
Wstaw element Y z prawej strony:
Wstaw Y z lewej strony;
PTR ← P;
Drzewa binarne
Drzewo binarne jest skończonym zbiorem węzłów, który jest albo pusty, albo
zawiera korzeń oraz dwa drzewa binarne.
T
AA
B
Pierwszy obiekt zwany jest korzeniem, kolejne obiekty traktowane są jako jego
potomstwo: węzły, liście – węzły nie mające potomstwa.
Droga w drzewie – sekwencja węzłów
w drzewie odpowiadających przejściu
w kierunku od korzenia do liścia.
Usuń z listy lewy element:
jeśli PTR=Λ to niedomiar
wpp{ P ← link(PTR);
Y ← info(P);
link(PTR) ← link(P);
jeśli PTR=P to PTR ← Λ;
delete(P);
A
C
B
D
E
korzeń
E
F
F
węzeł
a
og
dr
Pojęcia:
• rodzic
liść
• przodek
• potomek
• rodzeństwo (dwa węzły są rodzeństwem, gdy mają tego samego ojca)
Przechodzenie drzewa
Jest to systematyczne przeglądanie węzłów w taki sposób, ze każdy węzeł jest
odwiedzony dokładnie jeden raz.
Przejście drzewa wyznacza porządek liniowy w drzewie.
• Każdy węzeł przechowuje dwa wskaźniki: do lewego poddrzewa LLINK
i prawego poddrzewa RLINK
• T jest wskaźnikiem do drzewa
• Jeśli T = Λ - drzewo puste
Wpp T jest adresem korzenia drzewa, a LLINK(T) wskazuje lewe poddrzewo,
RLINK(T) wskazuje prawe poddrzewo.
Przykład:
AA
B
Sposoby przechodzenia drzewa binarnego:
• preorder (porządek przedrostkowy)
• inorder (porządek wrostkowy)
• postorder (porządek przyrostkowy)
Rekurencyjna definicja porządków przechodzenia drzewa binarnego:
Jeśli drzewo jest puste, stop
Wpp wykonaj:
Przechodzenie preorder
Przechodzenie inorder
Odwiedź korzeń
Przejdź lewe poddrzewo
Przejdź lewe poddrzewo
Odwiedź korzeń
Przejdź prawe poddrzewo
Przejdź prawe poddrzewo
Przechodzenie postorder
Przejdź lewe poddrzewo
Przejdź prawe poddrzewo
Odwiedź korzeń
C
D
D
C
E
F
G
Porządek preorder:
ABDCEGFHI
Porządek inorder:
DBAEGCHFI
Porządek postorder:
DBGEHIFCA
H
I
Algorytm: przechodzenie drzewa binarnego w porządku inorder
Niech T będzie wskazuje na drzewo binarne. Algorytm korzysta z pomocniczego
stosu S.
K1. Inicjalizowanie. Utwórz stos pusty S;
P ← T (P jest pomocniczą zmienną wskaźnikową).
K2. Sprawdzenie, czy P = Λ?
Jeśli P = Λ, to K4.
K3. S ← P (włóż P na stos S);
AA
Niech P ← LLINK(P);
Idź do K2.
B
C
K4. Jeśli stos S = Λ, koniec
algorytmu;
Wpp P ← S;
D
E
F
K5. Odwiedzenie P.
Odwiedź NODE(P);
G
H
I
P ← RLINK(P);
Idź do K2.
Przykłady wykorzystania drzew:
• drzewiasta struktura algorytmów
• diagramy organizacyjne przedsiębiorstw, drzewa gry
Sortowanie drzewiaste
Rozważamy drzewo binarne – każdy węzeł ma co najwyżej dwóch potomków,
zwanych lewostronnym i prawostronnym.
Algorytm sortowania drzewiastego:
1. przekształć listę wejściową w binarne drzewo poszukiwań T
2. obejdź drzewo T w porządku inorder i wypisz każdy element
przy okazji drugich odwiedzin.
Binarne drzewo poszukiwań T: każdy element binarnego drzewa
poszukiwań ma tę własność, że jego lewostronne potomstwo jest mniejsze co do
wartości od tego elementu, a prawostronne potomstwo jest większe.
procedura obejdz_drzewo(T){
if(T==0) koniec; //jeśli drzewo T jest puste
else{
obejdz_drzewo(lewe(T));
wypisz(korzen(T)); //wpisz element danych znajdujący się w korzeniu
obejdz_drzewo(prawe(T)); }
}
Przykład sortowania drzewiastego (etap 1)
Przykład sortowania drzewiastego (2)
Budowa binarnego drzewa poszukiwań T
128
76
106
402
100
46
354
1018
Procedura obejdz_drzewo(T)
112
28
396
128
35
76
402
128
76
46
402
106
28
46
106
354
354
100
112
1018
396
1018
35
28
100
112
396
35
Bazy danych i bazy wiedzy
Przykłady baz danych:
• dane finansowe i osobowe przedsiębiorstwa
• dane katalogowe biblioteki
• rezerwacja biletów lotniczych
Podstawowe modele baz danych
• relacyjny – organizacja danych w postaci tabel
• hierarchiczny – organizacja danych w postaci drzew lub sieci
(realizacja obiektowa)
Rozwinięciem baz danych są bazy wiedzy
128
46
76
28
28
35
35
35
28
46
46
76
106
100
100
100
106
112
112
112
106
76
128
402
354
354
396
396
396
354
402
1018
1018
1018
402
128