background image

1

Wykład XIV

Tablice, rekordy i zbiory

Podstawy informatyki
Semestr II Elektrotechnika

background image

2

Tablica

Tablica 

(ang. 

array) 

jest 

prawdopodobnie 

najbardziej  znaną  strukturą  danych,  ponieważ  w 
wielu  językach,  jest  jedyną  bezpośrednio  dostępną 
strukturą.
Tablica  jest  strukturą  jednorodną;  jest  złożona  ze 
składowych  tego  samego  typu  zwanego  typem 
podstawowym.
Tablicę  zwie  się  również  strukturą  o  dostępie 
swobodnym  
(ang.  random  access);  wszystkie 
składowe mogą być wybrane w dowolnej kolejności i 
są jednakowo dostępne.

background image

3

Definiowanie tablicy

W celu wybrania pojedynczej składowej nazwę 
całej  struktury  uzupełnia  się  tzw.  indeksem 
wybierającym  składową.  Indeks  ten  powinien 
być  wartością  pewnego  typu  zwanego  typem 
indeksującym 
(ang. index type) tablicy.
Definicja  typu  tablicowego  T  zawiera  więc 
zarówno  specyfikację  typu  podstawowego  T

0

jak i typu indeksującego I.

type T = array[I] of T

0

background image

4

Przykłady definiowania 

tablic

type  Wiersz  =  array  [1..5] 

of real

type  Karta  =  array  [1..80] 

of char 

type  alfa  =  array  [1..10]  of 

char

background image

5

Tablica typu Wiersz

Konkretną  wartość 

zmiennej

var x: Wiersz

której 

każda 

składowa 

spełnia 

równanie 

x

i

=2

-t

można  zobrazować 

tak,  jak  pokazano 

na rysunku

X

1

0.5

X

2

0.25

X

3

0.125

X

4

0.0625

X

5

0.03125

background image

6

Konstruktor tablicowy

Złożoną  wartość  x  typu  T  
wartościach  składowych  c

1,

  ...,  c

n

 

można 

oznaczyć 

za 

pomocą 

konstruktora 

tablicowego 

instrukcji przypisania:

x := T(c

1

,...,c

n

)

background image

7

Selektor tablicowy

Operatorem  odwrotnym  do  konstruktora 

jest  selektor.  Służy  on  do  wybrania 

konkretnej składowej tablicy.
Dla  danej  zmiennej  tablicowej  x  selektor 

jest  oznaczony  nazwą  tablicy,  po  której 

występuje 

indeks 

wybierający 

odpowiednią składową:

x[i]

background image

8

Zmienna 

tablicowa=tablica 

zmiennych składowych

Działając  na  tablicach  (zwłaszcza  zaś  na  dużych),  stosuje 

się  technikę  selektywnego  aktualizowania  poszczególnych 

składowych  zamiast  konstruowania  całkowicie  nowych 

wartości  złożonych.  Wyraża  się  to  traktowaniem  zmiennej 

tablicowej 

jako 

tablicy 

zmiennych 

składowych 

umożliwieniem 

wykonywania 

przypisań 

wybranym 

składowym.

PRZYKŁAD

x[i]:= 0.125

Aczkolwiek  aktualizacja  selektywna  powoduje  zmianę 

jedynie  pojedynczej  składowej  wartości,  jednak  z 

koncepcyjnego  punktu  widzenia  musimy  przyjąć,  że 

zmienia się również całą wartość złożoną.

background image

9

Indeksy tablicy mogą być 

obliczane

Niezwykle ważne konsekwencje pociąga za sobą fakt, że 

indeksy  tablicy,  tzn.  „nazwy"  składowych  muszą  być 

elementami zdefiniowanego typu skalarnego.
Indeksy mogą być, obliczane, tzn. stała indeksowa może 

być  zastąpiona  wyrażeniem  indeksowym.  Wyrażenie 

to ma być obliczone, a jego wynik decyduje o tym, która 

składowa zostanie wybrana.
Wspomniana  powyżej  możliwość  stanowi  niezwykle 

mocne  narzędzie  programowania,  lecz  jednocześnie 

umożliwia 

