1. Zaprogramować zwykłe sortowanie przez wstawianie na

Transkrypt

1. Zaprogramować zwykłe sortowanie przez wstawianie na
1. Zaprogramować zwykłe sortowanie przez wstawianie na jednokierunkowej liście o nieznanej z góry długości.
void sort_wstaw(wsk *P){
wsk *Q, *S, R;
if (*P!=NULL){
Q = &((*P)->nast);
while (*Q!=NULL){
S = P;
while ((*S)->x < (*Q)->x) { S = &((*S)->nast); }
if (S!=Q){
R = *Q;
*Q = R->nast;
R->nast = *S;
*S = R;
}
else { Q = &((*Q)->nast); }
}
}
}
2. Dla algorytmu Shella z h1 = 2 i h2 = 1, podać przykłady danych, na których ten algorytm działa (a) szybciej,
(b) podobnie lub wolniej niż zwykłe sortowanie bąbelkowe.
Pojedyncza zamiana elementów T [i] i T [i + h] wykonana w algorytmie Shella dla h > 1 odpowiada ciągowi
h(h + 1)/2 kolejnych zamian w obrębie elementów T [i], T [i + 1], . . . , T [i + h − 1], T [i + h] w zwykłym sortowaniu
bąbelkowym. Dlatego algorytm Shella działa szybciej na danych, których uporządkowanie prowadzi do zamian
dla h > 1. W naszym przykładzie, gdy h = 2, np. dla [8, 7, 6, 5, 4, 3, 2, 1]. Z kolei dla danych [2, 1, 4, 3, 6, 5, 8, 7]
faza algorytmu z h = 2 nie wykona żadnych zamian, a jedynie dodatkowe porównania. Stanowi więc dodatkowy
nakład pracy ponad to, co wykona faza z h = 1, a więc zwykłe sortowanie bąbelkowe.
3. Algebraiczne operacje na wielomianach stopni nie większych niż n można wykonywać zapamiętując ich współczynniki w tablicach wg schematu
w(x) = a0 + a1 x + a2 x2 + · · · + am xm
−→
A[0] = a0 , A[1] = a1 , . . . , A[m] = am , A[m + 1] = · · · = A[n] = 0
i następnie działając na tych tablicach obliczać sumy, różnice, iloczyny i ilorazy wielomianów. Oszacować złożoność obliczeniową tablicowej realizacji tych 4 operacji?
Niech mA i mB oznaczają stopnie wielomianów A[ ] i B[ ].
— Dodawanie i odejmowanie: C[i] = A[i] ± B[i], i = 0, 1, . . . , max{mA , mB } ¬ n; złożoność O(n).
Pk
— Mnożenie: C[k] = i=0 A[i]B[k − i], k = 0, 1, . . . , mA + mB ¬ n; złożoność O(n2 ).
— Pisemne dzielenie A[ ] przez B[ ] wymaga mA − mB + 1 kroków, w każdym z nich mB mnożeń i odejmowań,
a więc łącznie O(n2 ) działań.
4. Ekscentrycznością E wierzchołka v w grafie skierowanym G nazywamy długość najdłuższej wsród najkrótszych
ścieżek z innych wierzchołków do v,
E(v) =
max dmin (x, v) ,
x∈V (G)
dmin (x, v) = długość najkrótszej ścieżki z x do v .
Centrum C grafu G jest to zbiór wierzchołków w G o minimalnej ekscentryczności. Wśród zastosowań można
wymienić np. algorytm wyboru wsi na siedzibę gminnej przychodni zdrowia. Wybór wsi z centrum grafu połączeń
drogowych jest najbardziej korzystny dla mieszkańców gminy.
Wychodząc od macierzy najkrótszych ścieżek W = [wij ] w G utworzonej przez algorytm Warshalla-Floyda
napisać fragment kodu wyznaczający centrum C(G).
for (j=1; j<=n; j++){
M=W[1][j];
for (i=2; i<=n; i++){ if (M < W[i][j]) {M = W[i][j];} }
E[j]=M; // E[j] = ekscentrycznosc wierzcholka j (max W[][j])
}
for (j=1; j<=n; j++){ if (E[j]<M) {M=E[j];} } // M = najmniejsza ekscentrycznosc w G
printf("Centrum grafu zawiera wierzcholki:\n");
for (j=1; j<=n; j++){ if (E[j]==M) {printf("%i, ", j);} }
printf("\n");
5. Gwarancją poprawnego działania algorytmu Dijkstry jest założenie, że długości krawędzi grafu są nieujemne
wij ­ 0. Załóżmy, że macierz W zawiera ujemne elementy. Naiwna metoda zaradzenia temu problemowi polega
na dodaniu do wszystkich elementów W ustalonej liczby C > 0 tak, aby stały się one dodatnie. Po zastosowaniu
algorytmu do tak zmodyfikowanej macierzy W , od długości każdej krawędzi w wyznaczonej najkrótszej ścieżce
między wierzchołkami s i t należałoby odjąć liczbę C by odzyskać prawdziwą najmniejszą odległość z s do t.
Wyjaśnić na prostym przykładzie dlaczego takie podejście jest błędne.
u
2
v
-3
2
s
5
t
Dodanie 4 do wszystkich krawędzi powoduje, iż ich długości staną się dodatnie. Po tej modyfikacji najkrótsza
ścieżka z s do t pokrywa się z krawędzią (s, t) o długości 9. Po odjęciu 4 otrzymujemy jej oryginalną długość 5. W
rzeczywistości krótsza ścieżka to s − u − v − t o długości 1. W zmodyfikowanym grafie długość każdej jej krawędzi
powiększona jest o 4, więc całkowita długość tej ścieżki — o 12. Nie będzie więc wykryta jako najkrótsza ścieżka
z s do t.
Błąd proponowanej metody polega na tym, iż nie bierze ona pod uwagę faktu, że liczba krawędzi w ścieżce nie
ma na ogół nic wspólnego z jej długością mierzoną sumą wag tych krawędzi. Ścieżki zbudowane z wielu krawędzi
podlegają znacznemu wydłużeniu w stosunku do ścieżek o małej liczbie krawędzi, więc początkowe relacje między
ich długościami mogą łatwo zostać zmienione: najkrótsze ścieżki w oryginalnym grafie przestają nimi być w grafie
zmodyfikowanym.
Nota bene w powyższym przykładzie algorytm Dijkstry poprawnie wyznaczy najkrótszą ścieżkę z s do t na
niezmodyfikowanym grafie, mimo obecności w nim ujemnej krawędzi, podczas gdy modyfikacja grafu psuje jego
działanie.

Podobne dokumenty