i = 1

Transkrypt

i = 1
Poszukiwanie liniowe wśród liczb naturalnych
Wiele problemów, dotyczących liczb naturalnych, można rozwiązać idąc w
górę od zera (lub czasem od innej liczby) i sprawdzając, czy już.
Przykład: (zadane reszty z dzielenia)
M
Dane są liczby p > q ­ 0 oraz s > r ­ 0; p i s są względnie pierwsze,
czyli nie mają wspólnych dzielników większych niż 1. Znaleźć najmniejszą
liczbę n > 0, która
1. w dzieleniu przez p daje resztę q,
2. w dzieleniu przez s daje resztę r.
Niech n przebiega po kolei wszystkie liczby postaci
0 · p + q, 1 · p + q, 2 · p + q, ...
(war. 1), aż natrafi na taką, która spełnia war. 2.
Wykład 3. POSZUKIWANIE I TABLICE, str. 2
Poszukiwanie liniowe wśród liczb naturalnych
/* p > q ­ 0 & s > r ­ 0 */
n=q;
/* n%p = q */
while (n%s != r) {
n=n+p;
}
/* n%p = q & n%s = r */
p q s r
16 11 9 7
p%k — w języku C: reszta z dzielenia p przez k
To jest szczególny przypadek
„chińskiego twierdzenia o resztach”
n
11
27
43
Poszukiwanie liniowe wśród liczb naturalnych
Przykład: (liczby pierwsze)
M
Dane jest n ­ 1. Znaleźć najmniejszą liczbę pierwszą większą niż n.
Liczba p jest pierwsza, jeśli nie dzieli się przez żadną liczbę k spełniającą
2 ¬ k < p.
Niech p oznacza zawsze „kandydata” na poszukiwaną liczbę pierwszą; zaczniemy od p = n + 1 i będziemy sprawdzać jej podzielność przez liczby k
od 2 do p − 1.
• Jeśli znajdziemy dzielnik k, to zwiększymy kandydata p o 1 i zaczniemy
sprawdzanie znowu od 2.
• Jeśli dojdziemy z k do p − 1 i po drodze nie natrafimy na dzielnik p,
to p jest liczbą pierwszą.
Wykład 3. POSZUKIWANIE I TABLICE, str. 4
Poszukiwanie liniowe wśród liczb naturalnych
/* n ­ 1 */
p=n+1; k=2;
/* p > n ­ 1 & k ¬ p
p nie dzieli się przez i ∈ [2 . . k − 1] */
while (k<p) {
if (p%k == 0) {
/* p jest złym kandydatem */
p=p+1; k=2; }
else /* trzeba sprawdzać dalej */
k=k+1;
}
/* p > n ­ 1 &
p nie dzieli się przez i ∈ [2 . . p − 1] */
p%k — w C: reszta z dzielenia p przez k
n
8
p
9
k
2
3
10 2
11 2
3
4
5
6
7
8
9
10
11
Tablice czyli zmienne indeksowane
W językach programowania występują tablice — zmienne indeksowane reprezentujące skończone ciągi liczbowe.
a:
a:
a0 =
15
0
15
a1 =
0
1
0
a2 = −24
2
-24
• zamiast ai piszemy a[i],
a3 =
66
3
66
• zamiast a2·i−1 piszemy a[2*i-1].
a4 =
0
4
0
Indeksami są dowolne wyrażenie całkowite, w programie ujmuje się je w nawiasy
kwadratowe, np.
W C indeksowanie tablicy biegnie zawsze od zera; t.zn.
tablica n-elementowa a zawiera elementy
a[0], a[1], a[2], . . . , a[n-1]
Element a[n] nie istnieje.
Wykład 3. POSZUKIWANIE I TABLICE, str. 6
Tablice czyli zmienne indeksowane
Typowy program z tablicami w C:
nagłówek
deklaracje
wejście (w pętli)
obliczenie
wyjście (w pętli)
- main() {
-( int i, a[100];
for (i=0; i<100; i=i+1)
scanf ("%i", &a[i]);

. . . . . . . . . . . . . . .
- . . . . . . . . . . . . . . .

. . . . . . . . . . . . . . .
(
for (i=0; i<100; i=i+1)
printf ("a[%i] == %i\n", i,
}
-
.
.
.
a[i]);
Iteracja for
for (i=A; i<B; i=i+1) C
?
i←A
-
• iterację for można wyrazić przy pomocy
while-a:
i=A; while (i<B) { C i=i+1; }
?
i<B | i­B
?
C
• granice A i B oraz zmienna sterująca i prawidłowo skonstruowanej iteracji nie powinny
podlegać zmianie w ciele iteracji C;
?
i←i+1
• iteracja for nadaje się idealnie do przeglądania tablicy; ale nie tylko do tego.
?
Wykład 3. POSZUKIWANIE I TABLICE, str. 8
Tablice czyli zmienne indeksowane
Przykład: (odwracanie ciągu liczb)
M
Żeby wczytać ciąg n liczb i napisać go od końca, trzeba jego n wyrazów
czasowo zapamiętać; można to zrobić na przykład w tablicy:
for (i=0; i<n; i=i+1) scanf("%i", &a[i]);
for (i=n-1; i>=0; i=i-1) printf (" %i ", a[i]);
w
11
2
e
j
ś
c
−16
i
0
11
1
2
e
2
4
0
w
−16
3
4
4
0
0
4
y
j
ś
c
−16
i
e
2
11
Tablice czyli zmienne indeksowane
Przykład: (maksimum)
M
Znaleźć największą liczbę w ciągu N -elementowym, którego wszystkie wyrazy są nieujemne: ai ­ 0 dla i ∈ [0 . . . N − 1] .
max = 0;
for (n=0; n<N; n=n+1)
if (max < a[n]) max = a[n];
Samodzielny program, wczytujący liczby do tablicy, obliczający maksimum i
drukujący, nie ma wiele sensu. Liczyć maksimum można „w locie”, niczego
nie zapamiętując w tablicy.
Jednak powyższy fragment programu, liczący maksimum tablicy, można
wykorzystać jako fragment większej całości.
Wykład 3. POSZUKIWANIE I TABLICE, str. 10
Sortowanie
W tablicy a długości n zapisane są liczby. Należy je tak poprzestawiać, żeby
a0 ¬ a1 ¬ . . . ¬ an−1 .
Sortowanie tablicy a[0 . . n − 1] przez wybór maksimum:
1. znaleźć takie k ∈ [0 . . n − 1], że ak jest maksimum tablicy a[0 . . n − 1]
2. zamienić ak z an−1
3. posortować krótszą tablicę a[0 . . n − 2]
for (i=n; i>=2; i=i-1) {
znaleźć takie k ∈ [0 . . i − 1],że ∀p∈[0 . . i−1] ap ¬ ak ;
zamienić ak z ai−1 ;
}
Sortowanie
0
1
2
3
4
5
15
−7
23
−7
11
0
i=6
MAX
OSTATNI
for (i=n; i>=2; i=i-1) {
znaleźć takie k ∈ [0 . . i − 1],
że ∀p∈[0 . . i−1] ap ¬ ak ;
zamienić ak z ai−1 ;
}
Wykład 3. POSZUKIWANIE I TABLICE, str. 12
Sortowanie
0
1
2
3
4
5
−7
−7
0
11
15
23
i=1
for (i=n; i>=2; i=i-1) {
znaleźć takie k ∈ [0 . . i − 1],
że ∀p∈[0 . . i−1] ap ¬ ak ;
zamienić ak z ai−1 ;
}
Jak znajdować takie k, żeby ak było maksymalne?
— to już wiemy.
Jak zamieniać?
Sortowanie
Jak zamieniać a[k] z a[i-1]?
a[k]
Przypisanie:
∗
a[i-1]
∗
ŹLE!
a[k] = a[i-1];
Wykład 3. POSZUKIWANIE I TABLICE, str. 14
Sortowanie
Jak zamieniać a[k] z a[i-1]?
a[k]
a[i-1]
2
3
1
U
pomocnicza
Trzy kroki:
1
pomocnicza = a[k];
2
a[k] = a[i-1];
3
a[i-1] = pomocnicza;
Sortowanie
for (i=n; i>=2; i=i-1) {
k=0;
for (j=1; j<i; j=j+1)
if (a[k]<a[j]) k=j;
x=a[k]; a[k]=a[i-1]; a[i-1]=x;
}
znajdowanie maksimum
zamiana
Ile zamian?
W każdym obiegu zewnętrznej pętli: jedna.
Więc razem: n − 1.
Ile porównań elementów tablicy?
W każdym i-tym obiegu zewnętrznej pętli: i − 1.
n
X
n2
n(n − 1)
n
(i − 1) =
=
−
Więc razem:
2
2
2
i=2
Wykład 3. POSZUKIWANIE I TABLICE, str. 16
Sortowanie
Istnieje wiele różnych algorytmów sortowania tablicy, różniących się:
• czasem działania w zależności od długości tablicy (w sortowaniu przez
maksimum: około n2 ),
• zajętością dodatkowej pamięci (w sortowaniu przez maksimum: w miejscu),
• „długością” zamian (sortowanie przez maksimum: n − 1),
• możliwościami zrównoleglenia działań przy użyciu większej liczby procesorów,
• itp.
ISTNIEJĄ ZNACZNIE SZYBSZE
ALGORYTMY SORTOWANIA
Niebezpieczeństwa związane z tablicami
Wyjście indeksu poza zakres
Znaleźć pierwsze zero w tablicy a[0 . . n-1]:
i=0;
while (a[i] != 0 && i<n)
i=i+1;
i=0;
while (i<n && a[i] != 0)
i=i+1;
— jeśli w a[0 . . n-1] nie ma wcale zera, to pętla po lewej nie zatrzyma
się na czas i sięgnie po nieistniejący element a[n].
W C można temu zapobiec przez odwrócenie koniunkcji, jak w pętli po
prawej. Koniunkcja w C nie jest symetryczna, najpierw liczy się lewy argument.
W innych językach bywa różnie. . .
&
błąd
fałsz
prawda
błąd
błąd
fałsz
błąd
fałsz
błąd
fałsz
fałsz
prawda
błąd
fałsz
prawda
Wykład 3. POSZUKIWANIE I TABLICE, str. 18
Niebezpieczeństwa związane z tablicami
Niepewna tożsamość zmiennych
Tablica a[0 . . n-1]. Czy te instrukcje
for (i=0; i<n; i=i+2) a[i]=0;
for (i=n-1; i>=0; i=i-2) a[i]=0;
zerują jej wszystkie pola?
Jeśli n jest parzyste, tak. Jeśli n jest nieparzyste, nie.
Różne zmienne mogą w programie wyglądać tak samo; np. a[i] oznacza
różne zmienne, zależnie od wartości i.
Ta sama zmienna może w różnych miejscach programu wyglądać różnie;
np. a[i+1] i a[j-1] to ta sama zmienna, jeśli j = i + 2.
Poszukiwanie liniowe
Załóżmy, że tablica a[0 . . n − 1] jest wypełniona liczbami; i mamy daną
liczbę x. Wyszukać x w tablicy a; t.zn.
znaleźć takie p, że a[p] = x, lub
upewnić się, że takie p nie istnieje (czyli x nie występuje w tablicy a).
#define FALSE 0
#define TRUE 1
..........
// n ­ 0
znal=FALSE; p=0;
// 0 ¬ p ¬ n &
//
(znal & a[p] = x) ∨ (¬znal & w a[0 . . p − 1] nie ma x)
while (!znal && p<n)
if (a[p] == x) znal=TRUE;
else p=p+1;
// (znal & a[p] = x) ∨ (¬znal & w a[0 . . n − 1] nie ma x)
Wykład 3. POSZUKIWANIE I TABLICE, str. 20
Metody łapania lwa na pustyni
Fizyczna:
Przesypać całą pustynię przez sito. To, co przeleci, to piasek; to, co zostanie w sicie, to lew.
Matematyczna:
Zamknąć się w klatce; następnie dokonać inwersji przestrzeni względem klatki: my znajdziemy się na zewnątrz a lew w klatce. Uwaga!
nie stać w środku klatki, bo przy inwersji to
miejsce przechodzi na punkt w nieskończoności.
Informatyczna:
Podzielić pustynię na pół; połowę, w której jest lew, znowu na pół; ćwiartkę,
w której jest lew, na pół. . . Tak postępować, aż rozpatrywany fragment
pustyni zmaleje do rozmiaru podstawy klatki. Na tym fragmencie pustyni
postawić klatkę.
Poszukiwanie binarne
Zadanie: policzyć b =
√
√
5
10 z dokładnością do 0.1 (czyli |b − 5 10| < 0.1).
a = 1 jest za małe, bo 15 = 1 ¬ 10 ; c = 2 jest za duże, bo 10 < 32 = 25 .
a5 ¬ 10 < c5
abc
1.000
1.125
1.250
a
1.000
1.375
b=
a+c
2
1.500
1.625
c
2.000
b5
b5 ¬ 10
7.594
TAK
16.413
NIE
11.331
NIE
9.313
TAK
10.283
NIE
1.500
1.500
1.750
1.875
2.000
2.000
1.750
1.500
1.750
1.625
1.500
1.625
1.563
1.563
1.625
1.594
Wykład 3. POSZUKIWANIE I TABLICE, str. 22
Poszukiwanie binarne
Zadanie:
n > 0 i ε > 0√
√
policzyć b = 5 n z dokładnością do ε (czyli |b − 5 n| < ε).
a=0; b=n/2; c=n;
// a5 ¬ n < c5 & b =
while (c-a >= ε) {
if (b5 <= n) a=b;
else c=b;
b = (a+c)/2;
}
a+b
2
Poszukiwanie binarne
Załóżmy, że tablica a[0 . . n − 1] jest wypełniona liczbami i uporządkowana;
i mamy daną liczbę x. Wyszukać x w tablicy a.
// n > 0
if (x < a[0]) znal=FALSE;
else { // n > 0 & a[0] ¬ x < a[n] = +∞
p=0; q=n; // 0 ¬ p < q ¬ n & a[p] ¬ x < a[q]
while (q-p > 1) {
r=(p+q)/2;
if (x < a[r]) q=r;
else p=r;
} // a[p] ¬ x < a[p + 1]
if (x == a[p]) znal=TRUE;
else znal=FALSE;
}
// (znal & a[p] = x) ∨ (¬znal & w a[0 . . n − 1] nie ma x)

Podobne dokumenty