popełnianie 

jednego 

najczęściej 

spotykanych  błędów:  wartość  wynikowa  może  znaleźć 

się  poza  przedziałem  określonym  jako  możliwy  zakres 

indeksu tablicy.

background image

10

Porównywanie tablic

Typ  indeksujący  powinien  być  typem  skalarnym,  tzn.  typem 

niezłożonym, na którym określona jest pewna relacja porządkująca. 

Jeśli typ podstawowy tablicy jest również typem uporządkowanym, 

to dostajemy naturalne uporządkowanie typu tablicowego.
Naturalne  uporządkowanie  dwóch  tablic  jest  zdeterminowane 

dwoma  odpowiadającymi  sobie  nierównymi  składowymi  o 

najniższych  możliwych  indeksach.  Formalnie  wyraża  się  to 

następująco:

– Dla danych dwóch tablic relacja x < y zachodzi wtedy i tylko 

wtedy, gdy istnieje indeks taki, że x[k]<y[k] oraz x[i]=y[i] dla 

wszystkich i<k.

– Na przykład

(2, 3, 5, 7, 9)

< (2, 3, 5, 7, 11) 

   'LABEL' <      'LIBEL'

background image

11

Moc typu tablicowego

W większości zastosowań nie zakłada się istnienia 
relacji porządkującej na typach tablicowych.
Moc  typu  złożonego  otrzymuje  się  jako  iloczyn 
mocy  jego  składowych.  Ponieważ  wszystkie 
składowe  typu  tablicowego  A  są  tego  samego 
typu podstawowego Botrzymujemy

moc(A) = (moc(B))

n

gdzie  n=moc(I),  I  zaś  jest  typem  indeksującym 
tablicy.

background image

12

Korzystanie z selektora 

tablicowego

Poniższy  krótki  program  ilustruje  użycie  selektora 

tablicowego. 

Zadaniem 

programu 

jest 

znalezienie 

najmniejszego  indeksu  i  składowej  o  wartości  x. 

Poszukiwania  dokonuje  się,  przeglądając  sekwencyjnie 

tablicę a, zadeklarowaną jako 

var a: array[1..N] of T; {N > 0}
i:=0;
repeat
  i := i+1
until (a[i] = x) or (i=N);
if a[i] <> x then ShowMessage(

’nie ma takiego elementu 

w a’

)

background image

13

Czasem pomoże 

wartownik

Inny  wariant  tego  programu  ilustruje  znaną 
metodę 

wartownikiem 

(ang. 

sentinel), 

ustawionym  na  końcu  tablicy.  Zastosowanie 
wartownika 

znacznie 

upraszcza 

warunek 

zakończenia iteracji.
var a: array[1. .N+1] of T;
i:=0; a[N+1]:=x;
repeat i:=i+1 until a[i]=x;
if  i>N  then  ShowMessage(’nie  ma  takiego 
elementu w a’);

background image

14

Aktualizacja selektywna,

niezmiennik pętli

Przypisanie 

a[N+1]:=x 

jest 

przykładem 

aktualizacji 

selektywnej 

(ang. 

selective 

updating),  tzn.  zmiany  wybranej  składowej 

zmiennej złożonej.
Niezależnie  od  tego,  jak  często  powtórzyło  się 

wykonanie  instrukcji  i:=i+1,  spełniony  jest 

warunek
a[j]<>x,  dla  j = 1... i - 1
Warunek  ten  jest  spełniony  w  obu  wersjach 

programu  i  nazywany  jest  niezmiennikiem 

pętli (ang. loop invariant).

background image

15

Metoda poszukiwania 

połówkowego

Jeżeli 

elementy 

tablicy 

zostały 

wcześniej 

uporządkowane 

(posortowane),  przeszukiwanie 

można  znacznie  przyspieszyć.  W  takim  przypadku 

najczęściej 

stosuje 

się 

metodę 

połowienia 

przedziału, 

którym 

ma 

się 

znajdować 

poszukiwany element.
Metodę 

tę, 

nazywa 

się 

przeszukiwaniem 

połówkowym  (przeszukiwaniem  binarnym;  ang. 

binary  search).  Przy  każdym  powtórzeniu  dzieli  się 

