Zadania do wykładu ALGORYTMY I STRUKTURY DANYCH

advertisement
Zadania do wykładu ALGORYTMY I STRUKTURY DANYCH
Szacowanie tempa wzrostu funkcji
Wprowadzenie: Do szacowania złożoności obliczeniowej algorytmów wykorzystuje się następujące pojęcia analizy matematycznej:
Mówimy, że funkcja f (n) określona na liczbach naturalnych o wartościach nieujemnych jest asymptotycznie ograniczona z góry przez funkcję g(n), jeśli istnieje stała C taka, że f (n) ≤ C · g(n) dla prawie
wszystkich n. Piszemy wówczas lub f (n) = O(g(n)) lub f (n) g(n).
Mówimy, że funkcja f (n) jest asymptotycznie równa funkcji g(n) , jeśli f (n) = O(g(n)) oraz g(n) =
O(f (n)). Piszemy wówczas f (n) = Θ(g(n)). Piszemy też f (n) ≺ g(n), jeśli f (n) g(n), ale nieprawda,
że g(n) f (n).
W przypadku funkcji rosnących używamy określeń rośnie: nie szybciej niż, nie wolniej niż, ma takie
samo tempo wzrostu. Bardziej formalnie O(g) definiujemy jako klasę wszystkich funkcji f g, a zapis
f = O(g) traktujemy jako nieformalny zapis f ∈ O(g).
Określamy ponadto log(k) n = log log . . . log n, gdzie logarytmowanie wykonywane jest k razy. (Przez
log rozumiemy zawsze logarytm przy podstawie 2, jeśli nie jest powiedziane inaczej).
1. Wykazać, że ak nk + ak−1 nk−1 + . . . + a0 = Θ(nk ), jeśli ak > 0.
2. Wykazać, że z warunek limf (n)/g(n) = 0 implikuje f (n) ≺ g(n). Wykorzystać to, do uzasadnienia, zachodzą następujące zależności (dla jakich k i c?):
1 ≺ log(k) n ≺ log(k−1) n ≺ n ≺ nk ≺ nk+1 ≺ cn ≺ (c + 1)n ≺ nn ≺ . . . ≺ n! ≺ . . .
3. Wykazać, że relacje ≺ i są przechodnie.
4. Pokazać, że dla dowolnych podstaw r, s > 1 zachodzi logr n logs n. Wywnioskować stąd, że w
zapisie O(log n) podstawa jest nieistotna.
5. Znajdź wzór na długość zapisów dziesiętnego i binarnego liczby naturalnej n i wywnioskuj, że w
obu przypadkach jest to Θ(log n). Oszacować proporcję długości zapisu dziesiętnego do długości
zapisu binarnego liczby naturalnej n.
6. Wykazać, że jeśli f = O(g), to O(g) + O(f ) = O(g + f ) = O(g).
7. Znaleźć wzory na sumy
(a) 1 + 2 + . . . + n
(b) 12 + 22 + . . . + n2
i umiejscowć te funkcje w hierarchii zadania 2.
8. Udowodnić, że ogólnie dla k ≥ 1:
n
X
i=1
ik =
1
nk+1 + O(nk ) = O(nk+1 )
k+1
9. *Skonstruuj („sztuczną”) funkcję, która nie da się umieścić w liniowej hierarchii zadania 2 (czyli
pokaż, że porządek nie jest bynajmniej porządkiem liniowym na zbiorze wszystkich klas funkcji
asymptotycznie równych).
Zbiory dynamiczne, listy, kolejki, stosy
10. Zaimplementuj listę z wartownikiem (tzn. napisz operacje Search, Insert i Delete dla tego
typu list).
11. Przy pomocy tablicy jednowymiarowej zaimplementuj kolejkę (procedury Enqueue, Dequeue)
12. Przy pomocy tablicy jednowymiarowej zaimplementuj stos (procedury Push, Pop oraz StackEmpty).
13. Przy pomocy listy jednokierunkowej zaimplementuj kolejkę oraz stos.
14. Napisać algorytm odwracania elementów listy jednokierunkowej (możliwie efektywny).
15. Odwróć stos S mając do dyspozycji puste stosy S1 i S2 .
16. Odwróć stos S mając do dyspozycji pusty stos T i kilka zmiennych.
17. Uporządkuj kolejkę Q (według kluczy) mając do dyspozycji stos i kilka zmiennych.
18. Uporządkuj kolejkę 100-elementową mając do dyspozycji kilka zmiennych (czyli „w stałej pamięci”; znana jest z góry długość kolejki).
Binarne drzewa wyszukiwań
19. Jaka jest minimalna wysokość drzewa k-arnego zawierającego n wierzchołków. Udowodnij.
20. Ile jest wierzchołków w drzewie binarnym pełnym na poziomie h? Ile jest wierzchołków rozpoczynających poddrzewo wysokości h? (Te same pytanie dla drzew pełnych k-arnych).
Binarne drzewo wyszukiwań (BST) to takie drzewo, w którym dla każdego wierzchołka v klucze elementów w lewym poddrzewie mniejsze są od klucza v, a klucze elementów w prawym poddrzewie są większe
od klucza v. Zakładając, że operacje wstawiania i usuwania elementów są losowe, można przyjąć, że
drzewo jest mniej więcej zrównoważone, a oczekiwana wysokość (pesymistyczny czas wyszukiwania)
wynosi O(log n).
21. Napisz algorytm wstawiania nowego elementu do BST. Oszacuj czas działania.
22. Napisz algorytm usuwania elementu z BST. Oszacuj czas działania.
23. Czy usuwanie elementów z BST jest przemienne? To znaczy, czy usuwając najpierw element x a
potem y otrzymamy to samo drzewo co usuwając najpierw element y a potem x?
24. Napisz algorytm wypisania wszystkich elementów BST w kolejności porządku liniowego wyznaczonego przez klucze oraz oszacuj jego złożoność. (Wskazówka: zastosuj procedurę rekurencyjną
wypisując najpierw elementy lewego podrzewa, a potem elementy prawego podrzewa). szacuj
czas działania.
25. * Rozważ, które operacje się komplikują przy założeniu, że różne elementy w BST mogą mieć
jednakowe klucze.
26. Udowodnij, że dla elementu, który ma dwóch synów, jego następnik (w porządku liniowym) nie
ma lewego syna, a jego poprzednik nie ma prawego syna.
27. Wykorzystując procedurę wypisywania wszystkich elementów drzewa BST, dla dowolnego drzewa
z jednokierunkowymi dowiązaniami, zaprojektuj procedurę odnajdywania ojca.
2
Sortowanie
28. Zaimplementować sortowanie przez scalanie (Merge-Sort) na tablicy (z użyciem dodatkowej
tablicy).
29. Opisać algorytm sortowania przez bąbelkowanie (Bubble-Sort). Jaki jest jego czas działania?
30. Ile razy trzeba podzielić daną liczbę n na kolejne połowy, żeby otrzymać liczbę nie większą niż
1. Zakładamy, że przy dzieleniu liczby nieparzystej wybieramy „większą połowę”, tzn. sufit z
podzielenia liczby przez dwa. Odpowiedź udowodnij.
31. Tablicę A[1..n] różnych liczb 1, . . . , n traktujemy jako permutację. Każdą parę liczb i < j, taką że
A[i] > A[j] nazywamy inwersją. Zaprojektuj algorytm liczący ilość inwersji działający w czasie
O(n log n) (wzorując się na algorytmie Merge-Sort).
Rekurencja
32. Wzór rekurencyjny Fn = Fn−1 + Fn−2 z warunkiem F0 = F1 = 1 definiuje tzw. liczby Fibbonaciego. Udowodnić przez indukcję wzór:
!
!
√ !n
√ !n
√
√
5+1
1+ 5
5˘1
1− 5
√
√
Fn =
+
2
2
2 5
2 5
Który ze wzorów lepiej nadaje się do zastosowań komputerowych? Opisać najefektywniejszą
metodę obliczania liczb Fibonacciego.
Schemat Hornera
33. Omów algorytm obliczania wartości wielomianu w danym punkcie za pomocą schematu Hornera.
Pokaż jak można wykorzystać schemat Hornera do obliczania wartości liczby danej w zapisie
szesnastkowym. Przykładowo, jaka liczba ma szesnastkowy zapis 2EF 5A7?
34. Opisz możliwie efektywny algorytm znajdowania zapisu szestnastkowego liczb (czy można wykorzystać tu schemat Hornera?)
35. Opisz algorytmy szybkiego potęgowania oparty na idei schematu Hornera oraz na idei znajdowania zapisu binarnego od prawej do lewej.
36. Zastosuj algorytmy szybkiego potęgowania dla wykładników m = 15, 23, 48 (to znaczy pokaż
jak szybko obliczyć potęgi x15 , x23 , x48 przy pomocy tych algorytmów). Czy można te potęgi
obliczyć szybciej (w mniejszej ilości mnożeń)?
Przechodzenie drzew
37. Poniższe wyrażenia przedstaw w notacji polskiej i odwrotnej polskiej:
a) ab + (c(d + e + f ) − g − h/a)
b) ((p → q) ∧ (q → r)) → (p → r)
38. Oblicz wartości wyrażeń zapisanych w notacji odwrotnej polskiej, gdzie symbolami końcowymi
są pojedyncze cyfry:
a) 33 + 4 + 5 ∗ 1−
b) 313 + +22 + 22 ∗ −∗
39. Narysuj drzewa wyrażeń z dwóch poprzednich zadań. Czy były one potrzebne do rozwiązania
tych zdań?
3
40. Zapisać prawa łączności mnożenia i rozdzielności mnożenia względem dodawania w odwrotnej
notacji polskiej.
41. Załóżmy, że wyrażeniu w zapisie infiksowym używamy tylko jednego działania binarnego, którego
argumenty ujmujemy w nawiasy (bez symbolu działania; jak dla mnożenia). Napisz procedurę
zapisującą takie wyrażenie w notacji prefiksowej. Przekonaj się, o ile trudniejsze jest zadanie
odwrotne.
42. Opisz procedurę sprawdzania poprawności zapisu w postaci infiksowej (prefiksowej).
43. Opisz procedurę tworzenia drzewa wyrażenia w zapisie infiksowym. Wynik ma być dany w formie
tablicy reprezentującej drzewo binarne.
44. Opisz procedurę przekształcania zapisu w notacji polskiej na zapis w odwrotnej notacji polskiej.
Kopce
45. Udowodnić, że jeśli węzły drzewa binarnego prawie pełnego ponumerować poziomami od góry w
dół, to dla każdego węzła, jeśli ma on numer i, to jego lewy syn i prawy syn mają, odpowiednio,
numery 2i oraz 2i + 1.
46. Jaki jest numer pierwszego elementu rozpoczynającego ciąg liści w tablicy reprezentującej drzewo
binarne zrównoważone (prawie pełne)?
47. Czy tablica A = (23, 17, 14, 6, 13, 10, 1, 5, 7, 12) jest kopcem?
48. Na powyższej tablicy zademonstrować procedury budowania kopca i sortowania przez kopcowanie.
49. Dla kopca n elementowego, ile maksymalnie i ile minimalnie elementów zawierają lewe i prawe
poddrzewo korzenia?
50. Jaki jest czas działania algorytmu heap-sort na tablicy juz posortowanej (rosnąco, malejaco)?
51. Zaimplementuj kolejkę priorytetową przy użyciu kopca (procedury Extract-Max, Insert.
52. Napisz algorytm przekształcania listy uporządkowanej w kopiec i oszacuj czas działania. Czy
algorytm warto zmienić w zależności od sposobu posortowania?
Opis algorytmów
53. Opisz algorytm Euklidesa znajdowania NWD liczb na dwa sposoby: jako algorytm iteracyjny i
algorytm rekurencyjny. Uzasadnij jego poprawność.
54. Oszacuj czas działania algorytmu Euklidesa. Ile maksymalnie dzieleń trzeba w nim wykonać?
(Wskazówka: Rozważ zmianę pary (a, b) i zauważ, że co dwa kroki algorytmu, drugi element tej
pary zmniejsza co najmniej o połowę).
55. Napisz najprostszy algorytm testowania czy liczba naturalna n jest pierwsza. Jaki jest jego czas
działania? Podać wynik względem wielkości liczby n oraz wynik względem długości zapisu liczby
n. Który z nich jest proporcjonalny do rzeczywistego czasu obliczeń na komputerze?
56. Załóżmy, że operacja sprawdzania czy liczba n podzielna jest przez liczbę d wykonywana jest
w czasie stałym i wymaga (przy odpowiedniej implementacji) nie więcej niż 100 – 1000 operacji podstawowych (cykli) procesora. Załóżmy że obliczenia wykonujemy na procesorze 4 GHz.
Jak duże liczby jesteśmy w stanie testować, czy są pierwsze, przy pomocy powyższego prostego
algorytmu?
4
57. Gdybyśmy chcieli testować pierwszość liczb dłuższych niż 64 bity (long long int, jak należałoby zaimplementować algorytm. Podaj jedynie idee. Czy sprawdzanie podzielności może być
wykonywane w czasie stałym? Jaki jest czas działania algorytmu?
58. Opisz rekurencyjny algorytm generowania wszystkich słów długości k nad alfabetem n-elementowym
(przez formalne słowo rozumiemy dowolny ciąg liter).
59. Ustal porządek liniowy, w jakim generowane są słowa w poprzednim algorytmie (ewentualnie
zmień algorytm tak, żeby był to porządek słownikowy-licznikowy). Napisz procedurę Next,
która generuje następne słowo na podstawie poprzedniego i użyj jej do zaprojektowania algorytmu
generującego wszystkie słowa. (Taki algorytm ma tę zaletę, że działa używając stałej pamięci).
60. Zdefiniuj porządek leksykograficzny (alfabetyczny) i porządek standardowy na słowach. (W porządku standardowym słowa krótsze poprzedzają dłuższe, a gdy długości są równe decyduje
porządek alfabetyczny). Słowo a1 . . . an jest mniejsze od słowa b1 . . . bm , jeśli . . . .
61. Opisz algorytm generowania wszystkich permutacji zbioru n-elementowego. Jaki jest jego czas
działania?
62. *Opisz algorytm generowania kolejnych permutacji zbioru n-elementowego, który używa stałej
pamięci.
Wieże w Hanoi
W indyjskim mieście Benares, w samym środku ziemi na początku świata Brahma nasadził na diamentowy pręcik 64 szczerozłote krążki, których średnice rosną od góry do dołu. Używając drugiego,
pomocniczego pręcika kapłani mają za zadanie przełożyć tę piramidę z krążków na trzeci pręcik, przy
czym ich ruchy muszą polegać na zdjęciu jednego krążka z jednego pręcika i nasadzeniu go na inny
pręcik, a na każdym pręciku krążki muszą zawsze leżeć mniejszy na większym. Kiedy na trzeciej pałeczce znajdą się wszystkie 64 krążki, nastąpi koniec świata. Tyle hinduska legenda. Oszacuj, kiedy
będzie koniec świata.
63. Opisz naturalny algorytm rekurencyjny rozwiązujący problem wież Hanoi. Wykaż jego poprawność.
64. Zastosuj ten algorytm do przypadku n = 5 symulując mechaniczne działanie kompilatora. (Kompilator wchodząc z kolejne wywołanie procedury rekurencyjnej zapamiętuje na stosie aktualne
parametry i numer aktualnie wykonywanej instrukcji – żeby wiadomo było, którą instrukcję wykonać po powrocie i z jakimi parametrami. Na końcu procedury rekurencyjnej musi być znacznik
końca informujący kompilator, że procedura została zakończona i należy wrócić do wykonywania
procedury na wyższym poziomie pobierając dane ze stosu.)
65. Jaka jest minimalna ilość przesunięć potrzebna do przestawienia n krążków. Udowodnij odpowiedź.
66. Znajdź przepis pokazujący jaki należy wykonać ruch w danej sytuacji (algorytm on-line). Wskazówka: przyjrzyj się jak poruszają się krążki w procedurze rekurencyjnej i spróbuj dać możliwie
prostą receptę na kolejne ruchy.
Sortowanie
67. Zilustruj działanie procedury Partition dla tablicy A = (13, 19, 9, 5, 12, 8, 7, 4, 11, 2, 6, 21).
68. Jaką wartość q zwraca procedura Partition, gdy wszystkie elementy w tablicy są równe. Jak
zmodyfikować procedurę żeby zwracała wartość środkową? Jaki jest czas działania procedury
Quicksort w tym przypadku.
5
69. Załóżmy, że w ciągu miesiąca spływają dane o zrealizowanych czekach, po kilku czekach na dzień,
i numery czeków są posortowane z dokładnością do dnia (w danym dniu dane mogą spłynąć
w nieprawidłowej kolejności. Uzasadnij, że dla takich danych procedura Insert-sort działa
szybciej niż Quicksort
70. Jak zmodyfikować procedurę Quicksort, żeby sortowała w porządku nierosnącym?
71. Ile porównań potrzeba, żeby wyznaczyć minimum dla danego zbioru liczb? Zaprojektuj algorytm,
który wyznacza jednocześnie minimum i maksimum w danym zbiorze. Ile porównań potrzeba?
72. Używając procedury Partition zaprojektuj algorytm wyznaczający i-ty element zbioru liczb.
Oszacuj czas działania.
73. Zaprojektuj szczegóły algorytmu Counting-Sort sortującego n kluczy-liczb całkowitych z przedziału h1, mi, opartego na pomyśle zliczenia najpierw w osobnej tablicy P [i] ile jest kluczy równych i, a następnie ile jest kluczy nie większych od i – i w ten sposób wyznaczenie właściwego
miejsca tablicy wynikowej dla klucza równego i. Oszacuj czas działania.
74. Zilustruj działanie procedury Counting-Sort na tablicy A = (6, 0, 2, 0, 1, 3, 4, 6, 1, 3, 2). Czy
procedura ta sortuje stabilnie.
75. Zaprojektuj algorytm, który dla danych n liczb z przedziału < 0, k > wykonuje wstępne obliczenia
w czasie O(n + k), a następnie na ich podstawie w stałym czasie pozwala określić ile spośród n
liczb leży w przedziale < a, b >.
76. Zilustruj działanie procedury sortowania kubełkowego z zastosowaniem sortowania przez wstawianie kolejnych list dla tablicy A = (0.79, 0.13, 0.16, 0.64, 0.39, 0.20, 0.89, 0.53, 0.71, 0.42).
77. Metodę sortowania nazywamy stabilną, jeśli nie zmienia ona kolejności elementów o równych
kluczach. Które ze znanych algorytmów sortowania są stabilne?
78. Udowodnij przez indukcję poprawność sortowania pozycyjnego.
Haszowanie i programowanie dynamiczne
79. Zilustruj ciąg wstawień elementów o kluczach 5, 28, 19, 15, 20, 33, 12, 17, 10 do tablicy z haszowaniem, wykorzystując do rozwiązywania kolizji metodę łańcuchową. Przyjmujemy, że tablica
zawiera 9 pozycji, a h(k) = k mod 9 jest funkcja haszującą.
80. Zilustruj ciąg wstawień elementów o tych samych kluczach do tablicy 12 elementowej przy pomocy
adresowania otwartego liniowego.
81. Zilustruj działanie algorytmu programowania dynamicznego (PD) znajdowania minimalnej ilości mnożeń skalarnych potrzebnych do pomnożenia czterech macierzy o kolejnych wymiarach:
21, 15, 7, 15, 9.
82. Opisz algorytm wyznaczania optymalnego nawiasowania dla pomnożenia n macierzy.
83. Wyznacz optymalne nawiasowanie iloczynu ciągu macierzy o wymiarach 5, 10, 3, 17, 5, 50, 6.
84. Opisz algorytm (oparty na metodzie PD) wyznaczania najdłuższego wspólnego podciągu (NWP)
dwóch ciągów i oszacuj jego czas działania.
85. Znajdź NWP ciągów 10010101 i 010110110.
86. *Zmodyfikuj algorytm znajdywania długości NWP dwóch ciągów długości m i n, tak żeby działał
w czasie O(m + n). Czy możliwe to jest w przypadku wyznaczania NWP?
87. Zaprojektuj algorytm wyznaczania najdłuższego niemalejącego podciągu ciągu n liczb całkowitych działający w czasie O(n2 ).
6
88. *Jak poprawić poprzedni algorytm tak żeby działał w czasie O(n log n).
Algorytmy grafowe
89. (Graf eulerowski ) Udowodnij, że spójny graf ma zamkniętą drogę Eulera wtedy i tylko gdy każdy
wierzchołek ma stopień parzysty.
90. (Graf półeulerowski ) Udowodnij, że spójny nieeulerowski graf ma drogę Eulera (niekoniecznie
zamkniętą) wtedy i tylko gdy ma dokładnie dwa wierzchołki stopnia nieparzystego.
91. Przedstaw efektywny algorytm wyznaczania drogi Eulera w grafie.
92. Zaprojektuj dwa algorytmy tworzenia drzewa rozpinającego w grafie prostym spójnym:
(a) rozpoczynający od zbioru pustego T dodający kolejne krawędzie do T , aż do otrzymania
drzewa rozpinającego
(b) rozpoczynający od zbioru wszystkich krawędzi i usuwający kolejne krawędzie, aż do otrzymania drzewa
Uzasadnij poprawność tych algorytmów.
93. Jednocześnie z przeszukiwaniem grafu skonstruować drzewo rozpinające grafu
94. Opisz procedurę wyznaczania najkrótszej drogi między wierzchołkami w grafie a) prostym; b)
skierowanym.
95. Opisz procedury sprawdzania w czasie O(n + m), że graf jest a) spójny; b) acykliczny. Jakiej
reprezentacji musimy użyć? Jak sprawa się zmienia, gdy rozważymy wersje skierowane tych
zagadnień?
96. Pokazać na przykładzie konkretnego grafu, że DFS iteracyjny (z bezpośrednim użyciem stosu) i
DFS rekurencyjny wyznaczają różne drzewa i mogą wyznaczać nawet drzewa różnej wysokości.
97. * Czy da się tak zaprojektować DFS iteracyjny tak, żeby kolorował wierzchołki grafu (na biało,
szaro i czarno) dokładnie tak samo jak DFS rekurencyjny.
98. (Problem chińskiego listonosza) Wskazać sposoby obliczania najkrótszej drogi zamkniętej w grafach ważonych eulerowskich i półeulerowskich. Odpowiedź uzasadnić.
99. Zaprojektować algorytm znajdowania krótkiej ścieżki pomiędzy wierzchołkami oparty na strategii
zachłannej (w każdym wierzchołku wybieramy najkrótszą nieodwiedzoną krawędź). Pokazać, że
w tym przypadku strategia zachłanna nie jest optymalna.
100. Rozważyć wersję algorytmu Kruskala polegającą na usuwaniu kolejnych krawędzi o możliwie
największej wadze rozpoczynając od zbioru wszystkich krawędzi.
101. (Algorytm Prima) Zaprezentować algorytm wyznaczania minimalnego drzewa rozpinającego (MST)
w grafir ważonym oparty na zasadzie dołączania kolejnych krawędzi do spójnego acyklicznego
podgrafu o możliwie najmniejszej wadze.
102. (Backtracking) Zaprojektować iteracyjny algorytm numerujący wierzchołki drzewa w numeracji
preorder.
7
Download