|
Serwis Edukacyjny w I-LO w Tarnowie
Materiały dla uczniów liceum |
Wyjście Spis treści Wstecz Dalej
Autor artykułu: mgr Jerzy Wałaszek |
©2026 mgr Jerzy Wałaszek
|
ProblemW zbiorze Z należy wyszukać element, od którego w tym zbiorze jest dokładnie
Jeśli nie musimy zachowywać oryginalnej kolejności elementów
Działanie algorytmu Szybkiego Wyszukiwania oparte jest na zasadzie Dziel i Zwyciężaj (ang. Divide and Conquer). Polega ona na rekurencyjnym podziale pierwotnego problemu na problemy prostsze tego samego typu. Podział wykonywany jest dotąd, aż rozwiązanie stanie się oczywiste. Następnie z rozwiązań podproblemów tworzymy rozwiązania na wyższych poziomach aż dojdziemy do rozwiązania problemu pierwotnego W przypadku Szybkiego Wyszukiwania postępujemy w sposób następujący: W zbiorze Z wybieramy dowolny element. Oznaczmy go
|
Podstawowym problemem w algorytmie Szybkiego Wyszukiwania jest podział zbioru
na dwa podzbiory, partycje, o wymaganych własnościach. Ponieważ
ip – przechowuje indeks pierwszego elementu podzbioru – początek ik – przechowuje indeks ostatniego elementu podzbioru – koniec
Początkowo podzbiór obejmuje cały
ip = 0 ik = n-1, gdzie n jest liczbą elementów tablicy Z
| Odwzorowanie zbioru Z w tablicy Z | ||||||||||
|---|---|---|---|---|---|---|---|---|---|---|
| Z[0] | Z[1] | Z[2] | Z [3] | … | … | … | … | Z[n-3] | Z[n-2] | Z[n-1] |
| ip | ik | |||||||||
Element zwrotny można wybierać na różne sposoby.
Poniżej podajemy algorytm partycjonowania zbioru wg pierwszego elementu partycji głównej. Jeśli zechcemy partycjonować wg innego elementu zwrotnego, to po prostu wymieniamy wybrany element zwrotny z pierwszym elementem partycji i dalej wykorzystujemy podany poniżej algorytm.
K01: v ← Z[ip] ; zapamiętujemy wartość elementu zwrotnego K02: i ← ip ; indeksem i będziemy szukali elementów ≥ v K03: j ← ik+1 ; indeksem j będziemy szukali elementów ≤ v K04: Dopóki i < j: ; w pętli elementy większe umieszczamy w ZP, wykonuj kroki K05…K09 ; a mniejsze w ZL K05: i ← i+1 ; przesuwamy się na następną pozycję w ZL K06: Jeśli Z[i] < v, ; szukamy elementu, który nie należy do ZL to idź do kroku K05 K07: j ← j-1 ; przesuwamy się na poprzednią pozycję w ZP K08: Jeśli Z[j] > v, ; szukamy elementu, który nie należy do ZP to idź do kroku K07 K09: Jeśli i < j, ; znalezione elementy zamieniamy miejscami to Z[i] ↔ Z[j] K10: Z[ip] ← Z[j] ; zwalniamy pozycję elementu zwrotnego K11: Z[j] ← v ; na zwolnionej pozycji umieszczamy element zwrotny K12: Zakończ z wynikiem j ; kończymy zwracając pozycję elementu zwrotnego
|
Uwaga: Zanim uruchomisz program, przeczytaj wstęp do tego artykułu, w którym wyjaśniamy funkcje tych programów oraz sposób korzystania z nich. |
| Program wypełnia tablicę 20 elementową Z liczbami pseudolosowymi z zakresu od 0 do 999. Następnie dokonuje partycjonowania tablicy wg pierwszego elementu. Wyświetla zawartość tablicy Z z zaznaczeniem punktu podziałowego. |
Pascal// Podział zbioru na dwie partycje
// Data: 17.05.2008
// (C)2020 mgr Jerzy Wałaszek
//--------------------------------
program prg;
const N = 20;
var
Z : array [0..N] of integer;
i, j, v, x : integer;
begin
randomize;
// Przygotowujemy tablicę Z[]
for i := 0 to N-1 do
Z[i] := random(1000);
// Na końcu Z[] umieszczamy wartownika
Z[N] := 1000;
// Wyświetlamy Z[] przed podziałem
for i := 0 to N-1 do
write(Z[i]:4);
writeln;
// Dzielimy Z[] na dwie partycje
v := Z[0]; i := 0; j := N;
while i < j do
begin
repeat inc(i); until Z[i] >= v;
repeat dec(j); until Z[j] <= v;
if i < j then
begin
x := Z[i];
Z[i] := Z[j];
Z[j] := x;
end;
end;
Z[0] := Z[j];
Z[j] := v;
// Wyświetlamy Z[] po podziale
for i := 0 to N-1 do
if i = j then
write('|---')
else
write('----');
for i := 0 to N-1 do
if i = j then
write('|', Z[i]:3)
else
write(Z[i]:4);
for i := 0 to N-1 do
if i = j then
write('|---')
else
write('----');
writeln;
writeln;
end. |
// Podział zbioru na dwie partycje
// Data: 17.05.2008
// (C)2020 mgr Jerzy Wałaszek
//--------------------------------
#include <iostream>
#include <iomanip>
#include <cstdlib>
#include <ctime>
using namespace std;
const int N = 20;
int main()
{
int Z[N+1], i, j, v;
srand(time(NULL));
// Przygotowujemy tablicę Z[]
for(i = 0; i < N; i++)
Z[i] = rand() % 1000;
// Na końcu Z[] umieszczamy wartownika
Z[N] = 1000;
// Wyświetlamy Z[] przed podziałem
for(i = 0; i < N; i++)
cout << setw(4) << Z[i];
cout << endl;
// Dzielimy Z[] na dwie partycje
v = Z[0]; i = 0; j = N;
while(i < j)
{
while(Z[++i] < v);
while(Z[--j] > v);
if(i < j) swap(Z[i], Z[j]);
}
Z[0] = Z[j]; Z[j] = v;
// Wyświetlamy Z[] po podziale
for(i = 0; i < N; i++)
cout << (i == j ? "|---": "----");
for(i = 0; i < N; i++)
if(i == j)
cout << "|" << setw(3) << Z[i];
else
cout << setw(4) << Z[i];
for(i = 0; i < N; i++)
cout << (i == j ? "|---" : "----");
cout << endl << endl;
return 0;
}
|
Basic' Podział zbioru na dwie partycje
' Data: 17.05.2008
' (C)2020 mgr Jerzy Wałaszek
'--------------------------------
Const N = 20
Dim As Integer Z(N), i, j, v
Randomize
' Przygotowujemy tablicę Z[]
For i = 0 To N-1
Z(i) = Cint(Rnd*999)
Next
' Na końcu Z[] umieszczamy wartownika
Z(N) = 1000
' Wyświetlamy Z[] przed podziałem
For i = 0 To N-1
Print Using "####";Z(i);
Next
Print
' Dzielimy Z[] na dwie partycje
v = Z(0): i = 0: j = N
While i < j
Do: i += 1: Loop Until Z(i) >= v
Do: j -= 1: Loop Until Z(j) <= v
If i < j Then Swap Z(i), Z(j)
Wend
Z(0) = Z(j): Z(j) = v
' Wyświetlamy Z[] po podziale
For i = 0 To N-1
If i = j Then
Print "|---";
Else
Print "----";
End If
Next
For i = 0 To N-1
If i = j Then
Print Using "|###";Z(i);
Else
Print Using "####";Z(i);
End If
Next
For i = 0 To N-1
If i = j Then
Print "|---";
Else
Print "----";
End If
Next
Print
Print
End
|
Python
(dodatek)# Podział zbioru na dwie partycje
# Data: 29.02.2024
# (C)2024 mgr Jerzy Wałaszek
#--------------------------------
import random
N = 20 # Ilość liczb
# Przygotowujemy tablicę Z[]
z = [random.randrange(1000) for i in range(N)]
# Na końcu Z[] umieszczamy wartownika
z.append(1000)
# Wyświetlamy Z[] przed podziałem
for i in range(N):
print("%4d" % z[i], end="")
print()
print()
# Dzielimy Z[] na dwie partycje
v, i, j = z[0], 0, N
while i < j:
while True:
i += 1
if z[i] >= v: break
while True:
j -= 1
if z[j] <= v: break
if i < j: z[i], z[j] = z[j], z[i]
z[0], z[j] = z[j], v
# Wyświetlamy Z[] po podziale
for i in range(N):
if i == j:
print("|---", end="")
else:
print("----", end="")
for i in range(N):
if i == j:
print("|%3d" % z[i], end="")
else:
print("%4d" % z[i], end="")
for i in range(N):
if i == j:
print("|---", end="")
else:
print("----", end="")
print()
print()
|
| Wynik: |
382 983 4 321 701 483 706 214 816 904 310 366 408 372 896 583 808 308 774 212 --------------------------------|----------------------------------------------- 310 212 4 321 308 372 366 214|382 904 816 706 408 483 896 583 808 701 774 983 --------------------------------|----------------------------------------------- |
K01:i p ← 0 ; startowa partycja obejmuje cały zbiór Z K02:i k ←n -1 K03:p v ← Dziel_na_partycje(Z ,i p,i k) ; dokonujemy podziału ; na dwie partycje ZL i ZP K04: Jeślip v =n -k , ; sprawdzamy, czy znaleźliśmy to zakończ z wynikiemZ [p v] ; poszukiwany element K05: Jeślin -k <p v, ; jeśli nie, to w zależności idź do kroku K08 ; od pozycji elementu zwrotnego K06:i p ←p v+1 ; elementu będziemy szukać w ZP K07: Idź do kroku K03 ; lub K08:i k ←p v-1 ; elementu będziemy szukać w ZL K09: Idź do kroku K03
|
Uwaga: Zanim uruchomisz program, przeczytaj wstęp do tego artykułu, w którym wyjaśniamy funkcje tych programów oraz sposób korzystania z nich. |
| Program wypełnia tablicę 20 elementową
|
Pascal// Szybkie wyszukiwanie
// Data: 18.05.2008
// (C)2020 mgr Jerzy Wałaszek
//--------------------------------
program prg;
const N = 20;
// Funkcja dzieli zbiór Z na dwie partycje:
// ZL-elementy mniejsze od elementu zwrotnego
// ZP-elementy większe od elementu zwrotnego
// Zwraca pozycję elementu zwrotnego
//-------------------------------------------
function Dziel_na_partycje(var Z : array of integer;
ip, ik : integer)
: integer;
var i, v, x : integer;
begin
v := Z[ip]; i := ip; inc(ik);
while i < ik do
begin
repeat inc(i); until Z[i] >= v;
repeat dec(ik); until Z[ik] <= v;
if i < ik then
begin
x := Z[i]; Z[i] := Z[ik]; Z[ik] := x;
end;
end;
Z[ip] := Z[ik]; Z[ik] := v;
Dziel_na_partycje := ik;
end;
var
Z : array [0..N] of integer;
i, ip, ik, k, pv : integer;
begin
randomize;
// Przygotowujemy tablicę Z[]
for i := 0 to N-1 do
Z[i] := random(1000);
// Na końcu Z[] umieszczamy wartownika
Z[N] := 1000;
// Wyświetlamy Z[] przed podziałem
for i := 0 to N-1 do
write(Z[i]:4);
writeln;
// Losujemy k
k := random(20)+1;
// Szukamy k-tego największego elementu
ip := 0; ik := N-1;
while true do
begin
pv := Dziel_na_partycje(Z, ip, ik);
if pv = N-k then
break
else
if N-k < pv then
ik := pv-1
else
ip := pv+1;
end;
// Wyświetlamy k i Z[N-k]
writeln(' k = ', k,
', k-ty max element = ', Z[N-k]);
writeln;
// Wyświetlamy Z[] po podziale
for i := 0 to N-1 do
write(Z[i]:4);
for i := 0 to pv-1 do
write(' ');
writeln(' ---');
writeln;
end.
|
// Szybkie wyszukiwanie
// Data: 18.05.2008
// (C)2020 mgr Jerzy Wałaszek
//--------------------------------
#include <iostream>
#include <iomanip>
#include <cstdlib>
#include <ctime>
using namespace std;
const int N = 20;
// Funkcja dzieli zbiór Z na dwie partycje:
// ZL-elementy mniejsze od elementu zwrotnego
// ZP-elementy większe od elementu zwrotnego
// Zwraca pozycję elementu zwrotnego
//-------------------------------------------
int Dziel_na_partycje(int *Z,
int ip,
int ik)
{
int i, v;
v = Z[ip]; i = ip; ik++;
while(i < ik)
{
while(Z[++i] < v);
while(Z[--ik] > v);
if(i < ik) swap(Z[i], Z[ik]);
}
Z[ip] = Z[ik]; Z[ik] = v;
return ik;
}
int main()
{
int Z[N+1], i, ip, ik, k, pv;
srand(time(NULL));
// Przygotowujemy tablicę Z[]
for(i = 0; i < N; i++)
Z[i] = rand() % 1000;
// Na końcu Z[] umieszczamy wartownika
Z[N] = 1000;
// Wyświetlamy Z[] przed podziałem
for(i = 0; i < N; i++)
cout << setw(4) << Z[i];
cout << endl;
// Losujemy k
k = 1+(rand() % 20);
// Szukamy k-tego największego elementu
ip = 0; ik = N-1;
while(true)
{
pv = Dziel_na_partycje(Z, ip, ik);
if(pv == N-k)
break;
else
if(N-k < pv)
ik = pv-1;
else
ip = pv+1;
}
// Wyświetlamy k i Z[N-k]
cout << "k = " << k
<< ", k-ty max element = " << Z[N-k]
<< endl << endl;
// Wyświetlamy Z[] po podziale
for(i = 0; i < N; i++) cout << setw(4) << Z[i];
for(i = 0; i < pv; i++) cout << " ";
cout << " ---\n\n";
return 0;
} |
Basic' Szybkie wyszukiwanie
' Data: 18.05.2008
' (C)2020 mgr Jerzy Wałaszek
'--------------------------------
Const N = 20
' Funkcja dzieli zbiór Z na dwie partycje:
' ZL-elementy mniejsze od elementu zwrotnego
' ZP-elementy większe od elementu zwrotnego
' Zwraca pozycję elementu zwrotnego
'-------------------------------------------
Function Dziel_na_partycje(Z() As Integer, _
Byval ip As Integer, _
Byval ik As Integer) _
As Integer
Dim As Integer i, v
v = Z(ip): i = ip: ik += 1
While i < ik
Do: i += 1: Loop Until Z(i) >= v
Do: ik -= 1: Loop Until Z(ik) <= v
If i < ik Then Swap Z(i), Z(ik)
Wend
Z(ip) = Z(ik): Z(ik) = v
Dziel_na_partycje = ik
End Function
Dim As Integer Z(N), i, ip, ik, k, pv
Randomize
' Przygotowujemy tablicę Z()
For i = 0 To N-1
Z(i) = Cint(Rnd*999)
Next
' Na końcu Z() umieszczamy wartownika
Z(N) = 1000
' Wyświetlamy Z() przed podziałem
For i = 0 To N-1
Print Using "####";Z(i);
Next
' Losujemy k
k = Cint(Rnd * 19)+1
' Szukamy k-tego największego elementu
ip = 0: ik = N-1
Do
pv = Dziel_na_partycje(Z(), ip, ik)
If pv = N-k Then Exit Do
If N-k < pv Then
ik = pv-1
Else
ip = pv+1
End If
Loop
' Wyświetlamy k i Z(N-k)
Print
Print " k =";k;", k-ty max element =";Z(N-k)
Print
' Wyświetlamy Z() po podziale
For i = 0 To N-1
Print Using "####";Z(i);
Next
For i = 0 To pv-1
Print " ";
Next
Print " ---"
Print
End
|
Python
(dodatek)# Szybkie wyszukiwanie
# Data: 18.05.2008
# (C)2020 mgr Jerzy Wałaszek
#--------------------------------
import random
N = 20
# Funkcja dzieli podany zbiór Z na dwie partycje:
# ZL-elementy mniejsze od elementu zwrotnego
# ZP-elementy większe od elementu zwrotnego
# Zwraca pozycję elementu zwrotnego
#------------------------------------------------
def dziel_na_partycje(z, ip, ik):
v = z[ip]
i = ip
ik += 1
while i < ik:
while True:
i += 1
if z[i] >= v: break
while True:
ik -= 1
if z[ik] <= v: break
if i < ik:
z[i], z[ik] = z[ik], z[i]
z[ip], z[ik] = z[ik], v
return ik
# Przygotowujemy tablicę Z[]
z = [random.randrange(1000) for i in range(N)]
# Na końcu Z[] umieszczamy wartownika
z.append(1000)
# Wyświetlamy Z[] przed podziałem
for i in range(N):
print("%4d" % z[i], end="")
print()
# Losujemy k
k = random.randrange(1, 21)
# Szukamy k-tego największego elementu
ip, ik = 0, N-1
while True:
pv = dziel_na_partycje(z, ip, ik)
if pv == N-k: break
if N-k < pv:
ik = pv-1
else:
ip = pv+1
# Wyświetlamy k i Z[N-k]
print()
print(" k =", k, ", k-ty max element =", z[N-k])
print()
# Wyświetlamy Z[] po podziale
for i in range(N):
print("%4d" % z[i], end="")
for i in range(pv):
print(" ", end="")
print(" ---")
print()
|
| Wynik: |
332 996 106 811 623 676 710 856 424 828 61 541 862 736 38 851 453 687 378 114
k = 10, k-ty max element = 851
106 996 332 676 623 811 424 856 710 828 851 541 862 736 38 687 453 378 61 114
---
|
![]() |
Zespół Przedmiotowy Chemii-Fizyki-Informatyki w I Liceum Ogólnokształcącym im. Kazimierza Brodzińskiego w Tarnowie ul. Piłsudskiego 4 ©2026 mgr Jerzy Wałaszek |
Materiały tylko do użytku dydaktycznego. Ich kopiowanie i powielanie jest dozwolone pod warunkiem podania źródła oraz niepobierania za to pieniędzy.
Pytania proszę przesyłać na adres email:
Serwis wykorzystuje pliki cookies. Jeśli nie chcesz ich otrzymywać, zablokuj je w swojej przeglądarce.
Informacje dodatkowe.