na  połowę  przedział  między  indeksami  i  oraz  j. 

Górną  granicą  wymaganej  liczby  porównań  jest 

log

2

(N)

background image

16

Przykład - Poszukiwanie 

połówkowe

i:=1;  j:=N;
repeat k:=(i+j) div 2;
   if x>a[k] then i:=k+1 else j:=k-1
until (a[k]=x) or (i>j)

Odpowiednim warunkiem niezmienniczym na wejściu 

do instrukcji iteracyjnej repeat jest

a[h]<x,  dla  h = 1..i –1

a[h]>x,  dla  h =j+1 .. N

W  związku  z  tym,  jeśli  wykonanie  programu  kończy 

się przy i>j, oznacza to, że nie istnieje a[h]=x takie, 

że 1hN. 

background image

17

Składowe typów 

tablicowych mogą być 

złożone

Składowe  typów  tablicowych  mogą  być  również 

złożone. Tablica, której składowe są również tablicami, 

jest zwana macierzą (ang. matrix). Np.

M: array[1..10] of Wiersz

jest  tablicą  o  dziesięciu  składowych  (wierszach),  z 

których każda składa się z pięciu składowych typu real, 

nazywa 

się 

macierzą 

10x5 

składowych 

rzeczywistych.
Selektory  mogą  być  konkatenowane  tak,  że

 

M[i][j]

 

oznacza  j-tą  składową  wiersza  M(i),  który  jest  i-tą 

składową macierzy M. Oznaczenie to skraca się zwykle 
do postaci 

M[i,j].

background image

18

Deklarowanie tablic 

wielowymiarowych

Podobnie deklaracja

M: array [1. .10] of array [1. .5] of 

real

może być napisana w sposób bardziej 
zwarty w postaci

M: array [1..10, 1..5] of real

background image

19

Pętla „dla” często przydaje 

się przy tablicach

Gdy  pewna  operacja  ma  być  wykonana  dla  wszystkich 

składowych  tablicy  (lub  kilku  kolejnych  składowych),  wygodnie 

jest  stosować  instrukcję  „dla",  co  ilustruje  przykład  (następny 

slajd).
Załóżmy, że ułamek f jest reprezentowany za pomocą tablicy d w 

ten sposób, że 

tzn.  przez  swoje  (k-1)-cyfrowe  rozwinięcie  dziesiętne.  Następnie 

ma  zostać  podzielone  przez  2.  Dokonuje  się  tego,  powtarzając 

operację  dzielenia  dla  wszystkich  k-1  cyfr,  począwszy  od  i=1. 

Operacja  ta  polega  na  podzieleniu  cyfry  przez  2,  z 

uwzględnieniem  ewentualnego  przeniesienia  z  poprzedniej 

pozycji i zachowaniem ewentualnej reszty r do następnego kroku. 

1

1

10

*

k

i

i

i

d

f

background image

20

Przykład - Reprezentacja 

dziesiętna ujemnych 

potęg dwójki

program potęga (output); 

{reprezentacja dziesiętna ujemnych potęg liczby 2}

{$APPTYPE CONSOLE}
const n=10;  type cyfra=0..9;  var i, k, r: integer; d: array [1. .n] of 

cyfra;

begin for k: = 1 to n do
   begin 
write ('.'); r:= 0;
     for i:=1 to k-1 do
       begin
         
r:=10*r+d[i]; d[i]:=r div 2; r:=r-2*d[i]; write(chr(d[i]+ord('0')))
      end;
    d[k]:=5; writeln('5')
  end
end.

background image

21

Przykład - Reprezentacja 

dziesiętna ujemnych 

potęg dwójki - wyniki

Postępowanie 

zastosowano 

programie  (poprzedni  slajd)  w  celu 

otrzymania  tablicy  ujemnych  potęg 

dwójki. 
Powtarzanie 

operacji 

połowienia 

służących  do  obliczenia  wartości  2

-1

2

-2

, ..., 2

-n

 jest ponownie wyrażone za 

pomocą  instrukcji  „dla",  "prowadząc 

do  zagnieżdżenia  dwóch  takich 

