Rozdział 7
ZBIORY
7.1. Wprowadzenie
Język Pascal umożliwia wykorzystywanie w programach zbiorów teorio-
mnogościowych, których elementy muszą należeć do pewnego określonego
typu.
Typ zbiorowy definiujemy w sposób następujący:
type nazwa = set of nazwa_typu ;
gdzie nazwa jest nazwą typu zbiorowego, a nazwa_typu jest nazwą tzw.
typu podstawowego, który stanowi elementy zbioru (może to być typ integer,
char, boolean, wyliczeniowy lub okrojony). Wartościami zmiennych typu
zbiorowego są zatem wszystkie zbiory, które można utworzyć z wartości
typu podstawowego oraz zbiór pusty (pusty nie zawiera żadnego elementu).
Wartości zmiennym typu zbiorowego nadajemy przy pomocy tzw. konst-
ruktora zbioru, którym jest para nawiasów prostokątnych [], wewnątrz
których wpisujemy wartości typu podstawowego.
Przykład
type
abc = 'a'..'c';
trzylitery = set of abc;
var
x: trzylitery;
Utworzono typ zbiorowy o nazwie trzylitery (typem podstawowym są
litery 'a','b','c') oraz zadeklarowano zmienną x typu trzylitery.
Wartościami zmiennej x mogą być wszystkie podzbiory zbioru { 'a','b','c' }
oraz zbiór pusty. Poniżej wypisano wszystkie możliwe przypisania wartości
zmiennej x przy pomocy konstruktora zbioru [].
x := [];
x := ['a'];
x := ['b'];
x := ['c'];
x := ['a','b'];
x := ['a','c'];
x := ['b','c'];
x := ['a','b','c'];
Zauważmy jeszcze, że definicję typu zbiorowego można zawrzeć bezpo-
średnio w deklaracji zmiennej x:
var
x: set of 'a'..'c';
Przykład
type
podstawa = 1..10;
zbiorliczb = set of podstawa;
var
pelny, x, pusty : zbiorliczb;
Zadeklarowano zmienne pelny, x, pusty typu zbiorowego, których warto-
ściami mogą być dowolne podzbiory zbioru {1,...,10}. Wartości tym zmiennym
przypiszemy w sposób następujący:
pelny := [1..10];
x := [3,5,7,9];
pusty := [];
Wartością zmiennej pelny jest zbiór liczb {1,...,10}, wartością zmiennej x
jest zbiór liczb {3,5,7,9}, a zmiennej pusty jest zbiór pusty, który nie
zawiera żadnego elementu.
Powyższy przykład ilustruje między innymi definicję tak zwanego zbioru
pełnego, czyli takiego, który zawiera wszystkie elementy ze zdefiniowanego
typu podstawowego. Warto zwrócić uwagę, że zarówno zbiór pełny jak i
zbiór pusty są szeroko wykorzystywane w wielu programach, w których
operuje się na zbiorach.
7.2. Operacje na zbiorach
Język Pascal umożliwia wykonywanie następujących operacji na zbio-
rach:
| Operator | Znaczenie |
| + | suma zbiorów |
| - | różnica zbiorów |
| * | część wspólna zbiorów |
Należy również zwrócić uwagę na operator in, który umożliwia stwier-
dzenie, czy dany element należy do zbioru. Można też wykorzystywać opera-
tory relacyjne:
| Operator | Znaczenie |
| = | równość zbiorów |
| <> | nierówność zbiorów |
| <= oraz => | zawieranie się zbiorów |
Obecnie dla przypomnienia podamy definicję sumy, różnicy i iloczynu
zbiorów. Sumą zbiorów A oraz B jest zbiór, którego elementy należą do
zbioru A lub do zbioru B. Iloczynem zbiorów A oraz B jest zbiór, którego
elementy należą do zbioru A i do zbioru B. Natomiast różnicą zbiorów A
oraz B jest zbiór, którego elementy należą do zbioru A, ale nie należą do
zbioru B. Wszystkie zdefiniowane operacje na zbiorach ilustruje poniższy
przykład.
Przykład
Rozważmy następujący zbiór artykułów sportowych:
{ narty, kijki, buty_nar, łyżwy, sanki, rakiety, piłki, płetwy, okulary_pływ,
rowery, motocykle}
Następnie przypuśćmy, że sklep A sprzedaje następujące artykuły:
{ narty, kijki,buty_nar,rakiety,piłki }
a sklep B sprzedaje poniżej wymienione artykuły:
{ rakiety,piłki,płetwy,okulary_pływ }
Powyższe dane możemy w programie zapamiętać przy pomocy struktury
danych postaci:
type
artyk = (narty,kijki,buty_narc,lyzwy,sanki,rakiety,
pilki,pletwy,okul_plyw,rowery,motocykle);
zbiorartyk = set of artyk;
var
sklep_A, { artykuły sprzedawane przez sklep A }
sklep_B, { artykuły sprzedawane przez sklep B }
wszystkie, { wszystkie artykuły }
x { zmienna robocza wykorzystywana do
przechowywania informacji o obu sklepach }
: zbiorartyk;
Zmiennym wszystkie, sklep_A, sklep_B powinny być nadane następujące
wartości:
wszystkie := [narty..motocykle];
sklep_A := [narty..pilki];
sklep_B := [rakiety..okul_plyw];
Przy pomocy tych zmiennych oraz poszczególnych operatorów możemy
otrzymywać informacje o artykułach sportowych, co ilustruje poniższa
tabela:
wyrażenie wartość zmiennej x
1) x := sklep_A + sklep_B
[narty..okul_plyw]
2) x :=
sklep_A * sklep_B
[rakiety,pilki]
3) x := sklep_A - sklep_B
[narty..sanki]
4) x :=
sklep_B - sklep_A
[pletwy,okul_plyw]
5) x :=
wszystkie - sklep_A
[pletwy..motocykle]
6) x :=
wszystkie - sklep_B
[narty..sanki,rowery,motocykle]
7) x :=
wszystkie - sklep_A - sklep_B
[rowery,motocykle]
Znaczenie wartości poszczególnych wyrażeń jest następujące:
1) artykuły dostępne w jednym lub drugim sklepie
2) artykuły dostępne w obu sklepach
3) artykuły dostępne w sklepie A i niedostępne w sklepie B
4) artykuły dostępne w sklepie B i niedostępne w sklepie A
5) artykuły niedostępne w sklepie A
6) artykuły niedostępne w sklepie B
7) artykuły niedostępne w żadnym sklepie
Program ilustrujący przetwarzanie informacji o artykułach sprzedawa-
nych w dwóch sklepach sportowych zostanie zamieszczony w następnym
podrozdziale.
7.3. Podstawowe algorytmy
W niniejszym podrozdziale podamy podstawowe algorytmy, które umoż-
liwiają wykonywanie operacji na zbiorach.
Przede wszystkim zilustrujemy podstawowe operacje, a mianowicie
wprowadzanie i wyprowadzanie danych ze zmiennych typu zbiorowego.
Jeżeli typem podstawowym nie jest typ wyliczeniowy, to wczytanie i
wydruk wartości zmiennej typu zbiorowego odbywa się względnie prosto.
Zilustrujemy to na przykładzie zmiennych o poniższej deklaracji:
type
zbiorliczb = set of 1..100;
var
x,y: zbiorliczb;
Przypomnijmy, że przy takiej deklaracji wartościami zmiennych x i y
mogą być wszystkie podzbiory zbioru { 1,...,100 } łącznie ze zbiorem pustym.
Procedura CzytajZbior pozwala na wczytanie dowolnej wartości zmiennej
typu zbiorliczb. Algorytm wykorzystany w tej procedurze jest następujący:
Algorytm 7.1.
przypisz zmiennej a typu zbiorowego zbiór pusty
podczas gdy wczytana liczba jest różna od zera to
jeśli wczytana liczba mieści się w zakresie typu podstawowego to
{
dodaj do zmiennej a zbiór złożony z wczytanej liczby
czytaj liczbę
}
A oto treść procedury:
procedure CzytajZbior(var a:zbiorliczb;ograniczenie1,
ograniczenie2: integer);
{ Procedura wczytywania wartości zmiennej typu zbiorowego }
var
k: integer;
begin
writeln('Podaj wartość zmiennej zbiorowej ( 0 kończy )');
read(k);
a := [];
while k <> 0 do
begin
if k in [ ograniczenie1..ograniczenie2] then
a := a + [k];
read(k)
end
end;
Wydruk wartości zmiennej typu zbiorliczb umożliwia procedura
DrukujZbior. Zanim podamy jej treść przedstawimy algorytm wykorzystany
w tej procedurze.
Algorytm 7.2.
dla i przebiegającej przez wszystkie wartości typu podstawowego
wykonuj
jeśli i należy do wartości zmiennej a to
drukuj i
procedure DrukujZbior(a:zbiorliczb;ograniczenie1,
ograniczenie2: integer);
{Procedura drukowania wartości zmiennej typu zbiorowego}
var
i: integer;
begin
writeln('Wartość zmiennej zbiorowej');
for i := ograniczenie1 to ograniczenie2 do
if i in a then writeln(i)
end;
Zamieszczony poniżej program testuje wykonanie procedur CzytajZbior i
DrukujZbior.
Program 7.1
program Test;
type
zbiorliczb = set of 1..100;
var
x,y: zbiorliczb;
procedure CzytajZbior(var a:zbiorliczb;ograniczenie1,
ograniczenie2: integer);
{Procedura wczytywania wartości zmiennej typu zbiorowego}
begin
{ Treść procedury zamieszczono wcześniej }
end;
procedure DrukujZbior(a:zbiorliczb;ograniczenie1,
ograniczenie2: integer);
{ Procedura drukowania wartości zmiennej typu zbiorowego }
begin
{ Treść procedury zamieszczono wcześniej }
end;
begin
CzytajZbior(x,1,100);
CzytajZbior(y,1,100);
DrukujZbior(x,1,100);
DrukujZbior(y,1,100)
end.
Jeśli wczytamy następujące ciągi liczb:
3 4 3 4 4 9 0
55 67 55 55 88 0
to wartością zmiennej x będzie [3,4,9], a wartością zmiennej y [55,67,88].
Warto podkreślić, że podane wyżej procedury mają charakter ogólny,
mogą być wykorzystywane dla wszystkich typów zbiorowych, w których
typem podstawowym są liczby. Dla innych typów podstawowych należy
dokonać drobnej modyfikacji tych procedur.
Sytuacja znacznie się komplikuje, jeśli typem podstawowym, z którego
tworzy się elementy zbioru, jest typ wyliczeniowy. W poprzednim podroz-
dziale rozważaliśmy przykład, w którym były wyznaczane informacje doty-
czące artykułów sprzedawanych w dwóch sklepach. Przypomnijmy, że typem
podstawowym, z którego tworzyliśmy wartości zmiennych typu zbiorowego
był następujący typ wyliczeniowy:
artyk = ( narty, kijki, buty_narc,lyzwy,sanki,rakiety,pilki,pletwy,
okul_plyw, rowery, motocykle );
a typem zbiorowym typ:
zbiorartyk = set of artyk;
W tym przypadku do wczytywania i wyprowadzania wartości zmiennych
typu zbiorowego należy zaprojektować procedury ukierunkowane na ten
konkretny typ wyliczeniowy (dla innego typu wyliczeniowego procedury te
będą miały inną postać).
Algorytm wykorzystany w procedurze drukowania i treść tej procedury
są przedstawione poniżej:
Algorytm 7.3.
dla i przebiegającej wszystkie wartości typu wyliczeniowego wykonuj
jeśli i zawiera się w a to
wyprowadź odpowiedni tekst w zależności od i
procedure DrukujWylicz(a:zbiorartyk);
{ Procedura drukowania wartości zmiennej typu zbiorowego,
którego typ podstawowy jest typem wyliczeniowym }
var
i: artyk;
begin
for i := narty to motocykle do
if i in a then
case i of
narty: writeln('narty');
kijki: writeln('kijki');
buty_narc: writeln('buty_narc');
lyzwy: writeln('lyzwy');
sanki: writeln('sanki');
rakiety:writeln('rakiety');
pilki: writeln('pilki');
pletwy: writeln('pletwy');
okul_plyw: writeln('okul_plyw');
rowery: writeln('rowery');
motocykle: writeln('motocykle')
end
end;
Algorytm wykorzystany w procedurze czytania i treść procedury są
podane poniżej.
Algorytm 7.4.
przypisz zmiennej a typu zbiorowego zbiór pusty
podczas gdy wczytana liczba jest różna od zera to
jeśli wczytana liczba mieści się w liczbie elementów typu
wyliczeniowego to
{
dodaj do zmiennej a element złożony z odpowiedniej wartości
typu wyliczeniowego poprzez przyporządkowanie liczbie wartości
czytaj liczbę
}
procedure CzytajWylicz(var a:zbiorartyk; liczbaelemen: integer);
{ Procedura wczytywania wartości zmiennej typu zbiorowego,
którego typ podstawowy jest typem wyliczeniowym }
var
k: integer;
begin
writeln('Podaj liczby odpowiadające wartościom',
' typu wyliczeniowego');
read(k);
a := [];
while k <> 0 do
begin
if ( 1 <= k ) and ( k <= liczbaelemen ) then
case k of
1: a := a + [narty];
2: a := a + [kijki];
3: a := a + [buty_narc];
4: a := a + [lyzwy];
5: a := a + [sanki];
6: a := a + [rakiety];
7: a := a + [pilki];
8: a := a + [pletwy];
9: a := a + [okul_plyw];
10: a := a + [rowery];
11: a := a + [motocykle]
end;
read(k)
end
end;
Program ilustrujący wykorzystanie procedury CzytajWylicz i
DrukujWylicz jest przedstawiony poniżej.
Program 7.2
program Testowy;
{ Program ilustrujący wykorzystanie procedur CzytajWylicz
i DrukujWylicz }
type
artyk = (narty,kijki,buty_narc,lyzwy,sanki,rakiety,
pilki,pletwy,okul_plyw,rowery,motocykle);
zbiorartyk = set of artyk;
var
x { zmienna do wprowadzania i wyprowadzania wartości }
: zbiorartyk;
procedure CzytajWylicz(var a:zbiorartyk; liczbaelemen:
integer);
{ Procedura wczytywania wartości zmiennej typu zbiorowego,
którego typ podstawowy jest typem wyliczeniowym }
begin
{ Treść procedury zamieszczono wcześniej }
end;
procedure DrukujWylicz(a:zbiorartyk);
{ Procedura drukowania wartości zmiennej typu zbiorowego,
którego typ podstawowy jest typem wyliczeniowym }
begin
{ Treść procedury zamieszczono wcześniej }
end;
begin
CzytajWylicz(x,11);
DrukujWylicz(x)
end.
Jeżeli wprowadzimy następujące dane:
1 5 1 4 6 4 1 0
to uzyskamy wydruk postaci:
narty
lyzwy
sanki
rakiety
Posiadając umiejętność wczytywania i wyprowadzania wartości, możemy
przystąpić do wykorzystania informacji zawartych w zmiennych typu zbioro-
wego. Obecnie zaprojektujemy program, który umożliwia po wprowadzeniu
wykazu artykułów sportowych uzyskanie następujących informacji:
1) wykaz artykułów (spośród wprowadzonych), których nie można zakupić w
żadnym sklepie
2) wykaz artykułów, które musimy zakupić w sklepie A
3) wykaz artykułów, które musimy zakupić w sklepie B
Zmienną, w której będziemy przechowywali wprowadzony wykaz artykułów,
nazwiemy wykaz. Podobnie jak w poprzednim podrozdziale do wyznaczenia
żądanych danych wykorzystamy wyrażenia logiczne. Informację pierwszą
możemy wyznaczyć poprzez wyrażenie postaci
( wszystkie - sklep_A - sklep_B ) * wykaz
Informację drugą wyznaczamy obliczając następujące wyrażenie:
( sklep_A - sklep_B ) * wykaz
A informację trzecią wyznaczamy przy pomocy wyrażenia:
( sklep_B - sklep_A ) * wykaz
gdzie wartością zmiennej wszystkie jest zbiór pełny, wartością zmiennej
sklep_A zbiór artykułów sprzedawanych w sklepie A oraz wartością zmien-
nej sklep_B zbiór artykułów sprzedawanych w sklepie B. Wartości wymie-
nionym zmiennym należy nadać na początku programu. Unikniemy w ten
sposób wypisywania w programie odpowiednich składowych poprzez zastą-
pienie ich nazwą zmiennej i tak np. zamiast zapisu [narty..motocykle]
użyjemy zmiennej wszystkie. Przypisanie tych wartości może się odbywać
przy pomocy poniższej procedury o nazwie Stale:
procedure Stale(var wszystkie,sklep_A,sklep_B: zbiorartyk);
{ nadanie zmiennym stałych wartości }
begin
wszystkie := [narty..motocykle];
sklep_A := [narty..sanki];
sklep_B := [rakiety..okul_plyw]
end;
Program realizujący wyprowadzenie żądanej informacji jest podany poniżej:
Program 7.3
program Sportowy;
type
artyk = (narty,kijki,buty_narc,lyzwy,sanki,rakiety,
pilki,pletwy,okul_plyw,rowery,motocykle);
zbiorartyk = set of artyk;
var
sklep_A, { wykaz artykułów dostępnych w sklepie A }
sklep_B, { wykaz artykułów dostępnych w sklepie B }
wszystkie, { wykaz wszystkich artykułów }
wykaz, { wprowadzony wykaz artykułów }
wynik { wartość wynikowa }
: zbiorartyk;
procedure Stale(var wszystkie,sklep_A,sklep_B: zbiorartyk);
{ nadanie zmiennym stałych wartości }
begin
{ Treść procedury zamieszczono wcześniej }
end;
procedure CzytajWylicz(var a:zbiorartyk; liczbaelemen: integer);
{ Procedura wczytywania wartości zmiennej typu zbiorowego,
którego typ podstawowy jest typem wyliczeniowym }
begin
{ Treść procedury zamieszczono wcześniej }
end;
procedure DrukujWylicz(a:zbiorartyk);
{ Procedura drukowania wartości zmiennej typu zbiorowego,
którego typ podstawowy jest typem wyliczeniowym }
begin
{ Treść procedury zamieszczono wcześniej }
end;
begin
Stale(wszystkie,sklep_A,sklep_B);
CzytajWylicz(wykaz,11);
writeln('Artykuły z wczytanego wykazu');
DrukujWylicz(wykaz);
writeln('Artykuły z wykazu, których nie ma w żadnym sklepie');
wynik := ( wszystkie - sklep_A - sklep_B ) * wykaz;
DrukujWylicz(wynik);
writeln('Artykuły z wykazu, które można kupić tylko w sklepie A');
wynik := ( sklep_A - sklep_B ) * wykaz;
DrukujWylicz(wynik);
writeln('Artykuły z wykazu, które można kupić tylko w sklepie B');
wynik := ( sklep_B - sklep_A ) * wykaz;
DrukujWylicz(wynik)
end.
Przedstawione wyżej procedury wprowadzania i wyprowadzania wartości
zmiennych typu zbiorowego wykorzystywały następujące dwa ogólne algorytmy:
Algorytm 7.5.
dla wszystkich wartości typu podstawowego wykonuj
jeśli wartość ta zawiera się w pewnym zbiorze to
przetwarzaj tę wartość
Algorytm 7.6.
przypisz zmiennej x wartość zbioru pustego
podczas gdy istnieją wartości do przetworzenia wykonuj
{
czytaj wartość a
jeśli a zawiera się w zbiorze pełnym to
x := x + [a]
}
Algorytm 7.5 był wykorzystywany przy wyprowadzaniu wartości zmiennej
typu zbiorowego, a algorytm 7.6 przy wprowadzaniu tej wartości. Równie
często jest stosowany następujący algorytm:
Algorytm 7.7.
przypisz zmiennej x wartość zbioru pełnego
podczas gdy istnieją wartości do przetworzenia wykonuj
{
czytaj wartość a
jeśli zawiera się w zbiorze pełnym to
x := x - [a]
}
Algorytm 7.7 jest stosowany do eliminacji pewnych wartości ze zbioru
pełnego. Wykorzystanie wszystkich trzech podanych algorytmów ilustruje
kolejny przykład.
Przykład
W przykładzie rozważymy następujący problem. W tekście umieszczonym w
pliku tekstowym należy znaleźć znaki nieobecne w tym tekście i jednocześ-
nie występujące w pierwszym zbiorze znaków oraz znaki obecne w tym
tekście i jednocześnie występujące w drugim zbiorze znaków.
Pierwszy zbiór znaków będziemy przechowywać w zmiennej typu zbioro-
wego o nazwie nieobecne, a drugi zbiór znaków w zmiennej o nazwie obecne.
Do wczytania i drukowania wartości tych zmiennych wykorzystamy dwie
procedury o nazwach CzytajZbior oraz DrukujZbior. Procedury te są zapro-
jektowane analogicznie jak procedury o tych samych nazwach podane w
poprzednim podrozdziale. Różnią się tylko typem parametrów i zmiennych
wewnętrznych.
Zbiór znaków obecnych w tekście i jednocześnie występujących w zmien-
nej obecne będziemy przechowywać w zmiennej t_obecne, natomiast zbiór
znaków nieobecnych w tekście i jednocześnie występujących w zmiennej
nieobecne będziemy przechowywać w zmiennej t_nieobecne. Wartość począt-
kowa zmiennej t_obecne powinna być równa [], a wartość początkowa zmien-
nej t_nieobecne powinna być równa wartości zmiennej nieobecne. Dla war-
tości zmiennej obecne:
[X,Y,P]
i wartości zmiennej nieobecne:
[a,b,c,d,e]
oraz tekstu
Program = algorytm + struktura danych
wartość zmiennej t_obecne powinna wynosić:
[P]
a wartość zmiennej t_nieobecne powinna być równa:
[b,e]
Możemy teraz przystąpić do zaprojektowania procedury wyznaczającej
wartości zmiennych t_obecne oraz t_nieobecne. Algorytm przetwarzania
tekstu wykorzystuje algorytmy 7.6 oraz 7.7 i jest następujący:
Algorytm 7.8
otwórz żądany plik
podczas gdy w pliku występują jeszcze symbole wykonuj
{
czytaj znak z pliku
jeśli znak zawiera się w wartości zmiennej obecne to
dodaj do wartości zmiennej t_obecne zbiór złożony ze znaku
jeśli znak zawiera się w wartości zmiennej nieobecne to
odejmij od wartości zmiennej t_nieobecne zbiór złożony ze znaku
Tekst procedury jest podany poniżej:
procedure Przetwarzaj(obecne,nieobecne:znaki;
var t_obecne:znaki; var t_nieobecne:znaki; var plik:text);
{ Procedura przetwarzania znaków z tekstu }
var
znak: char;
begin
assign(plik,'ala');
reset(plik);
while not eof(plik) do
begin
read(plik,znak);
if znak in obecne then
t_obecne := t_obecne + [znak];
if znak in nieobecne then
t_nieobecne := t_nieobecne - [znak]
end
end;
Możemy już teraz podać tekst programu sprawdzającego przynależność
znaków. Zrobimy to przy założeniu, że wzorcowe zbiory znaków (zmienne
obecne oraz nieobecne) mogą składać się z dużych i małych liter. Ogranicze-
nia typu podstawowego przy wywołaniu procedur CzytajZbior i DrukujZbior
są zatem następujące: 'A' ograniczenie dolne i 'z' ograniczenie górne. Przy
innym typie podstawowym należałoby zmienić te ograniczenia.
Program 7.4
program Tekst;
{ Program sprawdzania przynależności znaków z tekstu }
type
znaki = set of char;
var
obecne, nieobecne, { wzorcowe zbiory znaków }
t_obecne, t_nieobecne: { wyznaczane zbiory znaków }
znaki;
plik: text; { plik zawierający sprawdzany tekst }
procedure CzytajZbior(var a:znaki;
ograniczenie1,ograniczenie2,koniec: char);
{ Procedura wczytywania zbioru znaków }
var
k: char;
begin
writeln('Podaj wartość zmiennej zbiorowej: ');
read(k);
a := [];
while k <> koniec do
begin
if (ograniczenie1 <= k) and
(k <= ograniczenie2) then
a := a + [k];
read(k)
end
end;
procedure DrukujZbior(a:znaki; ograniczenie1,ograniczenie2: char);
{ Procedura drukowania zbioru znaków }
var
i: char;
begin
writeln('Wartość zmiennej zbiorowej');
for i := ograniczenie1 to ograniczenie2 do
if i in a then writeln(i)
end;
procedure Przetwarzaj(obecne,nieobecne: znaki;
var t_obecne,t_nieobecne: znaki; var plik: text);
{ Procedura przetwarzania znaków z tekstu }
begin
end;
begin
writeln('Podaj pierwszy wykaz znaków ');
CzytajZbior(obecne,'A','z','?');
writeln('Wykaz znaków, których szukamy znaków',
'obecnych w tekście:');
DrukujZbior(obecne,'A','z');
writeln('Podaj drugi wykaz znaków ');
CzytajZbior(nieobecne,'A','z','?');
writeln('Wykaz znaków, których szukamy znaków',
' nieobecnych w tekście:');
DrukujZbior(nieobecne,'A','z');
t_obecne := [];
t_nieobecne := nieobecne;
Przetwarzaj(obecne,nieobecne,t_obecne,t_nieobecne, plik);
writeln('Znaki obecne we wczytanym tekście');
DrukujZbior(t_obecne,'A','z');
writeln('Znaki nieobecne we wczytanym tekście');
DrukujZbior(t_nieobecne,'A','z')
end.
Na zakończenie zauważmy, że procedury wczytywania i drukowania
wzorcowych zbiorów znaków zostały tak zaprojektowane, aby wczytywany
był każdy znak należący do zbioru. Oczywiście możliwe jest takie zaprojek-
towanie tych procedur, aby wczytywane było tylko ograniczenie dolne i
górne znaków należących do zbioru. Wykonanie tego zadania pozostawiamy
jako ćwiczenie Czytelnikowi.