ALGORYTMY I STRUKTURY DANYCH
WYKŁAD 13
Techniki konstruowania algorytmów – przykłady Grażyna Mirkowska
PJWSTK, 2002/2003
Plan wykładu
Kody Huffmana
Mnożenie macierzy
Najdłuższy wspólny podciąg
Problem kodowania
Dany jest ciąg znaków. Chcemy tak zapisać ten ciąg, by zajmował jak najmniej miejsca i by dało się go potem łatwo odtworzyć.
Znak = liczba 0-255, czyli 8 bitów
100 000 znaków zajmuje 800 000 bitów.
Jeśli w naszych danych występuje tylko 6 różnych znaków, to 3 bity wystarczą do ich zakodowania, np.: 000,001,010,011,100,101
100 000 znaków
zajmuje 300 000
bitów.
Kody stałej i zmiennej długości
Kody o stałej długości -- wszystkie słowa kodowe mają tę samą długość
Kody o zmiennej długości -- długość słowa kodowego zależy od częstości
występowania danego znaku w ciągu danych.
Znaki występujące często mają kod możliwie krótki.
Niech będzie tekst 100000 znakowy, w którym występują tylko litery a,b,c,d,e,f i a-45tys razy, b-13tys., c-12tys.,
d-16tys., e - 9tys., f-5tys. razy.
Używając kodu
a= 0, b= 101,c= 100, d=111, e=1101, f=1100 nasz tekst można
zakodować na 224000bitach.
Przykład
Przykład
Kody prefiksowe
Żadne słowo kodowe nie jest prefiksem żadnego innego słowa kodowego.
ZASADA
ZASADA tzn,. Nie istnieją takie
dwa słowa a i b a=(a
1,...a
n) i b=(b
1,b
2...,b
m) n<m , że a
1=b
1, a
2= b
2... a
i= b
idla i=1...n.
Chodzi o to by można było jednoznacznie odczytać zakodowany
tekst.
Twierdzenie Twierdzenie
Jeśli istnieje optymalne
kodowanie, to zawsze można
znaleźć kod prefiksowy, który
go realizuje.
Drzewo kodowe (1)
A:45
100
86 14
58 28 14
B:13 C:12 D:16 E:9 F:5
Kod stałej długości
Każda ścieżka odpowiada jednemu słowu kodowemu.
W lewo = 0 w prawo = 1
F ma kod 101 F ma kod 101
Znak + częstość
występowania
Drzewo kodowe(2)
Kod zmiennej długości 100
A:45
25 30
C:12 B:13 14 D:16
F:5 E:9
55
Optymalny kod zawsze jest reprezentowany przez
lokalnie pełne drzewo binarne.
Ciąg:
0100110110101100
A 0 B 101 C 100 D 111 E 1101 F 1100 Odczytujemy
jako:ACEBAF
Konstrukcja kodu Huffmana
1.Utworzyć kolejkę priorytetową PQ
zawierającą wszystkie znaki alfabetu wraz z ich częstością wystąpienia
lewy prawy f
Znak f 2. For i :=1 to n-1 do
a := min(PQ); PQ := delmin(PQ);
b := min(PQ); PQ := delmin(PQ);
z := New node (a,b);
z.f := a.f + b.f;
PA := insert(PQ, z);
od;
return min (PQ);
liść liść
Wierzchołek Wierzchołek wewnętrzny wewnętrzny
Koszt
Koszt O(n lgn)
Algorytm zachłanny
Algorytm zachłanny
Przykład
A:45
C:12 B:13 D:16
F: 5 E: 9
14 A:45
C:12 B:13 D:16
F: 5 E: 9 14
25
A:45
C:12 B:13
D:16
F: 5 E: 9
14 25
30 A:45
C:12 B:13 D:16
F: 5 E: 9 14
25 30
55 A:45
0 100 1
1
1 0
0 1 0
0 1
Mnożenie macierzy
Dany jest ciąg macierzy A
1, A
2,...,A
n. Obliczyć iloczyn A
1 A
2... A
ntak by koszt mnożenia był najmniejszy.
Uwaga: Możemy pomnożyć macierz A
1przez A
2wttw
gdy A
1ma tyle kolumn ile A
2wierszy .
Koszt = A
1.w *A
1.k*A
2.k
Przykład Przykład
Obliczyć A B C.
A(10 100) B(100 5) C(5 50) (A B) C = A ( B C)
Koszt prawej strony =
(100 *5*5 0) + (10*100*50) = 75000 mnożeń skalarnych
Koszt lewej strony =
(10 *100*5 ) + (10*5*50)=
7500 mnożeń skalarnych
Prosty Algorytm?
Rozważyć wszystkie możliwe ustawienia
nawiasów w ciągu, a potem wykonać mnożenia zgodnie z ustawieniem nawiasów.
Za każdym razem wyliczyć koszt mnożenia przy danym ustawieniu nawiasów i wybrać to
ustawienie, które ma koszt najmniejszy.
A ile jest możliwych ustawień nawiasów?
A ile jest możliwych ustawień nawiasów?
Niech P(n) będzie liczbą ustawień
nawiasów w ciągu n elementowym.
(A
1,..., A
k) ( A
k+1..,A
n)
1 1
. )
(
* ) (
1 ,
1 )
(
nk
wpp k
n P k P
n gdy n
P
n-1- sza liczba Catalana
(4
n/n
3/2)
Za duży koszt!
Paradygmat programowania dynamicznego
1. Scharakteryzować strukturę rozwiązania optymalnego .
Rozwiązanie optymalne zawiera w sobie optymalne rozwiązania dla
podproblemów.
2. Zdefiniować rekurencyjnie wartość rozwiązania optymalnego, jako funkcję rozwiązań optymalnych dla podproblemów.
W naszym przykładzie: dla pewnego k, policzymy najpierw optymalne
ustawienie nawiasów dla iloczynu (A
1,..., A
k) potem optymalne
ustawienie nawiasów dla iloczynu
(A
k+1..,A
n), a potem dodamy do tego
koszt mnożenia 2 macierzy.
Liczymy minimalny koszt
m i k m k j p p p dla i j
j i
j gdy i
m
j k j i
k
i
{ [ , ] [ 1 , ]
1min ] 0
, [
Niech m[i,j] będzie minimalną liczbą mnożeń skalarnych potrzebnych do policzenia iloczynu ( A
i..,A
j), oraz macierz A
ima wymiar (p
i-1 p
i).
Niech s[i,j] = to k, które realizuje minimum dla m[i,j].
Rekurencyjny algorytm obliczania m[i,j] nie jest możliwy, nie jest możliwy, bo jego koszt jest wykładniczy, ale...
Przecież
można zapamiętywać policzone
wcześniej wartości
m[i,j]!
Algorytm MCM
for i :=1 to n do m[i,i] :=0; od;
for x := 2 to n do
for i := 1 to n-x+1 do j := i+x-1
m[i,j] := +;
for k := i to j-1do
q := m[i,k]+m[k+1,j] + p
i-1*p
k*p
j;
if q < m[i,j] then m[i,j] := q; s[i,j] :=k fi od
od od
return m,s; Koszt O(n Koszt O(n 3 3 ) )
Ustawienie
początkowej wartości elementów tablicy m.
Dwie pętle odpowiedzialne za wypełnienie wszystkich elementów m[i,j].
Wyszukiwanie
minimum
15125 10500
5375
3500
5000
0
11875 7125
2500
1000
0
9375 4375
750
0
7875
2625
0
15750
0 0
1 2
3 4
5 6 1
2 3
4 5
6
A
1A
2A
3A
4A
5A
6Tablica m
Tablica s
3 3
3
5
5
3 3
3
4
3 3
3
1
2
1
1 2
3 4
5 6 2
3 4
5 6
m[2,5]= min {
m[2,2] + m[3,5] + p
1*p
2*p
5,
,