instrukcji. 
Wyniki  programu  dla  n  =  10 

przedstawiono obok.

.5
.25
.125
.0625
.03125
.015625
.0078125
.00390625
.001953125
.0009765625

background image

22

Rekordy

Najbardziej 

ogólną 

metodą 

tworzenia 

typów 

złożonych  jest  łączenie  w  typ  złożony  elementów  o 

dowolnych, być może złożonych typach.
Przykładami  z  matematyki  są  liczby  zespolone 

złożone 

dwóch 

liczb 

rzeczywistych 

bądź 

współrzędne  punktów  złożone  z  dwóch  lub  więcej 

liczb  rzeczywistych  w  zależności  od  wymiaru 

przestrzeni.
Przykładem  z  przetwarzania  danych  jest  opis  osoby 

za pomocą kilku istotnych cech charakterystycznych, 

takich jak imię, nazwisko, data urodzenia, płeć i stan 

cywilny.

background image

23

Iloczyn kartezjański

W  matematyce  taki  typ  złożony  zwie  się 
iloczynem kartezjańskim typów składowych.
Wypływa to z faktu, że zbiór wartości definiujący 
ten  typ  składa  się  ze  wszystkich  możliwych 
kombinacji  wartości  wziętych  odpowiednio  ze 
wszystkich typów składowych.
Liczba  takich  kombinacji  jest  równa  iloczynowi 
liczb  elementów  wszystkich  typów  składowych, 
czyli  moc  typu  złożonego  równa  jest  iloczynowi 
mocy typów składowych.

background image

24

Rekord znaczy zapis

W  przetwarzaniu  danych  typy  złożone,  takie  jak 
opisy  osób  czy  innych  obiektów,  służą  do 
zapisywania 

rejestracji 

ukierunkowanych 

problemowo charakterystyk tych osób czy obiektów;
Są  one  zazwyczaj  przechowywane  w  plikach  i 
„bankach(bazach)  danych”.  Fakt  ten  tłumaczy 
stosowanie angielskiego słowa record (zapis, rejestr, 
nagranie,  przechowywany  zestaw  informacji)  do 
oznaczania  tego  rodzaju  danych  zamiast  terminu 
„iloczyn kartezjański".

background image

25

Definiowanie typu 

rekordowego

Ogólnie,  typ  rekordowy  T  jest  zdefiniowany 

w następujący sposób:
type T = record
s

1

:  T

1

;

s

2

: T

2

;

...
s

n

: T

n

;

end
moc(T)=moc(T

1

) *... * moc (T

n

)

background image

26

Przykłady definicji typów 

rekordowych

type Zespolona = record 
  re:  real;
  im:  real
end

type Data=record
  dzien:  1.. 31;
  miesiac:  1..12;
  rok:  1..3000;
end

type Osoba = record
  nazwisko: String[50];
  imie: String[50];
  dataurodzenia: Data;
 

 

plec: 

(mezczyzna, 

kobieta);

    stancywilny:  (wolny, 

zonaty, 

owdowialy, 

rozwiedziony)

end

background image

27

Konstruktor rekordowy

Za 

pomocą 

konstruktora 

rekordowego 

można 

utworzyć 

wartość typu T, a następnie przypisać 
ją jakiejś zmiennej tego typu:

x:=T(x

1

, x

2

, ..., x

n

)

gdzie x

i

 są odpowiednio wartościami z 

typów składowych T

i

. 

background image

28

Zespolona z 

Data d 

Osoba p 

1.0 

WIRTH 

-1.0 

CHRIS 

1973 

18  1  1966 

mężczyzna 

 

 

 

 

wolny 

 

Przypisywanie danych

do zmiennych 

rekordowych

Dla danych
zmiennych
rekordowych

z: Zespolona
d: Data
p: Osoba

konkretne wartości mogą być przypisane następująco 
z:= Zespolona(1.0, -1.0)
d:= Data(1,4,1973)
p:= 

Osoba 

(‘WIRTH', 

‘CHRIS', 

Data(18,1,1966), 

mezczyzna, wolny)

background image

29

Selektory rekordowe

Identyfikatory  s

