You are on page 1of 52

1

Ch ng 3
Phn t#ch ph c t p m t s
gi i thu t tr%n c u tr'c d li u
2
N i dung
1. T)m ki m tu n t tr%n danh s+ch li%n k t
2. Cy t)m ki m nh phn
3. H,ng i c- u ti%n v, heapsort
4. K thu t b m
3
1.T)m ki m tu n t tr%n danh s+ch li%n k t
T)m ki m tu n t (sequential search) c- th c th c
hi n th/ng qua vi c d0ng danh s+ch li%n k t (linked
list) bi u di n c+c m u tin trong t p tin.
M t l i i m: d l,m cho danh s+ch li%n k t c- th t
m, gi'p cho vi c t)m ki m nhanh ch-ng h n.
4
3 4 7 21
Z

T)m ki m tu n t tr%n m t danh s+ch li%n k t c-


th t .
Qui c: z l, n't gi trong danh s+ch li%n k t.
type link = node
node = record key, info: integer;
next: link
end;
var head, t, z: link;
i: integer;
5
Gi i thu t t)m ki m tu n t tr%n danh s+ch
li%n k t
procedure initialize;
begin
new(z); z.next: = z;
new(head); head.next:= z
end;
function listsearch (v: integer; t: link): link;
begin
z.key: = v;
repeat t:= t.next until v < = t.key;
if v = t.key then listsearch:= t
else listsearch: = z
end;
6
Gi i thu t t)m ki m tu n t tr%n danh s+ch li%n
k t (tt.)
function listinsert (v: integer; t: link): link;
begin
z.key: = v;
while t.next.key < v do t: = t.next;
new(x); x.next: = t.key; t.next: = x;
x.key: = v;
listinsert: = x;
end;
Tnh ch t: Tm ki m tu n t tr"n danh s%ch li"n k t c(
th t d*ng trung bnh kho ng N/2 thao t%c so s%nh cho c
s tm ki m th,nh c-ng hay kh-ng th,nh.
7
Ch ng minh:
V i s t)m ki m th,nh c/ng, n u gi s r ng m i m u tin
trong danh s+ch li%n k t c- x+c xu t b ng nhau (1/N)
c t)m th y, s l n so s+nh trung b)nh s l,:
(1 + 2+ 1+ N)/N = N(N+1)/(2N) = (N+1)/2.
V i s t)m ki m kh/ng th,nh c/ng, n u gi s r ng m i m u
tin trong danh s+ch li%n k t hay n't k t th'c z c- x+c xu t
b ng nhau (1/(N+1)) c t)m th y v tr# sau c0ng c a
qu+ tr)nh t)m ki m, s l n so s+nh trung b)nh s l,:
(1 + 2+ 1+ (N+1))/(N+1) = (N+2)(N+1)/(2(N+1)) = (N+2)/2.
8
2.Cy t)m ki m nh phn
10
13
7
5
19 2
Trong m t c.y tm ki m nh ph.n (binary search tree),
t t c c+c m u tin v i kh-a nh h n kh-a t i n't ang x2t
th) cy con b%n tr+i c a n't v,
c+c m u tin v i kh-a l n h n hay b ng kh-a t i n't ang
x2t th) cy con b%n ph i c a n't.
9
Kh i t o cy nh phn
procedure tree_init;
begin
new(z); z.1: = z; z.r: = z;
new(head); head.key: = 0; head.r: = z;
end;
M t cy r ng c bi u di n b ng cy c- con
tr b%n ph i ch n n't gi z.
10
T+c v th%m v,o
Th"m m t n%t v'o trong c*y, ta th c hi n m t s t+m
ki m (kh,ng th'nh c,ng) n%t y tr"n c*y, r i g n n%t
y v'o v tr ng v i n%t gi z t i i m m' qu. tr+nh t+m
ki m k t th%c.
A
A R
S
C
E
H
H)nh v minh h a
vi c th%m n't P v,o
cy nh phn.
11
T+c v th%m v,o (tt.)
;
procedure tree_insert (v: integer; x: link): link;
var p: link;
begin
repeat
p: = x;
if v < x.key then x: = x.1 else x: = x.r
until x = z;
new(x); x.key: = v;
x.1: = z; x.r: = z; /* create a new node */
if v < p. key then p.1: = x /* p denotes the parent of
the new node */
else p.r: = x;
tree p.r: = x
end
12
In ra cy nh phn
procedure treeprint(x: kink)
begin
if x <> z then
begin
treeprint (x.1);
printnode (x);
treeprint (x.r)
end
end;
V) m t cy nh phn di n t m t t p tin c- th t , vi c in ra
c+c tr kh-a trong cy theo m t c+ch 'ng n s em l i
m t danh s+ch c+c kh-a c- th t .
13
T+c v t)m ki m
type link = node;
node = record key, info: integer;
l, r: link end;
var t, head, z: link;
function treesearch (v: integer, x: link): link; /* search the node with
the key v in the binary search tree x */
begin
while v <> x. key and x <> z do
begin
if v < x.key then x: = x.1
else x: = x.r
end;
treesearch: = x
end;
14
T#nh ch t c a s t)m ki m tr%n cy nh phn
T#nh ch t: M t t%c v th"m v,o hay tm ki m tr"n m t c.y nh
ph.n /i h i ch ng 2lnN so s%nh tr"n m t c.y c t o ra t N
tr kh(a ng u nhi"n.
Ch ng minh:
Chi u d,i l i i c a 1 n0t: l, s c nh c n duy t qua t n0t
y v n0t r +1.
i v i m i n't tr%n cy nh phn, s so s+nh c d0ng
cho m t s t)m ki m n't y th,nh c/ng ch#nh l, chi u d,i
l i i c a n't y.
T ng t t c chi u d,i l i i c a m i n't tr%n cy nh phn
c g i l, chi u d,i l i i c a cy nh phn.
15
Ch ng minh (tt.)
Khi chia chi u d,i l i i to,n cy v i N, ta s c s so s+nh
trung b)nh i v i m t s t)m ki m th,nh c/ng tr%n cy.
Nh ng n u C
N
bi u th chi u d,i l i i trung b)nh c a to,n
cy, ta c- m t h th c truy h i sau y, v i C
1
= 1
!
N
1
(C
k-1
+ C
N-k
) C
N
= N +
S h ng N l, do s ki n n't r -ng g-p 1 v,o chi u d,i l i i
c a m i n't.
S h ng th hai l, do s ki n kh-a t i n't r c- x+c xu t b ng
nhau tr th,nh ph n t l n th k trong cy, v i hai cy con
l n l t ch a k-1 n't v, N-k.
16
Ch ng minh (tt.)
k
k-1
N-k
H th c truy h i n,y r t gi ng h th c truy h i khi phn
t#ch Quicksort, v, n- 3 c gi i c0ng m t c+ch a
l i c0ng m t k t qu .
Do - chi u d,i trung b)nh c a cy N n't l,
C
N
2N lnN.
Suy ra chi u d,i trung b)nh c a m t n't trong cy l,
2lnN.
M t t+c v t)m ki m hay th%m v,o 5i h i trung b)nh
2lnN so s+nh tr%n m t cy g m N n't.
17
ph c t p trong tr 5ng h p x u nh t
T#nh ch t: Trong tr ng h p x u nh t, m t t%c v tm
ki m tr"n c.y nh ph.n g m N kh(a c( th c n N so
s%nh.
Tr ng h p x u nh t x y ra khi cy nh phn b suy bi n
th,nh m t danh s+ch li%n k t.
T+c v x-a
Vi c xo+ m t n't r t d n u n't y kh/ng c- n't con hay ch
c- m t n't con.
x-a m t n't c- hai con th) kh+ ph c t p: ta ph i thay
th n- v i n't c- tr kh-a cao nh t k ti p (t c n't t n c0ng
tr+i c a cy con b%n ph i).
18
Th# d : T+c v
xo+
E
C
R
H
L
N
M F
A
R
C N
M
A
P
H
L
19
The following procedure is to delete the node t from the binary
tree x.
procedure treedelete (t, x: link);
var p, c: link;
begin
repeat /* search for the node t in the tree */
p: = x;
if t.key < z. key then x: = x.1
else x: = x.r
until x = t;
if t.r = z then /* the node t has no right child */
x: = x.1 /* replace the deleted node with the left child of
t */
else if t.r.1 = then /* the right chile of t has no left child */
begin x: = x.r; x.1: = t.1 end /* replace the deleted node
with its right child */
20
else
begin
e: = x.r;
while c.1.1 <> z do c: = x.1; /* find the leftmost node
of the right subtree */
x: = c.1; /* x denotes the node that will replace the
deleted one */
c.1 = x.r; /* connect c, the parent of x to the right
child of x */
x.1: = t.1; x.r: = t.r /* connect x: the children of the
deleted node t */
end;
if t.key < p.key then p.1: = x /* connect x to the parent
of the deleted node */
else p.r: = x;
end;
21
3. H,ng i c- u ti%n v, gi i thu t s p
th t HEAPSORT
M t c u tr'c d li u m, h tr #t nh t hai t+c v :
+ th%m m t ph n t m i v,o c u tr'c
+ x-a b ph n t l n nh t
c g i l, h,ng i c- u ti%n (a priority-queue).
H,ng i c- u ti%n kh+c v i h,ng i th/ng th ng
i m khi l y ph n t ra kh i h,ng i th) - kh/ng ph i l,
ph n t c nh t trong h,ng i m, l, ph n t c( u ti"n
l n nh t trong h,ng i.
22
H,ng i c- u ti%n (tt.)
Ch'ng ta mu n xy d ng v, duy tr) m t c u tr'c d li u ch a nh ng
m u tin c- tr kh-a s ( u ti%n) v, c- h tr m t s trong nh ng
t+c v sau:
- t o m t h,ng i c- th t u ti%n g m N ph n t .
- th%m (insert ) m t ph n t m i v,o.
- x(a b ph n t l n nh t ra kh i h,ng i.
- thay th ph n t l n nh t v i m t ph n t m i
- thay i u ti%n c a m t ph n t .
- X-a b m t ph n t b t k n,o -.
- Gh2p hai h,ng i c- u ti%n th,nh m t h,ng i c- u ti%n
l n h n.
23
Thi c/ng h,ng i c- u ti%n
H,ng i c- u ti%n nh 3 m/ t l, m t v# d v ki u d li u tr u
t ng 3 n-i ch ng 1. C- hai c+ch thi c/ng h,ng i c-
u ti%n:
1. D0ng m ng thi c/ng h,ng i c- u ti%n (C+ch n,y th) n
gi n khi th%m v,o m t ph n t m i nh ng khi x-a b ph n t c-
u ti%n l n nh t ra kh i h,ng i th) ph c t p s cao.)
2. D0ng c u tr'c d li u heap.
24
C u tr'c d li u heap
C u tr'c d li u m, c- th h tr cho c+c t+c v l,m vi c v i
h,ng i c( u ti"n s ch a c+c m u tin trong m t m ng
sao cho:
m i kh(a ph i l n h n kh(a hai v tr1 kh%c trong m ng.
T ng t m i kh(a trong hai kh(a n,y ph i l n h n hai tr
kh(a kh%c v, c nh th ..
Th t n,y s d th y h n khi ta di n t m ng nh m t c u
tr'c cy v i nh ng ng n i m i kh-a xu ng hai kh-a
nh h n.
C+c tr kh-a trong c u tr'c cy th a i u ki n heap nh sau:
Kh-a t i m i n't c n ph i l n h n (hay b ng) c+c kh-a
hai con c a n- (n u c-). i u n,y h,m 6 r ng tr kh-a l n
nh t n't r .
25
Th# d : Heap d i d ng cy nh phn
X
T O
G
A
S
M
R A E
N
I
26
Heap d i d ng m t m ng
Ta c- th di n t d ng cy c a heap th,nh m t m ng b ng
c+ch t n't r t i v tr# 1 c a m ng, c+c con c a n- t i v tr# 2
v, 3, c+c n't c+c m c k ti p c+c v tr# 4, 5, 6 v, 7, v.v..
k 1 2 3 4 5 6 7 8 9 10 11 12
a[k] X T O G S M N A E R A I
T m t n't d d,ng i t i n't cha v, c+c n't con c a n-.
Cha m t n't v tr# j s l, n't v tr# j div 2.
Hai con c a m t n't v tr# j s c+c v tr# 2j
v, 2j+1.
27
C+c l i i tr%n heap
M t heap l, m t cy nh phn, c di n t nh l,
m t m ng trong - m i n't th a m3n i u ki n
heap. c bi t, ph n t c- kh-a l n nh t lu/n v
tr1 th nh t c a m ng.
T t c c+c gi i thu t l,m vi c tr%n heap i d c theo
m t l i i n,o - t n't r xu ng m c +y (bottom)
c a heap.
Trong m t heap c- N n't, t t c c+c l i i (path)
th ng c- lgN n't tr%n -.
28
C+c gi i thu t tr%n Heap
C- hai t+c v quan tr ng l,m vi c tr%n heap: th%m v,o
ph n t m i v, x-a b ph n t l n nh t ra kh i heap.
T+c v n,y s l,m t ng k#ch th c c a heap l%n th%m
m t ph n t . N c t ng th%m 1.
V, ph n t m i c t v,o t i v tr# a[N], nh ng l'c
- i u ki n heap c- th s b vi ph m.
N u i u ki n heap b vi ph m, n- s c kh c ph c
b ng c+ch ho%n i ph n t m i v i cha c a n-. i u
n,y l i c- th gy ra vi ph m i u ki n heap v, n- s
c kh c ph c ti p v i c0ng m t c+ch t ng t .
1. T+c v th%m v,o (insert)
29
T+c v th%m v,o
procedure upheap(k:integer)
var v: integer;
begin
v :=a[k]; a[0]:= maxint;
while a[k div 2] <= v do
begin a[k]:= a[k div 2 ]; k:=k div 2 end;
a[k]:= v
end;
procedure insert(v:integer);
begin
N:= N+1; a[N] := v ; unheap(N)
end;
30
Th%m (P) v,o heap
X
T P
G
A
S
O
R A E
N
I M
31
T+c v x-a b ph n t l n nh t
T+c v x-a s l,m gi m k#ch th c c a heap m t n v ,
t c n- l,m gi m N m t n v .
Nh ng ph n t l n nh t (t c a[1]) s c x-a b v, c
thay th b ng ph n t m, 3 v tr# a[N]. N u tr kh-a t i
n't r qu+ nh , n- ph i c di chuy n xu ng th a m3n
i u ki n heap.
Th t c downheap th c hi n vi c di chuy n ph n t ang
n't r xu ng b ng c+ch ho+n i n't v tr# k v i n't
l n h n trong hai n't con c a n-, n u c n v, d ng l i khi
n't k l n h n hai n't con c a n-.
32
T+c v x-a b
procedure downheap(k: integer);
label 0 ;
var j, v : integer;
begin
v:= a[k];
while k<= N div 2 do
begin
j:= 2*k;
if j < N then if a[j] < a[j+1] then
j:=j+1;
if v >= a[j] then go to 0;
a[k]:= a[j]; k:= j;
end;
0: a[k]: =v
end;
function remove: integer;
begin
remove := a[1];
a[1] := a[N]; N := N-1;
downheap(1);
end;
33
Th# d v t+c v x-a
T
S P
G
A
R
O
C A E
N
I
M
Tr c khi x-a
34
Sau khi x-a
S
R P
G
A
M
O
C A E
N
I
35
T#nh ch t c a c+c t+c v tr%n heap
T#nh ch t 3.1: M i t%c v th"m v,o, x(a b ,
downheap, upheap d/i h i 1t h n 2lgN so s%nh khi
th c hi n tr"n m t heap g m N ph n t .
T t c nh ng t+c v n,y ph i i d c theo m t l i i gi a
n't r cho n cu i heap m, bao g m#t h n lgN ph n t
v i m t heap g m N ph n t .
Th a s 2 l, do t+c v downheap m, c n hai thao t+c so
s+nh trong v5ng l p trong v, c+c thao t+c kh+c ch 5i h i
lgN l n so s+nh.
36
Gi i thu t heapsort
8 t ng: Gi i thu t bao g m 2 c/ng t+c (1) t o m t heap
ch a nh ng ph n t c n s p th t v, (2) l n l t l y
ch'ng ra kh i heap theo m t th t .
M : k#ch th c c a heap
N: s ph n t c n c s p th t .
N:=0;
for k:= 1 to M do
insert(a[k]); /* construct the heap */
for k:= M downto 1 do
a[k]:= remove; /*putting the element removed into the
array a */
37
S p th t d3y s 5, 3, 1, 9, 8, 2, 11 b ng heapsort
11
8 9
3 5 1 2
5
3 1
9
5
3
1
9
8
3
1
5
9
8
3
2
5 1
38
9
8
3
2
5 1
11
8
5
3
2
1
5
3
1
2
3
1 2
2
1
1
9 11
8 9
11
5
8 9
11
3
5
8
9
11
2 3
5 8 9
11
39
ph c t p c a heap sort
T#nh ch t: Heapsort d*ng 1t h n 3MlgM l n so
s%nh s p th t M ph n t .
Gi i h n tr%n n,y xu t ph+t t gi i thu t heapsort
v, t#nh ch t c a hai t+c v th%m v,o/x-a b tr%n
heap.
V5ng for th nh t t n MlgM l n so s+nh.
V5ng for th hai t n 2MlgM l n so s+nh.
T ng c ng:
MlgM + 2MlgM = 3MlgM
40
4.K thu t b m
K thu t b m (Hashing) l, m t ph ng ph+p t)m ki m c+c
m u tin trong m t b ng b ng c+c bi n i c+c tr kh-a th,nh
nh ng a ch (v tr#) trong b ng.
B c u l, t o m t h,m b m (hash function ) m, chuy n i
kh-a t)m ki m th,nh m t a ch trong b ng.
M t c+ch l6 t ng, nh ng tr kh-a kh+c nhau n%n +nh x
th,nh nh ng a ch kh+c nhau, nh ng kh/ng c- h,m b m n,o
l, ho,n h o v, do - hai hay nhi u kh-a kh+c nhau c- th b m
th,nh c0ng m t v tr# b ng.
B c k ti p l, qu+ tr)nh gi i quy t ng (collision-
resolution) m, i ph- v i tr ng h p hai hay nhi u kh-a
kh+c nhau c- th b m th,nh c0ng m t v tr# b ng.
41
H,m b m
H,m b m l, h,m bi n th c+c tr kh-a th,nh nh ng s
nguy%n trong t m [0 .. M-1], v i M l, s m c tin m, c- th
c ch a trong m t s l ng / nh c- s n.
M t h,m b m l6 t ng l, h,m b m m,
- d t#nh to+n
- g n gi ng nh m t h,m:ng u nhi%m;.
M t ph ng ph+p th/ng th ng nh t b m l, cho M l,
m t s nguy%n t v, v i m i tr kh-a k, ta t#nh
h(k): = k mod M
y l, m t ph ng ph+p tr c ti p m, d t#nh v, r i kh+
u c+c tr kh-a ra tr%n b ng b m.
42
V# d
K#ch th c b ng b m = 101. Gi s m i tr kh-a g m 4 k6
t . N u kh-a (:AKEY;) c m3 h-a th,nh m t m3 g m 5
bit, ta c- th coi kh-a y l, m t tr,ng s nh ph n nh sau:
00001 01011 00101 11001
1 < 32
3
+ 11 x 32
2
+ 5 x 32
1
+ 25 x 32
0
M, t ng ng v i tr s th p phn 44217 .
V), 44217 mod 101 = 80, nh v y kh-a :AKEY; +nh x
th,nh 80.
T i sao k#ch th c M c a b ng b m c n ph i l, s nguy%n
t ? L6 do l, v) ch'ng ta mu n t t c m i k6 t trong kh-a
u tham gia v,o vi c chuy n i (b m) th,nh v tr#.
Trong th# d tr%n, n u M = 32, h,m b m c a b t k kh-a
n,o c ng ch b m m i k6 t sau c0ng!
43
B m m t kh-a d,i
N u kh-a l, m t d5ng k6 t kh+ d,i th) ch'ng ta v n c- th
t#nh b ng m t h,m b m m, bi n i kh-a t ng k6 t m t.
K thu t - th hi n b ng gi i thu t l p nh sau:
h:= key[1];
for j:= 2 to key_size do
begin
h:= ((h*32) + key[j]) mod M; /*25 is 32, used for
5-bit code */
end;
44
Ph ng ph+p gi i quy t ng : Xu ri%ng
(Separate chaining)
Trong k thu t b m, ch'ng ta ph i quy t nh d0ng c+ch
n,o gi i quy t v n hai kh-a kh+c nhau b m th,nh
c0ng m t gi+ tr a ch .
M t ph ng ph+p n gi n nh t: t o cho m i v tr# trong
b ng b m m t danh s+ch li%n k t (xu ri%ng) xu t t c
nh ng tr kh-a m, b m v,o c0ng v tr# -.
Khi c+c tr kh-a c xu tr%n danh s+ch li%n k t, ch'ng
n%n c s p cho c- th t .
type link = node;
node = record key, info: integer;
next: link end;
var heads: array [0..M] of link; t, x: link;
45
Xu ri%ng (tt.)
Danh s+ch li%n k t cho t ng v tr# trong b ng b m c kh i
t o nh gi i thu t sau:
procedure initialize;
var i: integer;
begin
new (z); z.next: = z;
for i: = 0 to M-1 do
begin
new (heads [i]); heads [i].next: = z
end;
end;
Trong h)nh v sau tr)nh b,y vi c a v,o b ng b m m t d3y
c+c k6 t ch .
46
Key: A S E A R C H I N G E X A M P L E
Hash: 1 8 5 1 7 3 8 9 3 7 5 2 1 2 5 1 5
A
A
A
L
M
X
C
N E
E
E
P
G
R
H
S
I
0 1 2 3 4 5 6 7 8 9 10
47
Ph ng ph+p gi i quy t ng : D5 tuy n t#nh
Ph ng ph+p xu ri%ng c- th +p d ng trong tr ng h p
M < N (M: k#ch th c b ng b m, N: s tr kh-a c- th c-)
C- m t s ph ng ph+p l u N m u tin trong b ng b m c-
k#ch th c M m, M > N, nh v,o nh ng v tr# tr ng trong
b ng b m gi i quy t ng . Nh ng ph ng ph+p nh
v y c g i l, k thu t b m a ch m (open addressing
hashing).
Ph ng ph+p a ch m n gi n nh t l, ph ng ph+p
d/ tuy n t1nh ( linear probing): m i khi c- ng th) d5 n
v tr# k ti p trong b ng b m, t c l, so s+nh tr kh-a c n t)m
v i tr kh-a t i m u tin.
48
D5 tuy n t#nh (tt.)
C- ba k t qu c- th c- c a s th m d5:
- N u hai tr kh-a kh p nhau th) s t)m ki m k t th'c th,nh
c/ng.
- N u kh/ng th y c- m u tin t i v tr#, th) s t)m ki m k t th'c
th t b i.
- Ng c l i, d5 t)m t i v tr# k ti p, ti p t c nh th cho n khi
t)m th y tr kh-a kh p nhau ho c l, m t v tr# r ng.
49
Gi i thu t d5 tuy n t#nh
procedure hash_initialize;
var i: integer;
begin
for i: = 0 to M do a[i].key:= maxint; /* maxint means an empty
position */
end;
function hash_search(v: integer): integer;
var x: integer;
begin
x: = h(v);
while a[x].key <> maxit and a[x].key <> v do
x: = (x+1) mod M;
if a[x].key: = v then hash_search: = x
else hash_search: = M;
end;
50
D5 tuy n t#nh (tt.)
function hash_insert (v: integer): integer;
var x: interger
begin
x:= h(v);
while a[x].key <> maxint do /* collision */
x: = (x+1) mod M;
a[x].key: = v; hash-insert: = x;
end;
H)nh v sau tr)nh b,y vi c a v,o b ng b m m t d3y c+c k6
t ch : A S E A R C H I N G E X A M P L E
51
Key: A S E A R C H I N G E X A M P L E
Hash: 1 0 5 1 18 3 8 9 14 7 5 5 1 13 16 12 5
R
P
N
M
L
E
X
I
H
G
E
E
A
C
A
A
S
52
T#nh ch t c a d5 tuy n t#nh
K#ch th c b ng b m d0ng cho k thu t d5 tuy n t#nh
th ng l n h n b ng b m d0ng xu ri%ng, v) ta ph i c-
M > N, nh ng t ng ch b nh s #t h n v) kh/ng c n l u
c+c con tr .
T#nh ch t. D/ tuy n t1nh s d ng trung bnh 1t h n 5 b c d/
i v i m t b ng b m y d i 2/3.
C/ng th c ch#nh x+c v s l n d5 trung b)nh c n cho m t s
t)m ki m kh/ng th,nh c/ng l,:
= + 1/(2*(1- )
2
) v i = N/M
N u = 2/3, ta c k t qu 5 b c d5.

You might also like