|
Serwis Edukacyjny Nauczycieli w I-LO w Tarnowie
Materiały głownie dla uczniów liceum |
Wyjście Spis treści Wstecz Dalej
Autor artykułu: mgr Jerzy Wałaszek |
©2026 mgr Jerzy Wałaszek
|
W tym rozdziale nauczymy się rozbierać kopiec. Zasada jest następująca:
Przykład:
Dokonaj rozbioru następującego kopca:

| Operacja | Opis | ||
![]() 9 |
Rozbiór kopca rozpoczynamy od korzenia,
który usuwamy ze struktury kopca. W miejsce korzenia wstawiamy ostatni liść. |
||
|
![]() |
![]() |
Poprzednia operacja zaburzyła strukturę kopca. Idziemy zatem od korzenia w dół struktury przywracając warunek kopca - przodek większy lub równy od swoich potomków. Praktycznie polega to na zamianie przodka z największym potomkiem. Operację kontynuujemy dotąd, aż natrafimy na węzły spełniające warunek kopca. |
8 9 |
Usuwamy z kopca kolejny korzeń zastępując go ostatnim liściem. |
||
|
![]() |
![]() |
W nowym kopcu przywracamy warunek kopca. |
7 8 9 |
Usuwamy z kopca kolejny korzeń zastępując go ostatnim liściem |
||
|
![]() |
W nowym kopcu przywracamy warunek kopca. W tym przypadku już po pierwszej wymianie węzłów warunek koca jest zachowany w całej strukturze. |
|
5 7 8 9 |
Usuwamy z kopca kolejny korzeń zastępując go ostatnim liściem |
||
![]() |
![]() |
Przywracamy warunek kopca w strukturze. | |
![]() 4 5 7 8 9 |
Usuwamy z kopca kolejny korzeń zastępując go ostatnim liściem |
||
|
![]() |
Przywracamy warunek kopca w strukturze. |
|
![]() 2 4 5 7 8 9 |
Usuwamy z kopca kolejny korzeń zastępując go ostatnim liściem. |
||
|
1 2 4 5 7 8 9 |
Po wykonaniu poprzedniej operacji usunięcia
w kopcu pozostał tylko jeden element - usuwamy go. Zwróć uwagę, iż usunięte z kopca elementy tworzą ciąg uporządkowany. |
||
Operację rozbioru kopca można przeprowadzić w miejscu. Jeśli mamy zbiór d[ ] ze strukturą kopca, to idąc od końca zbioru (ostatnie liście drzewa) w kierunku początku zamieniamy elementy z pierwszym elementem zbioru (korzeń drzewa), a następnie poruszając się od korzenia w dół przywracamy warunek kopca w kolejno napotykanych węzłach.
| d[ ] | - Zbiór zawierający poprawną strukturę kopca. Elementy są numerowane począwszy od 1. |
| n | - Ilość elementów w zbiorze, n ∈ N |
| d[ ] | - Zbiór zawierający elementy pobrane z kopca ułożone w porządku rosnącym |
| i | - zmienna licznikowa pętli pobierającej kolejne elementy z kopca, i ∈ N, i ∈ {n,n-1,...,2} |
| j,k | - indeksy elementów leżących na ścieżce w dół od korzenia, j,k ∈ N |
| m | - indeks większego z dwóch elementów potomnych, m ∈ N |
| K01: | Dla i = n, n - 1, ..., 2: wykonuj kroki K02...K08 |
| K02: | d[1] ↔ d[i] |
| K03: | j ← 1; k ← 2 |
| K04: | Dopóki (k
< i): wykonuj kroki K05...K08 |
| K05: | Jeżeli
(k
+ 1 < i) ∧ (d[k
+ 1] > d[k]), to m ← k + 1 inaczej m ← k |
| K06: | Jeżeli d[m]
≤ d[j], to wyjdź z pętli K04 i kontynuuj następny obieg pętli K01 |
| K07: | d[j] ↔ d[m] |
| K08: | j ← m; k ← j + j |
| K09: | Zakończ |