1

,...,  s

n

  wprowadzone  w 

definicji  typu  rekordowego  stanowią  nazwy 

przydzielone 

poszczególnym 

składowym 

zmiennych tego typu;
Stosuje  się  je  w  selektorach  rekordowych 

odnoszących sięs do zmiennych rekordowych.
Dla danej zmiennej x: Tjej i-ta składowa jest 

oznaczona przez

x.s

background image

30

Aktualizacja selektywna

Aktualizację  selektywną  x  prowadzi 
się 

przy 

użyciu 

tego 

samego 

oznacznika  selektora  stojącego  po 
lewej stronie instrukcji przypisania:

x.s

i

:=x

i

gdzie  x

i

  jest  wartością  (wyrażeniem) 

typu T

i

background image

31

Przykłady selektorów

Dla danych zmiennych rekordowych

z: Zespolona
d: Data
p: Osoba

selektory niektórych składowych są następujące:

z.im

(typu real)

d.miesiac

(typu 1..12)

p.nazwisko

(typu String[50])

p.dataurodzenia

(typu Data)

p.dataurodzenia.dzien

(typu 1..31)

background image

32

Typy złożone można 

składać

również z typów złożonych

Przykład typu Osoba dowodzi, że typy składowe 
rekordu  mogą  również  mieć  pewną  złożoną 
strukturę. Selektory można zatem składać.
Oczywiście  operację  składania  typów  o  różnych 
składowych  można  wykonywać  wielokrotnie 
(wielopoziomowo).  Na  przykład  j-ta  składowa 
tablicy 

a, 

będącej 

składową 

zmiennej 

rekordowej  r,  jest  oznaczana  przez  r.a[i]  
składowa  o  selektorze  s  i-tej  składowej 
rekordowej tablicy jest oznaczana przez a[i].s

background image

33

Poprawna definicja typu 

nie gwarantuje 

sensownych danych

Charakterystyczną  cechą  iloczynu  kartezjańskiego  jest 

to,  że  zawiera  on  wszystkie  kombinacje  elementów 

typów składowych.
Trzeba  jednak  pamiętać,  że  w  praktyce  nie  wszystkie 

muszą 

być 

„prawidłowe”, 

tzn. 

sensowne. 

Np. 

zdefiniowany  poprzednio  typ  Data  zawiera  mógłby 

zawierać  wartości  (31,4,1973)  i  (29,2,1815),  które 

odpowiadają datom nie istniejących nigdy dni.
Jak  widać,  definicja  tego  typu  nie  odzwierciedla  sytuacji 

rzeczywistej. 

Niemniej 

jednak 

praktycznie 

jest 

dostatecznie  bliska  rzeczywistości;  od  programisty 

zależy,  aby  bezsensowne  wartości  nigdy  nie  wystąpiły 

podczas wykonania programu.

background image

34

Przykład– korzystanie

ze zmiennych 

rekordowych

Przytoczony  poniżej  krótki  fragment  programu 

ilustruje  użycie  zmiennych  rekordowych.  Jego 

zadaniem  jest  zliczenie  „Osób”  reprezentowanych 

w tablicy jako kobiety stanu wolnego.

 

var a: array [1.. N] of Osoba;
licznik: integer; 
licznik:=0; for i:=1 to N do
if 
(a[i].plec=kobieta) and (a[i].stancywilny = wolny)
then licznik:=licznik+1

background image

35

Instrukcja wiążąca

W  innym  wariancie  powyższego  fragmentu  programu 

korzysta  się  z  konstrukcji  zwanej  instrukcją  wiążącą 

with:

  for i:=1 to N do

  with a[i] do
      if  
(plec=kobieta)  and  (stancywilny=wolny)  then 

licznik:=licznik+1

Konstrukcja  with  r  do  s  oznacza,  że  można  używać  nazw 

selektorów  z  typu  zmiennej  r  bez  poprzedzenia  ich  nazwą 

zmiennej, ponieważ wiadomo, że będą się do niej odnosiły. 
Użycie  instrukcji  with  skraca  więc  tekst  programu,  jak 

również  zapobiega  wielokrotnemu  obliczaniu  od  nowa 

