Documentos de Académico
Documentos de Profesional
Documentos de Cultura
Rosa Ma Jimnez
Conrado Martnez
U. Politcnica Catalunya
1 de octubre de 2013
Anlisis de Algoritmos
Divide y vencers
Tablas de Hash
Colas de prioridad
Grafos y Recorridos
Pr() Tn ()
An
X
k0
k Pr(Tn = k).
Para todo n 0
Tmejor (n) Tavg (n) Tpeor (n).
Ejemplo
1
Funciones cuadrticas:
q(n) = a n2 + b n + c q(2n) 4 q(n)
n log2 n
n2
n3
2n
2
4
8
4
8
16
64
16
24
64
512
256
64 256
4096
262144
160 1024 32768 6,87 1010
384 4096 262144 4,72 1021
` N
L
C
Q
E
` + 1 2N 2(L + N )
4C
8Q
E2
log2 n
1
2
3
4
5
6
n
2
4
8
16
32
64
Definicin
Dada una funcin f : R+ R+ la clase O(f ) (O-grande de f )
es
O(f )={g:R+ R+ | n0 c nn0 :g(n)cf (n)}
logb x
logb c
Si el coste de un fragmento S1 es f y el de S2 es g
entonces el coste de S1 ; S2 es f + g.
Teorema
Sea T (n) el coste (en caso peor, en caso medio, ...) de un
algoritmo recursivo que satisface la recurrencia
(
f (n)
si 0 n < n0
T (n) =
a T (n c) + g(n) si n n0 ,
donde n0 es una constante, c 1, f (n) es una funcin
arbitraria y g(n) = (nk ) para una cierta constante k 0.
Entonces
si a < 1
(n )
k+1
T (n) = (n ) si a = 1
(an/c ) si a > 1.
Teorema
Sea T (n) el coste (en caso peor, en caso medio, . . . ) de un
algoritmo recursivo que satisface la recurrencia
(
f (n)
si 0 n < n0
T (n) =
a T (n/b) + g(n) si n n0 ,
donde n0 es una constante, b > 1, f (n) es una funcin
arbitraria y g(n) = (nk ) para una cierta constante k 0.
Sea = logb a. Entonces
si < k
(n )
k
T (n) = (n log n) si = k
(n )
si > k.
Anlisis de Algoritmos
Divide y vencers
Tablas de Hash
Colas de prioridad
Grafos y Recorridos
Introduccin
Teorema
Si g(n) = (nk ) entonces la solucin de la recurrencia
(
g(n) + a T (n/b) si n > n0 ,
T (n) =
f (n)
si n n0 ,
donde a 1 y b > 1 son constantes, satisface
si < k,
(g(n))
T (n) = (g(n) log n) si = k
(n )
si > k,
siendo = logb a.
ai
n k
0i<j
bi
+ aj f (n0 )
X a i
+ aj f (n0 ).
= nk
bk
0i<j
k
k
b
a/b 1
bk
0i<j
= (
n
) = (nk ).
nk
Bsqueda dicotmica
Problema: Dado un vector A[1..n] de n elementos, en orden
creciente, y un elemento x, determinar el valor i, 0 i n, tal
que A[i] x < A[i + 1] (convendremos que A[0] = y
A[n + 1] = +).
Si el vector A fuese vaco la respuesta es sencilla, pues x no
est en el vector. Pero para poder obtener una solucin
recursiva efectiva, debemos realizar la siguiente
generalizacin: dado un segmento o subvector A[` + 1..u 1],
0 ` u n + 1, ordenado crecientemente, y tal que
A[`] x < A[u], determinar el valor i, ` i u 1, tal que
A[i] x < A[i + 1]. Este es un ejemplo clsico de inmersin de
parmetros.
Ahora s, si ` + 1 = u, el segmento en cuestin no contiene
elementos y i = u 1 = `.
n > 0,
9 x 231 + 5 x 231 x 10
6 x 231 x 100
2079 + 11550 + 138600
152229
x y = (A 2n/2 + B) (C 2n/2 + D)
= A C 2n + (A D + B C) 2n/2 + B D.
n>1
procedure M ULT(x,y, i, j, i0 , j 0 )
Require: 1 i j n, 1 i0 j 0 n, j 0 i0 = j i
Ensure: Devuelve el producto de x[i..j] por y[i0 ..j 0 ]
n := j i + 1
if n < M then
Usar un mtodo simple para calcular el resultado
else
m := (i + j) div 2; m0 := (i0 + j 0 ) div 2
U := MULT(x, y, m + 1, j, m0 + 1, j 0 )
V := MULT(x, y, i, m, i0 , m0 )
U.DECALA _ IZQUIERDA(n)
W1 := x[i..m] + y[i0 ..m0 ]
W2 := x[m + 1..j] + y[m0 + 1..j 0 ]
Aadir un bit a W1 W2 si es necesario
W := M ULT(W1 , W2 , . . .)
W := W (U + V )
W.DECALA _ IZQUIERDA(n div 2)
return U + W + V
end if
end procedure
procedure S PLIT(L, L0 , n)
Require: L = [`1 , . . . , `m ], m n
Ensure: L = [`1 , . . . , `n ], L0 = [`n+1 , . . . , `m ]
p := L
while n > 1 do
p := p next
n := n 1
end while
L0 := p next; p next := null
end procedure
procedure M ERGE S ORT(L, n)
if n > 1 then
m := n div 2
S PLIT(L, L0 , m)
M ERGE S ORT(L, m)
M ERGE S ORT(L0 , n m)
. fusiona las listas L y L0
L := M ERGE(L, L0 )
end if
end procedure
Algoritmo de Strassen
=
A21 A22
B21 B22
C21 C22
donde C11 = A11 B11 + A12 B21 , etc.
C11 = M2 + M3
C12 = M1 + M2 + M5 + M6
C21 = M1 + M2 + M4 M7
C22 = M1 + M2 + M4 + M5
Puesto que las operaciones aditivas tienen coste (n2 ), el
coste del algoritmo de Strassen viene dado por la recurrencia
M (n) = (n2 ) + 7 M (n/2),
cuya solucin es (nlog2 7 ) = (n2,807... ).
QuickSort
Q UICK S ORT (Hoare, 1962) es un algoritmo de ordenacin que
usa el principio de divide y vencers, pero a diferencia de los
ejemplos anteriores, no garantiza que cada subejemplar tendr
un tamao que es fraccin del tamao original.
La base de quicksort es el procedimiento de PARTICIN: dado
un elemento p denominado pivote, debe reorganizarse el
segmento como ilustra la figura.
procedure PARTICIN(A, `, u, k)
Require: ` u
Ensure: A[`..k 1] A[k] A[k + 1..u]
i := ` + 1; j := u; p := A[`]
while i < j + 1 do
while i < j + 1 A[i] p do
i := i + 1
end while
while i < j + 1 A[j] p do
j := j 1
end while
if i < j + 1 then
A[i] :=: A[j]
end if
end while
A[`] :=: A[j]; k := j
end procedure
n
X
X
= =
(i) =
i
i=0
0in
= (n ).
Sin embargo, en promedio, el pivote quedar ms o menos
centrado hacia la mitad del segmento como sera deseable
justificando que quicksort sea considerado un algoritmo de
divide y vencers.
(n 1 + qj1 + qnj )
1jn
1
n
1 X
(qj1 + qnj )
n
1jn
2 X
= n + O(1) +
qj
n
= n + O(1) +
0j<n
2
Zn = 0j<n nj Wn,j
< 1.
n
El paso fundamental es hallar una funcin de forma (z) que
aproxima los pesos n,j .
Definicin
Dado un conjunto de pesos n,j , (z) es una funcin de forma
para el conjunto de pesos si
R1
1
0 (z) dz 1
2
k!
k
La extensin de los factoriales a los reales viene dada por la
funcin gamma de Euler (z) y la de los nmeros armnicos
es la funcin (z) = d lndz(z) .
Por ejemplo, en quicksort los pesos son todos iguales:
n,j = n2 . La funcin de forma correspondiente es
(z) = lmn n n,zn = 2.
tn
si H > 0,
H + o(tn )
t
n
Fn = H0 ln n + o(tn log n) si H = 0 y H0 6= 0,
(n )
si H < 0,
donde x = es la nica solucin real no negativa de la
ecuacin
Z
1
(z)z x dz = 0.
1
0
qn =
QuickSelect
El problema de la seleccin consiste en hallar el j-simo de
entre n elementos dados. En concreto, dado un vector A con n
elementos y un rango j, 1 j n, un algoritmo de seleccin
debe hallar el j-simo elemento en orden ascendente. Si j = 1
entonces hay que encontrar el mnimo, si j = n entonces hay
que hallar el mximo, si j = bn/2c entonces debemos hallar la
mediana, etc.
Es fcil resolver el problema con coste (n log n) ordenando
previamente el vector y con coste (j n), recorriendo el vector
y manteniendo los j elementos menores de entre los ya
examinados. Con las estructuras de datos apropiadas puede
rebajarse el coste a (n log j), lo cual no supone una mejora
sobre la primera alternativa si j = (n).
Q UICK S ELECT (Hoare, 1962), tambin llamado F IND y
one-sided Q UICK S ORT, es una variante del algoritmo
Q UICK S ORT para la seleccin del j-simo de entre n
elementos.
nk
1 X k1
Ck1 +
Cnk
n
n
n
1kn
2 X k
= n + O(1) +
Ck .
n
n
0k<n
obtenemos H = 1
R1
0
2zn
= 2z
n n
2z 2 dz = 1/3 y Cn = 3n + o(n).
Anlisis de Algoritmos
Divide y vencers
Tablas de Hash
Colas de prioridad
Grafos y Recorridos
Definicin
Un rbol binario de bsqueda T es un rbol binario tal que o es
vaco o bien contiene un elemento x y satisface
1
Lema
Un recorrido en inorden de un rbol binario de bsqueda T
visita los elementos de T por orden creciente de clave.
Vamos a considerar ahora el diseo del algoritmo de bsqueda
en rboles binarios de bsqueda (BSTs), en lo sucesivo). Dada
la naturaleza recursiva de la definicin de BST es razonable
abordar el diseo de este algoritmo de manera recursiva.
Sea T el BST que representa al diccionario y k la clave
buscada. Si T = entonces k no se encuentra el diccionario y
ello se habr de indicar de algn modo conveniente. Si T no es
vaco entonces tendremos que considerar la relacin que
existe entre la clave del elemento x que ocupa la raz de T y la
clave dada k.
// implementacin iterativa
template <typename Clave, typename Valor>
Diccionario<Clave,Valor>::nodo_bst*
Diccionario<Clave,Valor>::inserta_en_bst(nodo_bst* p,
const Clave& k, const Valor& v) throw(error) {
// el BST est vaco
if (p == NULL)
return new nodo_bst(k, v);
// el BST no est vaco
nodo_bst* padre = NULL;
nodo_bst* p_orig = p;
// buscamos el punto de insercin
while (p != NULL and k != p -> _k) {
padre = p;
if (k < p -> _k)
p = p -> _izq;
else // p -> _k < k
p = p -> _der;
}
//
//
//
if
}
else // k == p -> _k
p -> _v = v;
return p_orig;
}
=T
JUNTAR (, T )
=T
En particular, JUNTAR(, ) = .
T1
z+
T2
z
si uno
vaco,
(t1 ==
(t2 ==
1 X
C(n; k)
n
1kn
k1
nk
1 X
1
0+
C(k 1) +
C(n k)
=1+
n
n
n
n
1kn
1 X
=1+ 2
(k C(k) + (n 1 k) C(n 1 k))
n
0k<n
2 X
k C(k).
=1+ 2
n
C(n) =
0k<n
I(n)
n
2 X
I(k),
n
I(0) = 0.
(1)
0k<n
2(n 1)(n + 2)
n+2
2n
n+2
2n
+
I(n) =
+
+
I(n 1)
n+1
n+1
n+1
n(n + 1)
n
2(n 1)(n + 2)
2(n 2)(n + 2)
2n
n+2
=
+
+
+
I(n 2)
n+1
n(n + 1)
n(n 1)
n1
I(n + 1) =
i=k
X
ni
n+2
2n
+ 2(n + 2)
+
I(n k)
n+1
(n
i
+
1)(n
i
+
2)
n
k+1
i=1
i=n
X
2n
i
+ 2(n + 2)
n+1
(i
+
1)(i
+ 2)
i=1
X 2
1
= O(1) + 2(n + 2)
i+2
i+1
1in
1
2
+
+ Hn 2)
n+2
n+1
= 2nHn 4n + 4Hn + O(1),
P
donde Hn = 1in 1/i.
Puesto que Hn = ln n + O(1) se sigue que
I(n) = Q(n) = 2n ln n + O(n)
= 1,386 . . . n log2 n + O(n)
y que C(n) = 2 ln n + O(1).
Anlisis de Algoritmos
Divide y vencers
Tablas de Hash
Colas de prioridad
Grafos y Recorridos
rboles equilibrados
Definicin
Un AVL T es un rbol binario de bsqueda tal que o es vaco o
bien cumple que
1
{enero, febrero, marzo, abril, mayo, junio, julio, agosto, septiembre, octubre
noviembre, diciembre}
marzo
febrero
octurbre
agosto
abril
junio
enero
diciembre
julio
mayo
septiembre
noviembre
Lema
La altura h(T ) de un AVL de tamao n es (log n).
Demostracin. Puesto que el AVL es un rbol binario se
cumple que h(T ) dlog2 (n + 1)e, es decir, h(T ) (log n).
Ahora vamos a demostrar que h(T ) O(log n).
Sea Nh el mnimo nmero de nodos necesario para construir
un AVL de altura h. Claramente N0 = 0 y N1 = 1. El AVL ms
desequilibrado posible de altura h > 1 se consigue poniendo
un subrbol, digamos el izquierdo, de altura h 1 empleando el
mnimo posible de nodos Nh1 y otro subrbol, el derecho, que
tendr altura h 2 (pero no puede tener menos!) en el que
pondremos tambin el mnimo posible de nodos, Nh2 . Por
tanto,
Nh = 1 + Nh1 + Nh2
,
Fn = +
5 2
3 5
(n + )
h
2
x : y;
}
template <typename Clave, typename Valor>
static int Diccionario<Clave,Valor>::altura(
nodo_avl* p) throw() {
if (p == NULL)
return 0;
else
return p -> _alt;
}
template <typename Clave, typename Valor>
static void Diccionario<Clave,Valor>::actualizar_altura(
nodo_avl* p) throw() {
p -> _alt = 1 + max(altura(p -> _izq), altura(p -> _der));
}
y
C
A
B
Antes:
y
x
C
h+1
A
Despues:
y
h+2
A
h+1
LL
x
y
h+1
h+1
A
B
x
y
A
h
h+2
h
B
h+1
h+1
C
A
h+1
x
C
y
A
h+1
A
h+1
h
h+1
h+2
x
C
h+2
y
h+1
<
_ h+1
z
h
B1
B2
h+2
h+1
B1
B2
<
_h
z
y
h+2
h
C
h+1
B1
h+1
<
_ h+1
B2
<
_h
A
h+2
B1
B2
z
A
h+2
B1
h+2
B2
<
_ h1
B2
B1
LL(y)
h+2
y
h+1
B1
B2
<
_ h1
x
y
y
C
B1
B2
h+2
<
_h
B1
h+2
B2
RR(x)
h+2
<
_h
A
<
_h
B1
h+1
B2
RR
febrero
marzo
enero
marzo
abril
enero
marzo
junio +1
0 agosto
+1
mayo
julio
LR
1
febrero
0
abril
marzo +1
agosto
0
junio +1
enero
julio
mayo
febrero
0
abril
agosto
marzo
0
junio +1
enero
julio
mayo
septiembre
0
+1
octubre
+ {septiembre, octubre}
RL
febrero
0
abril
marzo 0
agosto
0
junio +1
enero
julio
0 mayo
octubre
septiembre
abril
marzo 1
agosto
junio
enero
julio
+1
octubre
+1
mayo
septiembre
0
noviembre
+ {noviembre}
RR
marzo 0
octubre
febrero
0 agosto
abril
junio +1
enero
julio
octubre
abril
diciembre
junio +1
+1
enero
julio
+ {diciembre}
septiembre
+1
febrero
1 agosto
noviembre
marzo
+1
mayo
+1
mayo
+1
noviembre
septiembre
si uno
vaco,
(t1 ==
(t2 ==
Anlisis de Algoritmos
Divide y vencers
Tablas de Hash
Colas de prioridad
Grafos y Recorridos
Funciones de hash
Resolucin de colisiones
Sinnimos encadenados
En las tablas con sinnimos encadenados cada entrada de la
tabla da acceso a una lista enlazada de sinnimos.
template <typename Clave, typename Valor,
template <typename> class HashFunct = Hash>
class Diccionario {
...
private:
struct nodo {
Clave _k;
Valor _v;
nodo* _sig;
// constructora de la clase nodo
nodo(const Clave& k, const Valor& v,
nodo* sig = NULL);
};
nodo** _Thash; // tabla de punteros a nodo
int _M;
// tamao de la tabla
int _n;
// numero de elementos
double _alfa_max; // factor de carga
nodo* busca_sep_chain(const Clave& k) const throw();
void inserta_sep_chain(const Clave& k,
const Valor& v) throw(error);
void elimina_sep_chain(const Clave& k) throw();
};
M = 13
h (x) = x mod M
13
30
17
19
23
10
25
12
1
2
3
4
5
6
7
8
9
10
11
12
}
}
si p != NULL, lo quitamos de la
lista teniendo en cuenta que puede
ser el primero
(p != NULL) {
--_n;
if (ant != NULL)
ant -> _sig = p -> _sig;
else
_Thash[i] = p -> _sig;
delete p;
Direccionamiento abierto
Sondeo lineal
template <typename Clave, typename Valor,
template <typename> class HashFunct = Hash>
class Diccionario {
...
private:
struct nodo {
Clave _k;
Valor _v;
bool _libre;
// constructora de la clase nodo
nodo(const Clave& k, const Valor& v, bool libre = true);
};
nodo* _Thash; // tabla de nodos
int _M;
// tamao de la tabla
int _n;
// numero de elementos
double _alfa_max; // factor de carga
M = 13
h (x) = x mod M
(incremento 1)
ocupado
13
ocupado
13
ocupado
libre
25
ocupado
libre
libre
ocupado
ocupado
17
ocupado
17
ocupado
ocupado
ocupado
19
ocupado
19
ocupado
libre
30
ocupado
libre
5
6
10
10
11
12
12
ocupado
libre
10
10
ocupado
10
10
ocupado
11
23
ocupado
11
23
ocupado
12
ocupado
12
12
ocupado
12
+ {25, 30}
//
//
//
//
Redimensionamiento
Anlisis de Algoritmos
Divide y vencers
Tablas de Hash
Colas de prioridad
Grafos y Recorridos
Definicin
Un montculo (ing: heap) es un rbol binario tal que
1
Proposicin
1
//
//
//
//
Versin recursiva.
Hunde el elemento en la posicin j del heap
hasta reestablecer el orden del heap; por
hiptesis los subrboles del nodo j son heaps.
// Coste: O(log(n/j))
template <typename Elem, typename Prio>
void ColaPrioridad<Elem,Prio>::hundir(int j) throw() {
// si j no tiene hijo izquierdo, hemos terminado
if (2 * j > nelems) return;
int minhijo = 2 * j;
if (minhijo < nelems and
h[minhijo].second > h[minhijo + 1].second)
++minhijo;
//
//
//
if
}
}
//
//
//
//
Versin iterativa.
Hunde el elemento en la posicin j del heap
hasta reestablecer el orden del heap; por
hiptesis los subrboles del nodo j son heaps.
// Coste: O(log(n/j))
template <typename Elem, typename Prio>
void ColaPrioridad<Elem,Prio>::hundir(int j) throw() {
bool fin = false;
while (2 * j <= nelems and not fin) {
int minhijo = 2 * j;
if (minhijo < nelems and
h[minhijo].second > h[minhijo + 1].second)
++minhijo;
if (h[j].second > h[minhijo].second) {
swap(h[j], h[minhijo]);
j = minhijo;
} else {
fin = true;
}
}
}
Heapsort
// Da estructura de max-heap al
// vector v[1..n] de Elems; aqu
// cada elemento se identifica con su
// prioridad
template <typename Elem>
void crea_max_heap(Elem v[], int n) {
for (int i = n/2; i > 0; --i)
hundir(v, n, i);
}
i=n
X
O(log i)
i=1
= B(n) + O
log2 i
1in
!
nn/2
= O log
(n/2)!
= O log(2e)n/2 = O(n)
Puesto que B(n) = (n), podemos afirmar que B(n) = (n).
n+1
2k
Por lo tanto,
n+1
2k
0kh1
X k
= O n
2k
0kh1
X k
= O(n),
= O n
2k
B(n) =
O(k)
k0
ya que
X k
= 2.
2k
k0
k rk =
r
.
(1 r)2
Anlisis de Algoritmos
Divide y vencers
Tablas de Hash
Colas de prioridad
Grafos y Recorridos
Definicin
Un grafo (no dirigido) es un par G = hV, Ei donde V es un
conjunto finito de vrtices (tambin llamados nodos) y E es un
conjunto de aristas; cada arista e E es un par no ordenado
{u, v} donde u y v (u 6= v) son elementos de V .
Definicin
Un grafo dirigido o digrafo es un par G = hV, Ei donde V es un
conjunto finito de vrtices o nodos y E es un conjunto de arcos;
cada arco e E es un par (u, v) donde u y v (u 6= v) son
elementos de V .
Definicin
Un camino P = v0 , v1 , v2 , . . . , vn de longitud n en un grafo
G = hV, Ei es una secuencia de vrtices de G tal que para
toda i, 0 i < n
{vi , vi+1 } E
El vrtice v0 es el origen del camino P y vn es su destino.
Un camino en un digrafo se define de manera anloga: para
cada i, (vi , vi+1 ) es un arco del digrafo.
Se dice que un camino es simple si no se repite ningn vrtice.
Un camino en el que v0 = vn es un ciclo.
Definicin
Un grafo G = hV, Ei es conexo si y slo si, para todo par de
vrtices u y v, existe un camino que va de u a v en G.
Para digrafos la definicin es idntica, slo que entonces se
dice que el digrafo es fuertemente conexo.
Definicin
Dado un grafo G = hV, Ei, el grafo H = hV 0 , E 0 i se dice que es
un subgrafo de G si y slo si V 0 V , E 0 E, y para toda arista
e0 = (u0 , v 0 ) E 0 se cumple que u0 y v 0 pertenecen a V 0 .
Si E 0 contiene todas las aristas de E que son incidentes a dos
vrtices de V 0 , se dice que H es el subgrafo inducido por V 0 .
La definicin de subgrafo de un grafo dirigido es
completamente anloga.
Definicin
Una componente conexa C de un grafo G es un subgrafo
inducido maximal conexo de G. Maximal quiere decir que si se
aade cualquier vrtice v a V (C) entonces el subgrafo
inducido correspondiente no es conexoen particular, no
existe camino entre v y los restantes vrtices de C.
En el caso de digrafos, se habla de componentes fuertemente
conexas: una componente fuertemente conexa del digrafo G es
un subgrafo dirigido inducido maximal fuertemente conexo.
Definicin
Un grafo conexo y sin ciclos se denomina rbol (libre). Si G es
un grafo conexo, un subgrafo T = hV, E 0 i (es decir que
contiene los mismos vrtices que G) es un rbol de expansin
si T es un rbol.
Los rboles libres no tienen raz, y no existe orden entre los
vrtices adyacentes a un vrtice dado del rbol.
Lema
Si G = hV, Ei es un rbol entonces |E| = |V | 1.
Implementacin
Recorridos
Definicin
Dado un grafo conexo G = hV, Ei, un recorrido del grafo es una
secuencia que contiene todos y cada uno de los vrtices en
V (G) exactamente una vez y tal que para cualquier vrtice v
en la secuencia se cumple que, o bien v es el primer vrtice de
la secuencia, o bien existe una arista e E(G) que une al
vrtice v con otro vrtice que le precede en la secuencia.
El recorrido de un grafo es una secuencia de los recorridos de
las componentes conexas de G. No hay ningn vrtice que
aparezca en el recorrido sin que se haya completado el
recorrido de las componentes conexas correspondientes a los
vrtices que le preceden en el recorrido.
a
e
i
g
c
d
h
f
j
k
k
tree edge
backward edge
h
d
i
e
l
j
procedure E S B IPARTIDO(G)
for v V (G) do
color[v] := 1
end for
color := 0
es_bip := true
for v V (G) while es_bip do
if color[v] = 1 then
es_bip := E S B IPARTIDO -R EC(G, v, color)
end if
end for
return es_bip
end procedure
mas_alto[u] = nd[x]
procedure B ICONEXO(G)
Require: G es conexo
for v V (G) do
visitado[v] := false
ndf s[v] := 0
punto_art[v] := false
num_desc[v] := 0
end for
num_df s := 0
es_biconexo := true
. Basta lanzar un DFS porque G es conexo
v := un vrtice cualquiera de G
B ICONEXO -R EC(G, v, v, es_biconexo, ndf s, . . .)
return es_biconexo
end procedure
(1) + (grado(v)) =
vV
X
1 + grado(v)
!
=
vV
X
vV
1+
X
vV
grado(v)
= (n + m)
DFS en Digrafos
e
i
g
c
h
f
tree edge
m
j
k
k
backward edge
forward edge
cross edge