|
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
|
Dla danego grafu należy znaleźć jedno z drzew rozpinających.
Drzewo rozpinające (ang. spanning tree) jest drzewem, które zawiera wszystkie wierzchołki grafu. Dany graf może posiadać wiele różnych drzew rozpinających:
![]() Graf podstawowy |
![]() Drzewo rozpinające nr 1 |
![]() Drzewo rozpinające nr 2 |
Drzewo rozpinające powstaje przez usunięcie z grafu krawędzi, które tworzą cykl. Drzewo rozpinające możemy utworzyć przy pomocy przejścia DFS (drzewo rozpinające w głąb) lub BFS (drzewo rozpinające wszerz). Zasada tworzenia takiego drzewa jest bardzo prosta: w trakcie przechodzenia przez graf zapamiętywane są tylko przebyte krawędzie. Ponieważ ani DFS, ani BFS nie przechodzą do wierzchołków wcześniej odwiedzonych, metoda ta nie będzie zapamiętywała krawędzi tworzących pętle, czyli to, co zostanie, będzie drzewem rozpinającym. Drzewo rozpinające możemy tworzyć w podobnej strukturze jak sam graf, np. w tablicy list sąsiedztwa.
Do utworzenia drzewa rozpinającego w głąb (ang. Depth-First Spanning Tree) wykorzystujemy algorytm DFS. W trakcie przechodzenia przez graf zapamiętujemy w osobnej strukturze przebyte krawędzie. Po zakończeniu przejścia struktura ta będzie zawierała drzewo rozpinające w głąb.
K01: vs[v] ← true ; oznaczamy wierzchołek v ; jako odwiedzony K02: Dla każdego sąsiada u wierzchołka v: wykonuj kroki K03…K05 K03: Jeśli vs[u] = true, ; szukamy nieodwiedzonych to następny obieg pętli K02 ; jeszcze sąsiadów K04: Dodaj wierzchołek u do listy T[v] ; dodajemy krawędź v-u ; do drzewa rozpinającego K05: DFSTree(u,graf,T,vs) ; rekurencyjnie tworzymy ; drzewo rozpinające K06 Zakończ
Uwaga: jeśli drzewo rozpinające ma być grafem nieskierowanym, to w kroku K04 należy również dodać wierzchołek v do listy T [u], aby powstała krawędź biegnąca z powrotem od wierzchołka u do v.
|
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 wczytuje definicję grafu nieskierowanego oraz numer wierzchołka startowego. Następnie tworzy jedno z drzew rozpinających w głąb i wyświetla wyniki w oknie konsoli. |
|
Przykładowe dane (ostatnia
czerwona liczba określa wierzchołek startowy, który będzie
korzeniem drzewa rozpinającego):
|
Pascal// Drzewo rozpinające w głąb
// Data: 22.09.2013
// (C)2013 mgr Jerzy Wałaszek
//---------------------------
program DFS_tree;
// Typ listy jednokierunkowej
type
PSLel = ^SLel;
SLel = record
next : PSLel;
v : integer;
end;
TList = array of PSLel;
// Zmienne globalne
//-----------------
var
// Tablica list sąsiedztwa grafu
graf : TList;
// Tablica list sąsiedztwa
// drzewa rozpinającego
T : TList;
// Tablica odwiedzin
vs : array of boolean;
// Rekurencyjna procedura tworzenia
// drzewa rozpinającego w głąb
// v - numer wierzchołka startowego
// reszta zmiennych globalna
//---------------------------------
procedure DFSTree(v : integer);
var
p, r : PSLel;
u : integer;
begin
// Oznaczamy wierzchołek
// jako odwiedzony
vs[v] := true;
// Przeglądamy sąsiadów
p := graf[v];
while p <> nil do
begin
// u-numer sąsiada
u := p^.v;
// Interesują nas tylko
// nieodwiedzeni sąsiedzi
if not vs[u] then
begin
// Dodajemy u do listy T[v]
new(r);
r^.v := u;
r^.next := T[v];
T[v] := r;
// Rekurencyjnie
// tworzymy drzewo
DFSTree(u);
end;
// Następny sąsiad
p := p^.next;
end;
end;
// **********************
// *** PROGRAM GŁÓWNY ***
// **********************
var
i, n, m, v1, v2 : integer;
p, r : PSLel;
begin
// Czytamy liczbę
// wierzchołków i krawędzi
read(n, m);
// Tworzymy tablicę
// list sąsiedztwa grafu
SetLength(graf, n);
// Tworzymy tablicę list
// sąsiedztwa drzewa
// rozpinającego
SetLength(T, n);
// Tworzymy tablicę odwiedzin
SetLength(vs, n);
// Tablice wypełniamy
// pustymi listami
for i := 0 to n-1 do
begin
graf[i] := nil;
T[i] := nil;
vs[i] := false;
end;
// Odczytujemy kolejne
// definicje krawędzi
for i := 1 to m do
begin
// Wierzchołek startowy
// i końcowy krawędzi
read(v1, v2);
// Tworzymy nowy element
new(p);
// Numerujemy go jako v2
p^.v := v2;
// Dodajemy go na początek
// listy A[v1]
p^.next := graf[v1];
graf[v1] := p;
// Teraz krawędź
// w odwrotną stronę
new(p);
p^.v := v1;
p^.next := graf[v2];
graf[v2] := p;
end;
// Tworzymy drzewo
// rozpinające w głąb
//-------------------
// Czytamy wierzchołek startowy
read(v1);
DFSTree(v1);
// Wyświetlamy tablicę list
// sąsiedztwa drzewa
// rozpinającego
writeln;
for i := 0 to n-1 do
begin
write(i:2, ' : ');
p := T[i];
while p <> nil do
begin
write(p^.v, ' ');
p := p^.next;
end;
writeln;
end;
// Usuwamy dynamiczne
// struktury danych
for i := 0 to n-1 do
begin
p := graf[i];
while p <> nil do
begin
r := p;
p := p^.next;
dispose(r);
end;
p := T[i];
while p <> nil do
begin
r := p;
p := p^.next;
dispose(r);
end;
end;
SetLength(graf, 0);
SetLength(T, 0);
SetLength(vs, 0);
writeln;
end.
|
// Drzewo rozpinające w głąb
// Data: 22.09.2013
// (C)2013 mgr Jerzy Wałaszek
//---------------------------
#include <iostream>
#include <iomanip>
using namespace std;
// Typ listy jednokierunkowej
struct SLel
{
SLel * next;
int v;
};
// Zmienne globalne
//-----------------
// Tablica list sąsiedztwa grafu
SLel ** graf;
// Tablica list sąsiedztwa
// drzewa rozpinającego
SLel ** T;
// Tablica odwiedzin
bool * vs;
// Rekurencyjna funkcja tworzenia
// drzewa rozpinającego w głąb
// v-numer wierzchołka startowego
// reszta zmiennych globalna
//-------------------------------
void DFSTree(int v)
{
SLel *p, *r;
int u;
// Oznaczamy wierzchołek
// jako odwiedzony
vs[v] = true;
// Przeglądamy sąsiadów
for(p = graf[v]; p; p = p->next)
{
// u-numer sąsiada
u = p->v;
// Interesują nas tylko
// nieodwiedzeni sąsiedzi
if(!vs[u])
{
// Dodajemy u do listy T[v]
r = new SLel;
r->v = u;
r->next = T[v];
T[v] = r;
// Rekurencyjnie tworzymy
// drzewo
DFSTree(u);
}
}
}
// **********************
// *** PROGRAM GŁÓWNY ***
// **********************
int main()
{
int n, m, i, v1, v2;
SLel *p, *r;
// Czytamy liczbę
// wierzchołków i krawędzi
cin >> n >> m;
// Tworzymy tablicę
// list sąsiedztwa grafu
graf = new SLel * [n];
// Tworzymy tablicę list
// sąsiedztwa drzewa
// rozpinającego
T = new SLel * [n];
// Tworzymy tablicę odwiedzin
vs = new bool [n];
// Tablice wypełniamy
// pustymi listami
for(i = 0; i < n; i++)
{
graf[i] = T[i] = nullptr;
vs[i] = false;
}
// Odczytujemy kolejne
// definicje krawędzi
for(i = 0; i < m; i++)
{
// Wierzchołek startowy
// i końcowy krawędzi
cin >> v1 >> v2;
// Tworzymy nowy element
p = new SLel;
// Numerujemy go jako v2
p->v = v2;
// Dodajemy go na początek
// listy graf[v1]
p->next = graf[v1];
graf[v1] = p;
// Teraz krawędź
// w odwrotną stronę
p = new SLel;
p->v = v1;
p->next = graf[v2];
graf[v2] = p;
}
// Tworzymy drzewo
// rozpinające w głąb
//-------------------
// Czytamy wierzchołek startowy
cin >> v1;
DFSTree(v1);
// Wyświetlamy tablicę list
// sąsiedztwa drzewa
// rozpinającego
cout << endl;
for(i = 0; i < n; i++)
{
cout << setw(2) << i << ":";
for(p = T[i]; p; p = p->next)
cout << setw(3) << p->v;
cout << endl;
}
// Usuwamy dynamiczne
// struktury danych
for(i = 0; i < n; i++)
{
p = graf[i];
while(p)
{
r = p;
p = p->next;
delete r;
}
p = T[i];
while(p)
{
r = p;
p = p->next;
delete r;
}
}
delete [] graf;
delete [] T;
delete [] vs;
cout << endl;
return 0;
}
|
Basic' Drzewo rozpinające w głąb
' Data: 22.09.2013
' (C)2013 mgr Jerzy Wałaszek
'---------------------------
' Typ listy jednokierunkowej
Type SLel
next As SLel Ptr
v As Integer
End Type
' Zmienne globalne
'-----------------
' Tablice list sąsiedztwa
' grafu i drzewa
Dim Shared As SLel Ptr Ptr graf, T
' Tablica odwiedzin
Dim Shared As Byte Ptr vs
' Rekurencyjna procedura tworzenia
' drzewa rozpinającego w głąb
' v-numer wierzchołka startowego
' reszta zmiennych globalna
'---------------------------------
Sub DFSTree(ByVal v As Integer)
Dim As SLel Ptr p, r
Dim As Integer u
' Oznaczamy wierzchołek
' jako odwiedzony
vs[v] = 1
p = graf[v]
' Przeglądamy sąsiadów
while p
' u-numer sąsiada
u = p->v
' Interesują nas tylko
' nieodwiedzeni sąsiedzi
If vs[u] = 0 Then
' Dodajemy u do listy T[v]
r = new SLel
r->v = u
r->next = T[v]
T[v] = r
' Rekurencyjnie tworzymy
' drzewo
DFSTree(u)
End If
p = p->Next
Wend
End Sub
' **********************
' *** PROGRAM GŁÓWNY ***
' **********************
Dim As Integer i, n, m, v1, v2
Dim As SLel Ptr p, r
Open Cons For Input As #1
' Czytamy liczbę
' wierzchołków i krawędzi
Input #1, n, m
' Tworzymy tablicę
' list sąsiedztwa grafu
graf = New SLel Ptr [n]
' Tworzymy tablicę
' list sąsiedztwa
' drzewa rozpinającego
T = New SLel Ptr [n]
' Tworzymy tablicę odwiedzin
vs = New Byte [n]
' Tablice wypełniamy
' pustymi listami
For i = 0 To n-1
graf[i] = 0
T[i] = 0
vs[i] = 0
Next
' Odczytujemy kolejne
' definicje krawędzi
For i = 1 To m
' Wierzchołek startowy
' i końcowy krawędzi
Input #1, v1, v2
' Tworzymy nowy element
p = New SLel
' Numerujemy go jako v2
p->v = v2
' Dodajemy go na początek
' listy graf[v1]
p->next = graf[v1]
graf[v1] = p
' Teraz krawędź w odwrotną stronę
p = new SLel
p->v = v1
p->next = graf[v2]
graf[v2] = p
Next
' Tworzymy drzewo
' rozpinające w głąb
' Czytamy wierzchołek startowy
Input #1, v1
Close #1
DFSTree(v1)
' Wyświetlamy tablicę list
' sąsiedztwa drzewa rozpinającego
Print
For i = 0 To n-1
Print Using "## :";i;
p = T[i]
While p
Print Using "###";p->v;
p = p->Next
Wend
Print
Next
' Usuwamy dynamiczne
' struktury danych
For i = 0 To n-1
p = graf[i]
While p
r = p
p = p->Next
Delete r
Wend
p = T[i]
While p
r = p
p = p->Next
Delete r
Wend
Next
Delete [] graf
Delete [] T
Delete [] vs
Print
End
|
Python
(dodatek)# Drzewo rozpinające w głąb
# Data: 7.01.2025
# (C)2025 mgr Jerzy Wałaszek
#---------------------------
# Klasa listy jednokierunkowej
class SLel:
def __init__(self):
self.next = None
self.v = 0
# Rekurencyjna procedura
# tworzenia drzewa rozpinającego
# w głąb
# v - numer wierzchołka
# startowego
def dfs_tree(v):
global vs, graf, t
# Oznaczamy wierzchołek
# jako odwiedzony
vs[v] = 1
p = graf[v]
# Przeglądamy sąsiadów
while p:
# u - numer sąsiada
u = p.v
# Interesują nas tylko
# nieodwiedzeni sąsiedzi
if not vs[u]:
# Dodajemy u do
# listy t[v]
r = SLel()
r.v = u
r.next = t[v]
t[v] = r
# Rekurencyjnie
# tworzymy drzewo
dfs_tree(u)
p = p.next
# **********************
# *** PROGRAM GŁÓWNY ***
# **********************
# Czytamy liczbę
# wierzchołków i krawędzi
x = input().split()
n = int(x[0])
m = int(x[1])
# Tworzymy tablicę
# list sąsiedztwa grafu
graf = [None] * n
# Tworzymy tablicę
# list sąsiedztwa
# drzewa rozpinającego
t = [None] * n
# Tworzymy tablicę odwiedzin
vs = [False] * n
# Odczytujemy kolejne
# definicje krawędzi
for i in range(m):
# Wierzchołek startowy
# i końcowy krawędzi
x = input().split()
v1 = int(x[0])
v2 = int(x[1])
# Tworzymy nowy element
p = SLel()
# Numerujemy go jako v2
p.v = v2
# Dodajemy go na początek
# listy graf[v1]
p.next = graf[v1]
graf[v1] = p
# Teraz krawędź
# w odwrotną stronę
p = SLel()
p.v = v1
p.next = graf[v2]
graf[v2] = p
# Tworzymy drzewo
# rozpinające w głąb
# Czytamy wierzchołek startowy
v1 = int(input())
dfs_tree(v1)
# Wyświetlamy tablicę list
# sąsiedztwa drzewa
# rozpinającego
print()
for i in range(n):
print("%2d :" % i, end="")
p = t[i]
while p:
print("%3d" % p.v,
end="")
p = p.next
print()
# Usuwamy dynamiczne
# struktury danych
for i in range(n):
while graf[i]:
graf[i] = graf[i].next
while t[i]:
t[i] = t[i].next
del graf,t,vs
print()
|
| Wynik: | |
17 24
0 1
0 2
0 3
1 2
1 9
1 14
2 6
3 4
3 6
4 12
4 13
5 6
5 9
6 7
6 8
6 12
7 13
10 11
10 14
10 15
11 16
12 16
13 16
14 15
6
0 : 2
1 : 9 14
2 : 1
3 : 0
4 : 3
5 :
6 : 8 12
7 :
8 :
9 : 5
10 : 11
11 :
12 : 16
13 : 4 7
14 : 15
15 : 10
16 : 13
|
![]() |
Algorytm tworzenia drzewa rozpinającego wszerz (ang. Breadth First Spanning Tree) jest w zasadzie identyczny jak dla drzewa rozpinającego w głąb – jedyną różnicą jest zastąpienie stosu kolejką (musimy przy tym pamiętać, iż kolejka nie odwraca kolejności zapisanych danych, jak robi to stos).
K01: Utwórz pustą kolejkę Q ; inicjujemy dane K02: Q.push(-1); Q.push(v) ; w kolejce umieszczamy krawędź -1-v K03: vs[v] ← true ; oznaczamy wierzchołek v jako odwiedzony K04: Dopóki Q.empty() = false: ; uruchamiamy BFS wykonuj kroki K05…K10 K05: v ← Q.front(); Q.pop() ; pobieramy z kolejki krawędź v–w w ← Q.front(); Q.pop() K06: Jeśli v > -1, ; krawędź v – w dodajemy do drzewa T to dodaj w do listy T[v] K07: Dla każdego sąsiada z wierzchołka w: wykonuj kroki K18…K10 K08: Jeśli vs[z] = true, ; szukamy nieodwiedzonego sąsiada to następny obieg pętli K07 K09: vs[z] ← true ; sąsiada oznaczamy jako odwiedzonego K10: Q.push(w) ; i krawędź w-z umieszczamy w kolejce Q.push(z) K11: Zakończ
Uwaga: jeśli drzewo rozpinające ma być grafem nieskierowanym, to po
kroku K06 należy również dodać
|
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 wczytuje definicję grafu nieskierowanego oraz numer wierzchołka startowego. Następnie tworzy jedno z drzew rozpinających wszerz i wyświetla wyniki w oknie konsoli. |
|
Przykładowe dane (ostatnia
czerwona liczba określa wierzchołek startowy, który będzie
korzeniem drzewa rozpinającego):
|
Pascal// Drzewo rozpinające wszerz
// Data: 22.09.2013
// (C)2013 mgr Jerzy Wałaszek
//---------------------------
program BFS_tree;
// Typ listy jednokierunkowej
type
PSLel = ^SLel;
SLel = record
next : PSLel;
v : integer;
end;
TList = array of PSLel;
// Zmienne globalne
var
// Liczba wierzchołków n
// i krawędzi m
n, m : integer;
// Tablica list sąsiedztwa grafu
A : TList;
// Tablica list sąsiedztwa
// drzewa rozpinającego
T : TList;
vs : array of Boolean;
// Zapisuje na początek listy
procedure push(var L : PSLel;
x : integer);
var
p : PSLel;
begin
new(p);
p^.v := x;
p^.next := L;
L := p;
end;
// Odczytuje z listy,
// usuwając odczytany element
function pop(var L : PSLel)
: integer;
var
p : PSLel;
begin
pop := L^.v;
p := L;
L := L^.next;
dispose(p);
end;
// Zapisuje do kolejki
procedure Q_push(var head,
tail : PSLel;
x : integer);
var
p : PSLel;
begin
new(p);
p^.next := nil;
p^.v := x;
if tail = nil then head := p
else tail^.next := p;
tail := p;
end;
// Odczytuje z kolejki,
// usuwając element
function Q_pop (var head,
tail : PSLel)
: integer;
var
p : PSLel;
begin
if head <> nil then
begin
Q_pop := head^.v;
p := head;
head := head^.next;
if head = nil then tail := nil;
dispose(p)
end
else Q_pop := -2
end;
// Tworzy drzewo rozpinające
procedure BFSTree(v : integer);
var
// Kolejka
head, tail : PSLel;
// Wskaźnik węzłów na liście
p : PSLel;
w, z : integer;
begin
// Tworzymy pustą kolejkę
head := nil;
tail := nil;
// W kolejce umieszczamy
// krawędź -1-v
Q_push(head, tail, -1);
Q_push(head, tail, v);
// Oznaczamy v jako odwiedzony
vs[v] := true;
// Uruchamiamy BFS
while head <> nil do
begin
// Pobieramy parę v-w z kolejki
v := Q_pop(head, tail);
w := Q_pop(head, tail);
// w dodajemy do listy T[v]
if v > -1 then push(T[v], w);
// Sąsiadów w umieszczamy
// w kolejce
p := A[w];
while p <> nil do
begin
z := p^.v;
if not vs[z] then
begin
vs[z] := true;
// Do kolejki para w-sąsiad
Q_push(head, tail, w);
Q_push(head, tail, z);
end;
p := p^.next;
end;
end;
end;
var
i, v1, v2 : integer;
p : PSLel;
begin
// Czytamy liczbę
// wierzchołków i krawędzi
read(n, m);
// Tworzymy tablicę list
// sąsiedztwa grafu
SetLength(A, n);
// Tworzymy tablicę list
// sąsiedztwa drzewa
SetLength(T, n);
// Tworzymy tablicę odwiedzin
SetLength(vs, n);
// Tablice inicjujemy
for i := 0 to n-1 do
begin
A[i] := nil;
T[i] := nil;
vs[i] := false;
end;
// Odczytujemy kolejne
// definicje krawędzi
for i := 1 to m do
begin
// Wierzchołek startowy
// i końcowy krawędzi
read(v1, v2);
// Krawędź v1-v2
push(A[v1], v2);
// Krawędź v2-v1
push(A[v2], v1);
end;
// Tworzymy drzewo
// rozpinające wszerz
//-------------------
// Czytamy wierzchołek startowy
read(v1);
BFSTree (v1);
// Wyświetlamy tablicę list
// sąsiedztwa drzewa rozpinającego
writeln;
for i := 0 to n-1 do
begin
write(i:2, ' :');
p := T[i];
while p <> nil do
begin
write(p^.v:3);
p := p^.next;
end;
writeln;
end;
// Usuwamy tablice dynamiczne
for i := 0 to n-1 do
begin
while A[i] <> nil do
v1 := pop(A[i]);
while T[i] <> nil do
v1 := pop(T[i]);
end;
SetLength(A, 0);
SetLength(T, 0);
SetLength(vs, 0);
writeln;
end.
|
C++// Drzewo rozpinające wszerz
// Data: 22.09.2013
// (C)2013 mgr Jerzy Wałaszek
//---------------------------
#include <iostream>
#include <iomanip>
using namespace std;
// Typ listy jednokierunkowej
struct SLel
{
SLel * next;
int v;
};
// Zmienne globalne
//-----------------
// Liczba wierzchołków n
// i krawędzi m
int n, m;
// Tablica list
// sąsiedztwa grafu
SLel ** A;
// Tablica list sąsiedztwa
// drzewa rozpinającego
SLel ** T;
// Tablica odwiedzin
bool * vs;
// Zapisuje na początek listy
void push(SLel * & L, int x)
{
SLel * p = new SLel;
p->v = x;
p->next = L;
L = p;
}
// Odczytuje z listy,
// usuwając odczytany element
int pop(SLel * & L)
{
int x;
if(L)
{
x = L->v;
SLel * p = L;
L = L->next;
delete p;
}
else x = -2;
return x;
}
// Zapisuje do kolejki
void Q_push(SLel * & head,
SLel * & tail,
int x)
{
SLel * p = new SLel;
p->next = nullptr;
p->v = x;
if(!tail)
head = p;
else
tail->next = p;
tail = p;
}
// Odczytuje z kolejki,
// usuwając element
int Q_pop(SLel * & head,
SLel * & tail)
{
int x;
SLel * p = head;
if(p)
{
x = head->v;
head = head->next;
if(!head) tail = NULL;
delete p;
}
else x = -2;
return x;
}
// Tworzy drzewo rozpinające
void BFSTree(int v)
{
// Kolejka
SLel * head, * tail;
// Wskaźnik węzłów na liscie
SLel * p;
int w, z;
// Tworzymy pustą kolejkę
head = tail = nullptr;
// W kolejce umieszczamy
// krawędź -1-v
Q_push(head, tail, -1);
Q_push(head, tail, v);
// Oznaczamy v jako odwiedzony
vs[v] = true;
// Uruchamiamy BFS
while(head)
{
// Pobieramy parę v-w z kolejki
v = Q_pop(head, tail);
w = Q_pop(head, tail);
if(v > -1)
// w dodajemy do listy T[v]
push(T[v], w);
// Sąsiadów wierzchołka w
// umieszczamy w kolejce
for(p = A[w]; p; p = p->next)
{
z = p->v;
if(!vs[z])
{
vs[z] = true;
// Do kolejki para w-sąsiad
Q_push(head, tail, w);
Q_push(head, tail, z);
}
}
}
}
int main()
{
int i, v1, v2;
SLel * p;
// Czytamy liczbę
// wierzchołków i krawędzi
cin >> n >> m;
// Tworzymy tablicę list
// sąsiedztwa grafu
A = new SLel * [n];
// Tworzymy tablicę list
// sąsiedztwa drzewa
// rozpinającego
T = new SLel * [n];
// Tworzymy tablicę odwiedzin
vs = new bool [n];
// Tablice inicjujemy
for(i = 0; i < n; i++)
{
A[i] = T[i] = nullptr;
vs[i] = false;
}
// Odczytujemy kolejne
// definicje krawędzi
for(i = 0; i < m; i++)
{
// Wierzchołek startowy
// i końcowy krawędzi
cin >> v1 >> v2;
// Krawędź v1-v2
push(A[v1], v2);
// Krawędź v2-v1
push(A[v2], v1);
}
// Tworzymy drzewo
// rozpinające wszerz
//-------------------
// Czytamy wierzchołek startowy
cin >> v1;
BFSTree(v1);
// Wyświetlamy tablicę list
// sąsiedztwa drzewa
// rozpinającego
cout << endl;
for(i = 0; i < n; i++)
{
cout << setw(2) << i << ":";
for(p = T[i]; p; p = p->next)
cout << setw(3) << p->v;
cout << endl;
}
// Usuwamy tablice dynamiczne
for(i = 0; i < n; i++)
{
while(A[i]) pop(A[i]);
while(T[i]) pop(T[i]);
}
delete [] A;
delete [] T;
delete [] vs;
cout << endl;
return 0;}
|
Basic' Drzewo rozpinające wszerz
' Data: 22.09.2013
' (C)2013 mgr Jerzy Wałaszek
'---------------------------
' Typ listy jednokierunkowej
Type SLel
next As SLel Ptr
v As Integer
End Type
' Zmienne globalne
'-----------------
' Liczba wierzchołków n i krawędzi m
Dim Shared As Integer n, m
' Tablica list sąsiedztwa grafu
Dim Shared As SLel Ptr Ptr A
' Tablica list sąsiedztwa drzewa
' rozpinającego
Dim Shared As SLel Ptr Ptr T
' Tablica odwiedzin
Dim Shared As Byte Ptr vs
' Zapisuje na początek listy
Sub push(ByRef L As SLel Ptr, _
ByVal x As Integer)
Dim As SLel Ptr p = New SLel
p->v = x
p->next = L
L = p
End Sub
' Odczytuje z listy,
' usuwając odczytany element
Function pop(ByRef L As SLel Ptr) _
As Integer
Dim As Integer x
Dim As SLel Ptr p = L
If L <> 0 Then
x = L->v
L = L->Next
Delete p
Else
x = -2
End If
Return x
End Function
' Zapisuje do kolejki
Sub Q_push(ByRef head As SLel Ptr, _
ByRef tail As SLel Ptr, _
ByVal x As Integer)
Dim As SLel Ptr p = new SLel
p->next = 0
p->v = x
If tail = 0 Then
head = p
Else
tail->next = p
EndIf
tail = p
End Sub
' Odczytuje z kolejki, usuwając element
Function Q_pop(ByRef head As SLel Ptr, _
ByRef tail As SLel Ptr) _
As Integer
Dim As SLel Ptr p = head
Dim As Integer x
If head <> 0 Then
x = head->v
head = head->Next
If head = 0 Then tail = 0
delete p
Else
x = -2
End If
Return x
End Function
' Tworzy drzewo rozpinające
Sub BFSTree(ByVal v As Integer)
' Kolejka
Dim As SLel Ptr head, tail
' Wskaźnik węzłów na liscie
Dim As SLel Ptr p
Dim As Integer w, z
' Tworzymy pustą kolejkę
head = 0
tail = 0
' W kolejce umieszczamy krawędź -1-v
Q_push(head, tail, -1)
Q_push(head, tail, v)
' Oznaczamy v jako odwiedzony
vs[v] = 1
' Uruchamiamy BFS
While head <> 0
' Pobieramy parę v-w z kolejki
v = Q_pop(head, tail)
w = Q_pop(head, tail)
' w dodajemy do listy T[v]
If v > -1 Then push(T[v], w)
p = A[w]
' Sąsiadów wierzchołka w
' umieszczamy w kolejce
While p <> 0
z = p->v
if vs[z] = 0 Then
vs[z] = 1
' Do kolejki para w-sąsiad
Q_push(head, tail, w)
Q_push(head, tail, z)
End If
p = p->Next
Wend
Wend
End Sub
' **********************
' *** PROGRAM GŁÓWNY ***
' **********************
Dim As Integer i, v1, v2
Dim as SLel Ptr p
Open Cons For Input As #1
' Czytamy liczbę wierzchołków i krawędzi
Input #1, n, m
' Tworzymy tablicę list sąsiedztwa grafu
A = new SLel Ptr [n]
' Tworzymy tablicę list sąsiedztwa
' drzewa rozpinającego
T = new SLel Ptr [n]
' Tworzymy tablicę odwiedzin
vs = New Byte [n]
' Tablice inicjujemy
For i = 0 To n-1
A[i] = 0
T[i] = 0
vs[i] = 0
Next
' Odczytujemy kolejne definicje krawędzi
For i = 1 To m
' Wierzchołek startowy i końcowy krawędzi
Input #1, v1, v2
' Krawędź v1-v2
push(A[v1], v2)
' Krawędź v2-v1
push(A[v2], v1)
Next
' Tworzymy drzewo rozpinające wszerz
'-----------------------------------
' Czytamy wierzchołek startowy
Input #1, v1
BFSTree (v1)
Close #1
' Wyświetlamy tablicę list sąsiedztwa
' drzewa rozpinającego
Print
For i = 0 To n-1
Print Using "## :";i;
p = T[i]
while p <> 0
Print Using "###";p->v;
p = p->next
Wend
Print
Next
' Usuwamy tablice dynamiczne
For i = 0 To n-1
While A[i] <> 0
pop(A[i])
Wend
While T[i] <> 0
pop(T[i])
Wend
Next
Delete [] A
Delete [] T
Delete [] vs
Print
End
|
Python
(dodatek)# Drzewo rozpinające wszerz
# Data: 8.01.2025
# (C)2025 mgr Jerzy Wałaszek
#---------------------------
# Klasa listy jednokierunkowej
class SLel:
def __init__(self):
self.next = None
self.v = 0
# Klasa kolejki
class Queue:
def __init__(self):
self.head = None
self.tail = None
# Zapisuje do kolejki
def push(self, x):
p = SLel()
p.next = None
p.v = x
if not self.tail:
self.head = p
else:
self.tail.next = p
self.tail = p
# Odczytuje z kolejki,
# usuwając element
def pop(self):
if self.head:
x = self.head.v
self.head = self.head.next
if not self.head:
self.tail = None
else:
x = -2
return x
# Zapisuje na początek listy
def push(lst, x):
p = SLel()
p.v = x
p.next = lst
lst = p
return lst
# Odczytuje z listy,
def pop(lst):
if lst:
lst = lst.next
return lst
# Tworzy drzewo rozpinające
def bfs_tree(v):
global vs, t, a
# Tworzymy pustą kolejkę
q = Queue()
# W kolejce umieszczamy
# krawędź -1-v
q.push(-1)
q.push(v)
# Oznaczamy v jako odwiedzony
vs[v] = True
# Uruchamiamy BFS
while q.head:
# Pobieramy parę v-w
# z kolejki
v = q.pop()
w = q.pop()
# w dodajemy do listy T[v]
if v > -1:
t[v] = push(t[v], w)
p = a[w]
# Sąsiadów wierzchołka w
# umieszczamy w kolejce
while p:
z = p.v
if not vs[z]:
vs[z] = True
# Do kolejki
# para w-sąsiad
q.push(w)
q.push(z)
p = p.next
# **********************
# *** PROGRAM GŁÓWNY ***
# **********************
# Czytamy liczbę wierzchołków
# i krawędzi
x = input().split()
n = int(x[0])
m = int(x[1])
# Tworzymy tablicę list
# sąsiedztwa grafu
a = [None] * n
# Tworzymy tablicę list sąsiedztwa
# drzewa rozpinającego
t = [None] * n
# Tworzymy tablicę odwiedzin
vs = [False] * n
# Odczytujemy kolejne
# definicje krawędzi
for i in range(m):
# Wierzchołek startowy
# i końcowy krawędzi
x = input().split()
v1 = int(x[0])
v2 = int(x[1])
# Krawędź v1-v2
a[v1] = push(a[v1], v2)
# Krawędź v2-v1
a[v2] = push(a[v2], v1)
# Tworzymy drzewo rozpinające wszerz
#-----------------------------------
# Czytamy wierzchołek startowy
v1 = int(input())
bfs_tree(v1)
# Wyświetlamy tablicę list sąsiedztwa
# drzewa rozpinającego
print()
for i in range(n):
print("%2d :" % i, end="")
p = t[i]
while p:
print("%3d" % p.v, end="")
p = p.next
print()
# Usuwamy tablice dynamiczne
for i in range(n):
while a[i]: a[i] = pop(a[i])
while t[i]: t[i] = pop(t[i])
del a, t, vs
print()
|
| Wynik: | |
17 24 0 1 0 2 0 3 1 2 1 9 1 14 2 6 3 4 3 6 4 12 4 13 5 6 5 9 6 7 6 8 6 12 7 13 10 11 10 14 10 15 11 16 12 16 13 16 14 15 6 0 : 1 : 14 2 : 1 3 : 0 4 : 5 : 9 6 : 2 3 5 7 8 12 7 : 13 8 : 9 : 10 : 11 : 10 12 : 4 16 13 : 14 : 15 15 : 16 : 11 |
![]() |
Na koniec dla porównania przedstawiamy oba drzewa rozpinające:
Drzewo rozpinające w
głąb![]() |
Drzewo rozpinające
wszerz![]() |
![]() |
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.