składowej indeksowanej a[i].

background image

36

Rekordy vs. Tablice

Strukturę  rekordu  i  strukturę  tablicy  charakteryzuje 

wspólnie cecha „dostępu swobodnego”.
Rekord  jest strukturą  bardziej ogólną w tym  sensie, 

że  nie  ma  tu  wymagania,  aby  wszystkie  typy 

składowe były identyczne.
Jednakże  stosowanie  tablicy  zapewnia  większą 

elastyczność, 

ponieważ 

selektory 

składowych 

tablicy  mogą  być  wartościami  obliczanymi  w 

programie  (reprezentowanymi  przez  wyrażenia), 

podczas  gdy  selektory  składowych  rekordu  są 

sztywno 

ustalonymi 

identyfikatorami 

wprowadzonymi w definicji odpowiedniego typu.

background image

37

Rekordy z wariantami

W  praktyce  okazuje  się  zazwyczaj  wygodne  i 

naturalne  traktowanie  dwóch  typów  po  prostu  jako 

wariantów tego samego typu.
Na  przykład  typ  Wspolrzedne  można  traktować 

jako 

sumę 

dwóch 

wariantów, 

mianowicie 

współrzędnych 

kartezjańskich 

biegunowych, 

których  składowymi  są  odpowiednio  (a)  dwie 

wielkości liniowe i (b) wielkość liniowa i kątowa.
W  celu  rozpoznania  wariantu,  który  aktualnie  jest 

wartością zmiennej, wprowadza się trzecią składową 

zwaną 

wyróżnikiem 

typu 

albo 

polem 

znacznikowym.

background image

38

Przykład rekordu 

wariantowego

type Współrzędne =

record  case  rodzaj:  (kartezjanskie,  biegunowe) 

of
kartezjanskie: (x, y: real);
biegunowe: (r: real; kat: real)
end
W tym przypadku nazwą pola znacznikowego jest 

rodzaj, a nazwy współrzędnych stanowią albo x i 

- wartości współrzędnych kartezjańskich, albo r 

kat - wartości współrzędnych biegunowych.

background image

39

Zbiór wartości typu i jego 

moc

Zbiór  wartości  typu  Współrzędne  jest 
sumą dwóch typów:
T

1

 = (x, y: real);

T

2

 = (r: real; kat: real)

a jego moc jest sumą mocy T

1

 i T

2

background image

40

Rekordy o częściowo 

identycznych składowych

Bardzo  często  jednak  nie  mamy  do  czynienia  z  dwoma 

całkowicie  różnymi  typami,  lecz  raczej  z  typami  o 

częściowo identycznych składowych.
Fakt  ten  zadecydował  o  nazwie  takiego  typu  -  rekord  z 

wariantami (ang. variant record).
Przykładem  jest  typ  Osoba  zdefiniowany  na  jednym  z 

poprzednich  slajdów,  w  którym  informacje  mogłyby 

zależeć od płci osoby.
Na  przykład  dla  mężczyzny  charakterystycznymi 

informacjami  mogą  być  jego  waga  oraz  to,  czy  jest 

brodaty,  podczas  gdy  dla  kobiety  informacjami  tymi 

mogą  być  trzy  charakterystyczne  wymiary  figury 

(natomiast waga może pozostać nieujawniona).

background image

41

Przykład – nowa definicja 

typu osoba

Definicja takiego typu wyglądałaby więc następująco:
type Osoba=

record
    
nazwisko, imie: String[50];
    dataurodzenia: data;
    stancywilny: (wolny, zonaty, owdowialy, rozwiedziony);
  
case plec: (mezczyzna, kobieta) b
mężczyzna:

(waga: real;

brodaty: Boolean);
kobieta: (wymiary: 
array [1..3] of integer)
end

background image

42

Ogólna postać definicji 

rekordu z wariantami 

type T =

record  s

1

: T

1

;...; s

n-1

: T

n-1

;

  case s

n

: T

n

 of

c

1

: (s

1,1

: T

1,1

; ...; s

1,n1

: T

1,n1

);

……………………………….
c

m