Rozbiór kopca wykonywany jest w dwóch zagnieżdżonych pętlach. Pętla nr 1 zamienia miejscami kolejne liście ze spodu drzewa z korzeniem. Zadaniem pętli nr 2 jest przywrócenie w strukturze warunku kopca.
Pętla nr 1 przebiega wstecz indeksy elementów zbioru d[ ] poczynając od indeksu n a kończąc na indeksie 2. Element i-ty jest wymieniany z korzeniem kopca. Po tej wymianie rozpoczynamy w pętli nr 2 przeglądanie drzewa od korzenia w dół. Zmienna j przechowuje indeks przodka, zmienna k przechowuje indeks lewego potomka. Pętla nr 2 kończy się, gdy węzeł j-ty nie posiada potomków. Wewnątrz pętli wyznaczamy w zmiennej m indeks większego z dwóch węzłów potomnych. Następnie sprawdzamy, czy w węźle nadrzędnym j-tym jest zachowany warunek kopca. Jeśli tak, to następuje wyjście z pętli nr 2. W przeciwnym razie zamieniamy miejscami węzeł nadrzędny j-ty z jego największym potomkiem m-tym i za nowy węzeł nadrzędny przyjmujemy węzeł m-ty. W zmiennej k wyznaczamy indeks jego lewego potomka i kontynuujemy pętlę nr 2.
Po wyjściu z pętli nr 2 zmniejszamy zmienną i o 1 - przenosimy się do kolejnego, ostatniego liścia drzewa i kontynuujemy pętlę nr 1.
W celu wyznaczenia klasy złożoności obliczeniowej algorytmu rozbioru kopca zauważamy, iż pętla zewnętrzna nr 1 wykona się n - 1 razy, a w każdym obiegu tej pętli pętla wewnętrzna wykona się maksymalnie log2n razy. Daje to zatem górne oszacowanie O(n log n) w przypadku pesymistycznym oraz O(n) w przypadku optymistycznym, który wystąpi tylko wtedy, gdy zbiór d[ ] będzie zbudowany z ciągu tych samych elementów.
C++// Rozbiór kopca
//--------------
// (C)2012 mgr Jerzy Wałaszek
// I Liceum Ogólnokształcące
// w Tarnowie
#include <iostream>
#include <iomanip>
#include <cstdlib>
#include <time.h>
using namespace std;
int main()
{
const int N = 15; // liczba elementów
int d[N + 1],i,j,k,m,x;
srand((unsigned)time(NULL));
cout << " Rozbior kopca\n"
"----------------------\n"
"(C)2005 Jerzy Walaszek\n\n"
"Zbior wejsciowy ze struktura kopca:\n\n";
// W zbiorze d konstruujemy kopiec
d[1] = 9;
for(i = 2; i <= N; i++)
d[i] = rand() % (d[i / 2] + 1);
// Prezentujemy kopiec
for(i = 1; i <= N; i++)
cout << setw(2) << d[i];
cout << endl << endl;
x = (N + 1) / 2;
k = 2;
for(i = 1; i <= N; i++)
{
for(j = 1; j < x; j++)
cout << " ";
cout << d[i];
for(j = 1; j <= x; j++)
cout << " ";
if(i + 1 == k)
{
k += k;
x /= 2;
cout << endl;
}
}
// Rozbieramy kopiec
for(i = N; i > 1; i--)
{
swap(d[1],d[i]);
j = 1; k = 2;
while(k < i)
{
if((k + 1 < i) &&
(d[k + 1] > d[k]))
m = k + 1;
else
m = k;
if(d[m] <= d[j]) break;
swap(d[j],d[m]);
j = m;
k = j + j;
}
}
// Wyświetlamy wynik rozbioru kopca
cout << endl
<< "Zbior wyjsciowy po rozbiorze kopca:\n\n";
for(i = 1; i <= N; i++)
cout << setw(2) << d[i];
cout << endl << endl;
// Gotowe
system("pause");
return 0;
}
|
Pascal// Rozbiór kopca
//--------------
// (C)2012 mgr Jerzy Wałaszek
// I Liceum Ogólnokształcące
// w Tarnowie
program kopiec;
const N = 15; // liczba elementów
var
d : array[1..N] of integer;
i,j,k,m,x : integer;
begin
randomize;
writeln(' Rozbior kopca');
writeln('----------------------');
writeln('(C)2005 Jerzy Walaszek');
writeln;
// W zbiorze d konstruujemy kopiec
d[1] := 9;
for i := 2 to N do
d[i] := random(d[i div 2] + 1);
// Prezentujemy kopiec
writeln('Zbior wejsciowy ze struktura kopca:');
writeln;
for i := 1 to N do
write(d[i]:2);
writeln; writeln;
x := (N + 1) div 2;
k := 2;
for i := 1 to N do
begin
for j := 1 to x - 1 do
write(' ');
write(d[i]);
for j := 1 to x do
write(' ');
if i + 1 = k then
begin
k := k + k;
x := x div 2;
writeln;
end;
end;
// Rozbieramy kopiec
for i := N downto 2 do
begin
x := d[1];
d[1] := d[i];
d[i] := x;
j := 1; k := 2;
while k < i do
begin
if (k + 1 < i) and
(d[k + 1] > d[k]) then
m := k + 1
else
m := k;
if d[m] <= d[j] then break;
x := d[j];
d[j] := d[m];
d[m] := x;
j := m;
k := j + j;
end;
end;
// Wyświetlamy wynik rozbioru kopca
writeln;
writeln('Zbior wyjsciowy po rozbiorze kopca:');
writeln;
for i := 1 to N do
write(d[i]:2);
// Gotowe
writeln;
writeln;
write('Nacisnij klawisz Enter...');
readln;
end.
|
Basic' Rozbiór kopca
'--------------
' (C)2012 mgr Jerzy Wałaszek
' I Liceum Ogólnokształcące
' w Tarnowie
CONST N = 15 ' liczba elementów
DIM AS INTEGER d(N),i,j,k,m,x
RANDOMIZE
PRINT " Rozbior kopca"
PRINT "----------------------"
PRINT "(C)2005 Jerzy Walaszek"
PRINT
' W zbiorze d konstruujemy kopiec
d(1) = 9
FOR i = 2 TO N:
d(i) = INT(RND * (d(i \ 2) + 1))
NEXT
' Prezentujemy kopiec
PRINT "Zbior wejsciowy ze struktura kopca:"
PRINT
FOR i = 1 TO N
PRINT USING "##";d(i);
NEXT
PRINT
PRINT
x = (N + 1) \ 2
k = 2
FOR i = 1 TO N
FOR j = 1 TO x - 1
PRINT " ";
NEXT
PRINT USING "#";d(i);
FOR j = 1 TO x
PRINT " ";
NEXT
IF i + 1 = k THEN
k = k + k
x = x \ 2
PRINT
END IF
NEXT
' Rozbieramy kopiec
FOR i = N TO 2 STEP -1
SWAP d(1),d(i)
j = 1
k = 2
WHILE k < i
IF (k + 1 < i) AND _
(d(k + 1) > d(k)) THEN
m = k + 1
ELSE
m = k
END IF
IF d(m) <= d(j) THEN EXIT WHILE
SWAP d(j),d(m)
j = m
k = j + j
WEND
NEXT
' Wyświetlamy wynik rozbioru kopca
PRINT
PRINT "Zbior wyjsciowy po rozbiorze kopca:"
PRINT
FOR i = 1 TO N
PRINT USING "##";d(i);
NEXT
PRINT
PRINT
' Gotowe
PRINT "Nacisnij klawisz Enter..."
SLEEP
END
|
Python
(dodatek)# Rozbiór kopca
#--------------
# (C)2026 mgr Jerzy Wałaszek
# I Liceum Ogólnokształcące
# w Tarnowie
import random
n = 15 # liczba elementów
print(" Rozbiór kopca")
print("----------------------")
print("(C)2026 Jerzy Walaszek")
print()
# W zbiorze d konstruujemy kopiec
d = [9] * 2
for i in range(2,n +1):
d.append(random.randrange(d[i // 2] +1))
# Prezentujemy kopiec
print("Zbiór wejściowy ze strukturą kopca:")
print()
for i in range(1,n + 1):
print("%2d" % (d[i]),end="")
print()
print()
x = (n + 1) // 2
k = 2
for i in range(1,n + 1):
for j in range(1,x):
print(" ",end="")
print("%1d" % (d[i]),end="")
for j in range(1,x+1):
print(" ",end="")
if i + 1 == k:
k += k
x //= 2
print()
# Rozbieramy kopiec
for i in reversed(range(2,n + 1)):
d[1],d[i] = d[i],d[1]
j = 1
k = 2
while k < i:
if (k + 1 < i) and \
(d[k + 1] > d[k]):
m = k + 1
else:
m = k
if d[m] <= d[j]: break
d[j],d[m] = d[m],d[j]
j = m
k = j + j
# Wyświetlamy wynik rozbioru kopca
print()
print("Zbior wyjściowy po rozbiorze kopca:")
print()
for i in range(1,n + 1):
print("%2d" % (d[i]),end="")
print()
print()
# Gotowe
input("Naciśnij Enter...")
|
| Wynik: |
Rozbiór kopca
----------------------
(C)2026 Jerzy Walaszek
Zbiór wejściowy ze strukturą kopca:
9 4 9 0 2 7 8 0 0 1 0 5 1 2 2
9
4 9
0 2 7 8
0 0 1 0 5 1 2 2
Zbiór wyjściowy po rozbiorze kopca:
0 0 0 0 1 1 2 2 2 4 5 7 8 9 9
Naciśnij Enter...
|
JavaScript<html>
<head>
</head>
<body>
<div style="overflow-x: auto;"
align="center">
<table
border="0"
cellpadding="4"
style="border-collapse:
collapse">
<tr>
<td nowrap>
<form
name="frm"
style="text-align:
center;
background-color:
#E7E7DA">
<b>
Rozbiór Kopca
</b><br>
(C)2026 mgr
Jerzy Wałaszek
<hr/>
<input
onclick="main()"
value="Rozbierz Kopiec"
name="B1"
type="button">
<hr/>
<div id="out">.</div>
</form>
</td>
</tr>
</table>
</div>
<script language="javascript">
// Rozbiór kopca
//--------------
// (C)2005 mgr Jerzy Wałaszek
// I Liceum Ogólnokształcące
// w Tarnowie
function main()
{
var N = 15;
var d = new Array(N+1);
var i,j,k,x,t;
// W zbiorze d konstruujemy
// kopiec
d[1] = 9;
for(i = 2; i <= N; i++)
d[i] = Math.floor(
Math.random() *
(d[Math.floor(i / 2)] +
1));
// Prezentujemy kopiec
t = "";
for(i = 1; i <= N; i++)
t += d[i] + " ";
t += "<br/><br/>";
x = Math.floor((N + 1) / 2);
k = 2;
for(i = 1; i <= N; i++)
{
for(j = 1; j < x; j++)
t += " ";
t += d[i];
for(j = 1; j <= x; j++)
t += " ";
if(i + 1 == k)
{
k += k;
x = Math.floor(x / 2);
t += "<br/>";
}
}
// Rozbieramy kopiec
for(i = N; i > 1; i--)
{
x = d[1];
d[1] = d[i];
d[i] = x;
j = 1;
k = 2;
while(k < i)
{
if((k + 1 < i) &&
(d[k + 1] > d[k]))
m = k + 1;
else
m = k;
if(d[m] <= d[j])
break;
x = d[j];
d[j] = d[m];
d[m] = x;
j = m;
k = j + j;
}
}
// Wyświetlamy wynik
// rozbioru kopca
t += "<br/>";
for(i = 1; i <= N; i++)
t += d[i] + " ";
// Gotowe
t = "<pre>" + t +
"</pre>";
document.getElementById("out")
.innerHTML = t;
}
</script>
</body>
</html> |
![]() |
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.