: (s

m,1

: T

m,1

; ...; s

m,nm

: T

1,nm

);

end
Identyfikatory s

i

 s

ij

 są nazwami składowych dla typów T

i

 T

ij

s

n

 

jest  nazwą  wyróżniającego  pola  znacznikowego  o  typie  T

n

.  Stałe 

c

1

...c

m

 oznaczają wartości typu (skalarnego) T

n

Zmienna  x  typu  T  zawiera  składowe  x.s

1

,  x.s

2

,  …,  x.s

n

,  x.s

k,1

,  ..., 

x.s

k,nk 

wtedy  i  tylko  wtedy,  gdy  (bieżąca)  wartość  x.s

n

  jest  równa 

c

k

Składowe x.s

1

, ..., x.s

n

 tworzą część wspólną wariantów.

background image

43

Brodata pani

Wynika  stąd,  że  użycie  selektora  składowej 

x.s

k,h

 

(1≤hn

k

), 

gdy 

x.s

n

≠c

k

należy 

traktować  jako  poważny  błąd  programu, 

gdyż 

może 

to 

prowadzić 

do 

wielu 

paradoksalnych konsekwencji.
Dla  zdefiniowanego  poprzednio  typu  Osoba 

może to spowodować np.

– zapytanie, czy pani jest brodata,
– lub (w przypadku aktualizacji selektywnej) 

żądanie, aby taką była.

background image

44

Jeśli chcemy uniknąć 

problemów dobrze jest 

skorzystać z instrukcji 

wyboru

Jak  widać,  rekordy  z  wariantami  wymagają  niezwykle 

uważnego  programowania.  Odpowiednie  operacje  na 

poszczególnych  wariantach  najlepiej  grupować  w 

instrukcję  wybiórczą,  tzw.  instrukcję  wyboru,  której 

struktura  odzwierciedla  strukturę  definicji  rekordu  z 

wariantami.

case x.s

n

 of

c

1

: S

1

;

c

2

: S

2

;


c

m

: S

m

;

end

background image

45

Przykład – obliczanie 

odległości pomiędzy 

dwoma punktami 

Przytoczony 

dalej 

fragment  programu  ma 

za  zadanie  obliczenie 

odległości 

między 

punktami 

zadanymi 

postaci 

zmiennych  a  i  b  typu 

Wspolrzedne,  będącego 

rekordem z wariantami. 

Procedura obliczeń jest odpowiednio odmienna dla każdej 

z czterech możliwych kombinacji określania zmiennych za 

pomocą współrzędnych kartezjańskich lub biegunowych.

background image

46

Kod realizujący zadanie z 

przykładu

case a.rodzaj of

kartezjanskie:case b.rodzaj of
kartezjanskie: d:=sqrt(sqr(a.x-b.x)+sqr(a.y-b.y));
biegunowe:d:=sqrt(sqr(a.x-b.r*cos(b.kat))+sqr(a.y-

b.r*sin(b.kat)))

         end;

biegunowe: case b.rodzaj of
kartezjanskie: 

d:=sqrt(sqr(a.r*sin(a.kat)-b.x)

+sqr(a.r*cos(a.kat)-b.y))
biegunowe: d:=sqrt(sqr(a.r)+sqr(b.r)-
2*a.r*b.r*cos(a.kat-b.kat))

         end
end

background image

47

Zbiory

Trzecią  podstawową  strukturą  danych  -  oprócz 

tablicy i rekordu - jest struktura zbioru (ang. set 

structure).  Definiuje  się  ją  za  pomocą  deklaracji  o 

podanej poniżej postaci:

type T = set of T

0

Wartościami  zmiennej  x  typu  T  są  zbiory 

elementów typu T

0

.

Zbiór 

wszystkich 

możliwych 

podzbiorów 

elementów  T

0

  nazywa  się  zbiorem  potęgowym 

T

0

W związku z tym typ stanowi zbiór potęgowy 

swego typu podstawowego T

0

. 

background image

48

Przykłady typów 

zbiorowych

type zbiorcalk

set of 0..30

type zbiorznakow set of char
type koloryteczy set of kolor

Podstawę 

dla 

drugiego 

przykładu 

stanowi 

standardowy  zbiór  znaków  oznaczony  typem  char, 

podstawą  dla  trzeciego  przykładu  jest  zbiór  kolorów, 

który można zdefiniować jako typ skalarny

type  kolor=(zolty,  pomaranczowy,  czerwony, 

zielony,  niebieski, fioletowy)

opisujący różne kolory, jakie mogą wchodzić w skład 

tęczy.

background image

49

Przypisywanie wartości 

zmiennym typu 

zbiorowego

Dla danych zmiennych
zc 

zbiorcalk

zz 

 

zbiorznakow

t : array [1. .6] of koloryteczy
można  wykonać  przypisania  dla  poszczególnych  wartości 

typu zbiorowego:
zc:= [1, 4, 9, 16, 25]    zz := ['+','-','*','/']
t[3]

:

 = [zolty]     t[5]=[ ]

         t[6]=[czerwony..fioletowy]

Wartość 

przypisania 

zmiennej 

t[3] 

stanowi 

zbiór 

jednoelementowy  zawierający  pojedynczy  element  zolty; 

zmiennej t[5] jest przypisany zbiór pusty, co  oznacza, że w 

skład  piątej  tęczy  nie  wchodził  żaden  kolor  (nie  istniała?), 

natomiast zmiennej t[6] przypisano zbiór złożony z czterech 

spośród możliwych kolorów.

background image

50

Moc typu zbiorowego

Moc typu zbiorowego T jest określona wzorem 

Wzór  ten  wynika  bezpośrednio  z  faktu,  że  każdy  z 

elementów T

0

 musi być reprezentowany przez jedną 

z  dwóch  wartości:  „jest”  lub  „nie  ma”  oraz  stąd,  że 

wszystkie elementy są wzajemnie niezależne.
Dla efektywnej i ekonomicznej realizacji jest istotne, 

aby  typ  podstawowy  był  nie  tylko  skończony,  ale 

aby jego moc była stosunkowo niewielka.

 

 

0

2

T

moc

T

moc 

background image

51

Elementarne działania na 

zbiorach

Na  wszystkich  typach  zbiorowych  są  określone 

następujące operatory elementarne:

*

przecięcie zbiorów

+

suma zbiorów

-

różnica zbiorów

in

przynależność do zbioru

background image

52

Przykłady działań na 

zbiorach

Konstruowanie  przecięcia  (iloczynu)  i  sumy  zbiorów 

nazywa  się  też  często,  odpowiednio,  mnożeniem  i 

dodawaniem zbiorów.
Zgodnie z tą analogią określa się też priorytety operatorów 

zbiorowych:  największy  priorytet  otrzymuje  operator 

przecięcia  zbiorów,  następnie  -  operator  sumy  i  różnicy, 

najmniejszy  zaś  priorytet  -  operator  przynależności  do 

zbioru, klasyfikowany na równi z operatorami relacyjnymi.
Poniżej  podano  przykłady  wyrażeń  zbiorowych  i  ich 

odpowiedników z nawiasami:
r*s+t=(r*s)+t r-s*t=r-(s*t)
r-s+t=(r-s)+t x in s+t=x in (s+t)

background image

53

Podstawowe statyczne 

złożone struktury danych

Strukt

ura

Deklaracja Selektor

Dostęp do 

składowych

Typ 

składwy

ch

Moc

Tablica 

a: array [/] 

of T

0

a[i]
(iI)

Selektor 

obliczanym 

indeksem i 

Wszystk

ie 

jednako

we (T

0

)

moc(T

0

)

m

oc(l)

 

Rekord 

r: record
    
s

1

: T

1

;

    ...
    s

n

: T

n

;

  end 

r.s
(s[s

1

,...,

s

n

]) 

Selektor 

deklarowaną 

nazwą 

składowej s 

Mogą 

być 

różne 

Zbiór 

s : set of 

T

0

 

nie 

istnieje

Test 

przynależność 

za 

pomocą 

operatora 

relacyjnego in 

Wszystk

ie 

jednako

we 

(typu 

T

0

) 

 

n

i

i

T

moc

1

 

0

2

T

moc


Document Outline