Professional Documents
Culture Documents
Lio n. 1
Algoritmos e Estruturas de Dados
Algoritmos e Estruturas de Dados
Logstica
Tecnologia
Aulas
Avaliao
Programa da cadeira
O ambiente de programao
http://www.amazon.co.uk/Algorithms-Robert-Sedgewick/dp/032157351X/
6/1/16 Algoritmos e Estruturas de Dados 5
Bibliografia de interesse
Introduction to Algorithms, 3.
edio, Thomas Cormen, Charles
Leiserson, Ronald Rivest, Clifford
Stein.
http://www.amazon.co.uk/Introduction-Algorithms-T-
Cormen/
https://www.coursera.org/course/algs4partI
https://www.coursera.org/course/algs4partII
6/1/16 Algoritmos e Estruturas de Dados 8
Programa de AED
Conceitos fundamentais Grafos
Modelo de programao Busca em profundidade
Sacos, pilhas e filas Busca em largura
Arrays rvores de cobertura
Union-Find Caminho mais curto
Anlise de algoritmos Problema do caixeiro
Ordenao viajante
Algoritmos elementares Cadeias de carateres
Mergesort, quicksort Busca de subcadeias
Filas com prioridade Compresso de dados
Busca Estratgias programativas
rvores binrias de busca Diviso-conquista
rvores equilibradas Algoritmos gananciosos
Tabelas de disperso Programao dinmica
Intratabilidade
6/1/16 Algoritmos e Estruturas de Dados 9
Algoritmos de programao
Busca linear
Busca dicotmica
Insertionsort
Mergesort
Quicksort
Converso numrica
Reverso numrica
Mximo, mnimo de um array
Remoo de duplicados
Comparao lexicogrfica de arrays
6/1/16 Algoritmos e Estruturas de Dados 10
Algoritmos no ensino secundrio
Fatorizao
Mximo divisor comum
Simplificao de fraes
Regra de Ruffini
Mtodo de Gauss
Crivo de Eratstenes.
StdIn
// ...
Lio n. 2
Animao algortmica
Animao algortmica
Visualizao dos algoritmos
Utilizao do Processing
Recapitulao
Integrao com o Java
Animao do algoritmo de Euclides
}
$ pwd
/Users/pedro/Dropbox/AED_1516/ws2
$ cd TShirt/bin
$ ls
TShirtSketch.class
$ java -cp ../../core.jar:. TShirtSketch
// ...
6/1/16} Algoritmos e Estruturas de Dados 13
Variveis da animao
Registamos o tempo em que a animao comea, o
nmero de passos na animao e o valor do par de
inteiros:
public class EuclidSketch extends PApplet
{
// ...
private double startTime; // time when the animation started
private int steps; // number of steps in the animation
private int[] current; // current values being shown
// ...
}
Lio n. 3
Colees: sacos, pilhas e filas
Colees: sacos, pilhas e filas
Especificao das colees
Classes iterveis
Sacos (em ingls bags)
Implementao com arrays
Pilhas (em ingls stacks)
Implementao com listas
Filas (em ingls queues)
Implementao como exerccio.
Estudaremos hoje os sacos. As
pilhas e as filhas ficam para
uma das prximas lies.
// ...
Recorde que a capacidade do array est
}
registada no membro length do array.
public Bag()
{
items = (T[]) new Object[1];
size = 0;
}
Note bem: criamos um array de
// ...
objetos, e foramos a converso
}
para array de T.
public T next()
{
return items[i++];
}
// ...
// ...
}
Lio n. 4
Interldio: arrays base de sacos
Interldio: arrays base de sacos
Arrays em Java e arrays em C
Classe ArrayBag<T>.
Interfaces funcionais.
Expresses lambda.
// ...
}
Lio n. 5
Pilhas
Pilhas
Implementao com arrays redimensionveis.
Implementao com listas ligadas.
Aplicao: avaliao de expresses
aritmticas usando o algoritmo da pilha dupla,
de Dijkstra.
public Stack()
{
// ...
}
// ...
6/1/16 Algoritmos e Estruturas de Dados 5
Encolhendo no pop
A estratgia ser encolher para metade quando o
tamanho estiver a 25% da capacidade:
public class Stack<T> implements Iterable<T>
{
// ... Anula-se o apontador para que no
permanea no array uma referncia para o
public T pop() elemento removido, o que atrasaria a
{ garbage collection. Se no anulssemos,
T result = items[--size]; teramos vadiagem (em ingls, loitering):
referncias no array para valores inteis.
items[size] = null;
if (size > 0 && size == items.length / 4)
resize(items.length / 2);
return result;
} Note bem: no seria sensato encolher para
metade quando o array estivesse meio cheio,
// ... pois nesse caso ele ficava cheio logo aps ter
encolhido, e se houvesse um push a seguir, teria
de crescer de novo.
6/1/16 Algoritmos e Estruturas de Dados 6
Iterador reverso
Nas pilhas, queremos iterar os elementos de maneira a ver
primeiro os que entraram na pilha mais recentemente:
// ...
public T next()
{
return items[--i];
}
// ...
// ...
// ...
public T next()
{
T result = cursor.value;
cursor = cursor.next;
return result;
}
Prximas tarefas:
Evitar ter de separar os tquenes por espaos.
Evitar ter de distinguir os operadores com if-else em
cascata
6/1/16 Algoritmos e Estruturas de Dados 20
Algoritmos e Estruturas de Dados
Lio n. 6
Avaliao de expresses aritmticas
Avaliao de expresses aritmticas
Utilizao de tabelas de disperso.
Toquenizao de cadeias de caracteres.
Expresses regulares.
Esta lio antecipa matrias que
veremos mais adiante com mais
profundidade.
// ...
}
public DijkstraTwoStack2016()
{ Temos aqui mais operaes do
ops2 = new HashTable<>(); que no exerccio da lio
ops2.put("+", (x, y) -> x + y);
ops2.put("-", (x, y) -> x - y);
anterior.
ops2.put("*", (x, y) -> x * y);
ops2.put("/", (x, y) -> x / y);
ops2.put("%", (x, y) -> x % y);
ops2.put("max", (x, y) -> x >= y ? x : y);
ops2.put("min", (x, y) -> x <= y ? x : y);
ops2.put("^", (x, y) -> Math.pow(x, y));
// ...
}
6/1/16 Algoritmos e Estruturas de Dados 10
StringUtils: take e drop
Observe:
public static String take(String s, int n)
{
assert n > 0;
if (n > s.length())
n = s.length();
return s.substring(0, n);
}
Lio n. 7
Filas
Filas
Filas simples.
Implementao das filas simples com listas
ligadas.
Filas com prioridade.
Implementao das filas com prioridade com
heaps.
16
16 12
12
9
9 7 5 4
7
5
4 7 2
4
testPriorityQueueInteger(byValue0);
testPriorityQueueInteger((x, y) -> x-y); Esta funo de demonstrao ilustra
testPriorityQueueInteger(byWeight);
testPriorityQueueInteger(byWeightThenValue); a utilizao de comparadores.
testPriorityQueueInteger(Integer::compare);
testPriorityQueueInteger(Comparator.comparing(PriorityQueue::weight));
testPriorityQueueInteger(byWeight.thenComparing(byValue));
testPriorityQueueInteger(Collections.reverseOrder(byWeightThenValue));
testPriorityQueueInteger(Integer::compare);
testPriorityQueueString(String::compareTo);
testPriorityQueueString(byString);
testPriorityQueueString(Collections.reverseOrder(byString));
testPriorityQueueString(byLengthThenString1);
testPriorityQueueString(Collections.reverseOrder(byLengthThenString));
}
Lio n. 8
Anlise de Algoritmos
Anlise de Algoritmos
Questes centrais: tempo e memria.
Exemplo: soma tripla.
Determinao da frequncia absoluta
das instrues.
Aproximao til.
Medio do tempo de clculo.
Lio n. 9
Ordem de crescimento do tempo de execuo
Ordem de crescimento do tempo de
execuo
Classificao por ordem de crescimento do
tempo de execuo.
Gerao de arrays aleatrios.
Ensaios de razo dobrada.
{
public class BinarySearch int result = 0;
{ int d = 0;
int n = a.length;
// ... while (n > 0)
{
} int m = n / 2;
if (x <= a[d+m])
n = m;
else
{
result += m+1;
d += m+1;
n -= m+1;
}
}
return result;
6/1/16 Algoritmos }
e Estruturas de Dados 23
Funo da busca dicotmica
A busca dicotmica programa-se nas calmas
recorrendo ao renque.
Em caso de busca falhada, a funo retorna -1, como
de costume; em caso de busca bem sucedida, a
funo retorna o ndice do primeiro elemento do
array cujo valor igual ao valor procurado.
public static int bfind(int[] a, int x)
{
Esta funo pertence classe BinarySearch.
int r = rank(a, x);
return r < a.length && a[r] == x ? r : -1;
}
Note bem: esta funo devolve o ndice do primeiro
elemento com o valor dado, mesmo que haja vrios
elementos iguais a esse. Outras variantes da busca
dicotmica devolvem o ndice de um dos elementos
com o valor dado, no necessariamente o primeiro.
6/1/16 Algoritmos e Estruturas de Dados 24
Curiosidade: busca dicotmica tradicional
Esta a verso tradicional, que no se baseia no renque.
public static int bsearch(int x, int[] a)
{
int result = -1;
int i = 0;
int j = a.length - 1;
while (result == -1 && i <= j)
{
int m = i + (j - i) / 2; Porqu escrever i+(j-i)/2 e no,
if (x < a[m]) mais simplesmente, (i+j)/2?
j = m - 1; Resposta em
else if (x > a[m]) http://googleresearch.blogspot.pt/
i = m + 1; 2006/06/extra-extra-read-all-
else about-it-nearly.html.
result = m;
} Se houver mais do que um elemento
return result; com o valor procurado, esta acerta num
} deles, no necessariamente no primeiro.
6/1/16 Algoritmos e Estruturas de Dados 25
Funo countFaster
Eis o novo algoritmo para o problema da soma
tripla:
public static int countFaster(int[] a, int x)
{
// a is sorted
int result = 0;
final int n = a.length;
for (int i = 0; i < n; i++)
for (int j = i + 1; j < n; j++)
{
int r = BinarySearch.bfind(a, x - (a[i] + a[j]));
if (r > j)
result++; Com dois ciclos for imbricados e uma busca
} dicotmica l dentro, o tempo de crescimento
return result; de ordem N2logN, certamente.
}
...
else if (choice == 'I')
testDoubleRatio((a, x) -> ThreeSum.countFaster(a, x),
(a, x) -> RandomArrays.uniformUnique(a, x),
100, 1000, 1500, times);
...
6/1/16 Algoritmos e Estruturas de Dados 27
Resultados do ensaio
Eis os resultados do ensaio de razo dobrada com a
funo countFaster:
$ java -cp ../../algs4.jar:. ThreeSum I 7
100 0.0001
200 0.0007 4.68
400 0.0031 4.63 A razo ligeiramente superior a 4 (e
800 0.0138 4.40 muito inferior a 8). Isto confirma a
1600 0.0598 4.32
constatao de que esta funo
3200 0.2520 4.22
6400 1.0510 4.17
~N2logN.
$
Lio n. 10
Union-Find
Union-Find
Problema da conectividade dinmica.
Union-Find, em geral.
Quick-Find.
Quick-Union.
Quick-Union-Weighted.
Note bem: o programa desenha uma conexo entre dois ns vizinhos se eles estiverem
na mesma componente. Outra coisa seria desenhar uma conexo entre dois ns da
mesma componente se eles fossem vizinhos, ainda que o efeito visual fosse o mesmo.
6/1/16 Algoritmos e Estruturas de Dados 5
Classe abstrata UnionFind
Precisamos de uma operao para ligar dois ns, union, e
outra para ver se dois ns pertencem mesma componente,
connected.
J agora, tambm uma operao para dar o nmero de
componentes, count, e outra para calcular o identificador da
componente a que um dado n pertence, find.
Reunimos isto numa classe abstrata:
public abstract class UnionFind
{
public abstract void union(int x, int y);
public abstract boolean connected(int x, int y);
public abstract int count();
public abstract int find(int x);
}
O nome consagrado para a classe (e para o algoritmo em
anlise) vem do nome das operaes tpicas: union e find.
6/1/16 Algoritmos e Estruturas de Dados 6
Programando connected
Podemos oferecer j uma implementao da
operao connected, uma vez que, por hiptese, dois
ns estaro conectados se pertencerem mesma
componente:
public abstract class UnionFind
{
public abstract void union(int x, int y);
public abstract int find(int x);
public abstract int count();
7 liga a 1
8 liga a 2
2 liga a 7
0 liga a 4
6 liga a 3
6 liga a 2
2 liga a 0
Lio n. 11
QuickUnion
Union-Find
QuickUnion.
QuickUnion Weighted.
Liga do amarelo
para o verde.
Liga do amarelo
para o verde.
Aqui o 6 liga ao 2.
Aqui o 2 liga ao 6.
Lio n. 12
Ordenao de arrays
Ordenao de arrays
Preliminares.
Classes para os algoritmos de ordenao.
Animao algortmica.
Algoritmos quadrticos:
Bubblesort.
Selectionsort.
Inserstionsort.
...
public static void test(Sort<Integer> s, int size, int max, int times)
{
double z[] = doubleRatio(s, size, max, times);
printTable(size, z);
}
6/1/16 Algoritmos e Estruturas de Dados 15
}
Razo dobrada, Bubblesort
Acrescentamos um teste na funo main:
public static void main(String[] args)
{
...
else if (choice == 'C')
testDoubleRatio(new Bubblesort<Integer>(), 1000, 10000, 7)
...
}
Conclumos que os tempos com este bubblesort com ints esto consistentemente
abaixo de metade dos tempos do anterior bubblesort com Integers.
Lio n. 13
Ordenaes subquadrticas
Ordenaes subquadrticas
Shellsort.
Mergesort.
Quicksort.
Note que no estaria bem fazer apenas a = sortf(a) pois nesse caso estaramos a mudar a
cpia local da referncia para o array. O array passado em argumento ficaria na mesma!
6/1/16 Algoritmos e Estruturas de Dados 14
Ensaio de razo dobrada, mergesort funcional
No meu computador:
$ java ... MergesortFunctional C
10000 0.0027
20000 0.0042 1.60
40000 0.0088 2.06
80000 0.0193 2.21 Notamos que os quocientes so acima de 2
160000 0.0447 2.31 (quando os tempos deixam de ser diminutos) mas
320000 0.0905 2.03 abaixo dos do shellsort. Estes valores so um
640000 0.2183 2.41 sintoma de complexidade N log N.
1280000 0.5040 2.31
2560000 1.9450 3.86 $ java ... Shellsort C
10000 0.0025
5120000 3.8270 1.97 20000 0.0057 2.30
$ 40000 0.0136 2.39
80000 0.0324 2.38
160000 0.0813 2.51
320000 0.2575 3.17
O mergesort funcional mais de duas 640000 0.7050 2.74
1280000 1.6690 2.37
vezes mais rpido do que Shellsort, 2560000 4.4150 2.65
para arrays grandes. 5120000 10.3830 2.35
$
6/1/16 Algoritmos e Estruturas de Dados 15
Mergesort tradicional
Normalmente, queremos fazer o mergesort usando s dois arrays:
o array a ordenar, o qual vai receber o resultado de cada uma das
fuses, e um array auxiliar, para onde copiamos, justapostas, as duas
metades do array, j ordenadas, em cada chamada recursiva, para
depois serem fundidas de volta para o array dado.
Normalmente esse array auxiliar seria declarado na funo merge e
copiaramos para ele o array cujas metades ordenadas queremos
fundir, assim, em esquema:
public void merge(T[] a, ...)
{
T[] aux = (T[]) Array.newInstance(a.getClass().getComponentType(), ...);
...
}
Lio n. 14
Complexidade da ordenao
Complexidade da ordenao
Limites da complexidade da ordenao.
Mergesort bottom-up.
Lio n. 15
Quicksort
Quicksort
Quicksort clssico.
Complexidade do quicksort.
Vulnerabilidade do quicksort.
...
1 3 5 2 4 6 7 8 9 10
1 3 4 2 5 6 7 8 9 10
Como evitar o ataque?
1 3 2 4 5 6 7 8 9 10
1 2 3 4 5 6 7 8 9 10
6/1/16 Algoritmos e Estruturas de Dados 17
Evitando o ataque
Evita-se o ataque escolhendo um piv que no
seja nem o maior elemento do array nem o
menor.
H vrias tcnicas para fazer isso.
A mais prtica baralhar aleatoriamente o array
antes de ordenar.
Assim, fica impossvel fabricar bombas
deliberadamente.
A probabilidade de a baralhao aleatria de um
array grande produzir uma bomba nfima.
Lio n. 16
Quicksorts especializados
Quicksorts especializados
Quicksort com cutoff.
Quicksort tripartido.
Quicksort com duplo piv.
public QuicksortCutoff(int x)
{
cutoff = x;
}
Veja
6/1/16 online em http://w3.ualg.pt/~pjguerreiro/sites/20_aed_1314/movies/partition_3.m4v
Algoritmos e Estruturas de Dados 7
Quicksort tripartido
Faz uma partio ternria, anloga da bandeira holandesa.
Os azuis so os elementos menores que o piv; os brancos so os iguais
ao piv; os vermelhos so os maiores que o piv:
public void partitionTri(T[] a, int d, int n)
{
int i = 1; // number of elements less than pivot, so far, plus 1 for the pivot
int j = 0; // number of elements equal to pivot, so far;
int k = 0; // number of elements greater than pivot, so far;
T p = a[d];
while (i+j+k < n) Note bem: o piv o primeiro elemento,
{ que fica de fora das comparaes; no fim
T x = a[d+i+j];
if (less(x, p)) ser trocado para a posio certa.
{
exchange(a, d+i, d+i+j);
i++; Azuis
}
else if (less(p, x))
{
exchange(a, d+n-1-k, d+i+j); Vermelhos
k++;
} OK, mas os valores
else
Brancos finais de i, j e k tm
j++;
} de ser devolvidos
exchange(a, d, d+i-1); // move pivot to its sorted position pela funo. Como
i--; fazer?
}
6/1/16 Algoritmos e Estruturas de Dados 8
Longos, para pares
A funo partitionTri tem de devolver os valores finais de i, j e k, para
serem usados nas chamadas recursivas subsequentes.
Na verdade, basta devolver dois deles, por exemplo, i e k, pois ento j = n
(i+k).
Mas as funes s podem devolver um valor!
Agrupemos ento dois int num long, e devolvamos um long.
Eis a infraestrutura:
public static long pair(int x, int y)
{
long xl = x;
long yl = y; public static int first(long x)
xl = xl << 32; {
yl = yl & 0x0FFFFFFFFL; long result = x >> 32;
return xl | yl; return (int) result;
} }
Veja online em
http://w3.ualg.pt/~pjguerreiro/sites/20_aed_1314/movies/quicksort_tripartite_organ.m4v
6/1/16 Algoritmos e Estruturas de Dados 13
Caso de haver muitos duplicados
O quicksort tripartido porta-se bem no caso de haver muitos
duplicados, pois todos os elementos iguais ao piv ficam logo
arrumados, de uma vez.
Com efeito, havendo muitos duplicados, haver muitos
elementos iguais ao piv.
Observe:
Veja online em
http://w3.ualg.pt/~pjguerreiro/sites/20_aed_1314/movies/quicksort_tripartite_lots_duplicates.m4v
6/1/16 Algoritmos e Estruturas de Dados 14
Quicksort com piv duplo
uma variante do tripartido, usando dois pivs. Assim, os
azuis so os menores que o primeiro piv, os vermelhos os
maiores que segundo piv e os outros so brancos.
O piv da esquerda menor ou igual ao piv da direita:
private long partitionDual(T[] a, int d, int n)
{
T p = a[d]; // left pivot
T q = a[d+n-1]; // right pivot
int i = 1; // number of elements < p, so far, plus 1 for a[0];
int j = 0; // number of elements >= p and <= q, so far;
int k = 1; // number of elements > q so far, plus 1 for a[n-1];
while (i+j+k < n)
{
T x = a[d+i+j];
if (less(x, p)) Azuis
...
else if (less(q, x)) Vermelhos
...
else
...; Brancos
}
return pair(i, k);
}
6/1/16 Algoritmos e Estruturas de Dados 15
The devil is in the details
private long partitionDual(T[] a, int d, int n)
{
if (less(a[d+n-1], a[d])) Trocamos os candidatos a pivs, se for preciso.
exchange(a, d, d+n-1);
T p = a[d]; // left pivot
T q = a[d+n-1]; // right pivot
int i = 1; // number of elements < p, so far, plus 1 for a[0];
int j = 0; // number of elements >= p and <= q, so far;
int k = 1; // number of elements > q so far, plus 1 for a[n-1];
while (i+j+k < n) De incio, no mexemos nos pivs. Fica para o fim.
{
...
}
// exchange left pivot with last element less than left pivot.
exchange(a, d, d+i-1);
i--;
// j++; OK, but not necessary
// exchange right pivot with first element greater than right pivot.
exchange(a, d+n-1, d+n-k);
k--; No fim, trocamos os pivs, que estavam nas pontas, para as
// j++; OK, but not necessary suas posies ordenadas. Note que estes elementos
return pair(i, k); atingiram as suas posies finais e no entraro em mais
} operaes.
Lio n. 17
Outros algoritmos de ordenao
Outros algoritmos de ordenao
Timsort.
Ordenaes de arrays de nmeros.
Bucketsort.
Countsort.
Bitsort.
16000 0.003 0.004 0.002 0.003 0.002 0.003 0.002 0.006 0.009 0.002 0.004
32000 0.008 0.006 0.006 0.006 0.006 0.006 0.005 0.007 0.005 0.005 0.009
64000 0.018 0.012 0.012 0.014 0.011 0.012 0.010 0.014 0.011 0.010 0.019
128000 0.043 0.027 0.027 0.030 0.025 0.027 0.022 0.031 0.023 0.023 0.042
256000 0.117 0.065 0.067 0.072 0.059 0.062 0.055 0.068 0.053 0.053 0.105
512000 0.351 0.167 0.174 0.191 0.153 0.147 0.136 0.160 0.123 0.126 0.290
1024000 0.968 0.411 0.435 0.487 0.380 0.348 0.307 0.375 0.291 0.282 0.948
2048000 2.432 0.930 1.007 1.123 0.862 0.777 0.706 0.864 0.650 0.634 1.448
size shell quick cutoff tripart dual merge mergebu my_tim qsort
1000 0.000 0.000 0.000 0.000 0.000 0.000 0.000 0.000 0.000
2000 0.000 0.000 0.000 0.000 0.000 0.000 0.000 0.000 0.000
4000 0.001 0.001 0.000 0.001 0.001 0.001 0.001 0.001 0.000
8000 0.002 0.001 0.001 0.002 0.001 0.001 0.001 0.001 0.001 Note bem: em
16000 0.005 0.002 0.002 0.004 0.002 0.003 0.003 0.002 0.002 Java com arrays
C
32000 0.011 0.005 0.005 0.008 0.005 0.007 0.006 0.005 0.005
de Integer; em
64000 0.024 0.010 0.010 0.016 0.011 0.014 0.013 0.011 0.010
128000 0.054 0.021 0.020 0.035 0.022 0.030 0.027 0.023 0.021 C com arrays
256000 0.124 0.046 0.042 0.074 0.048 0.063 0.058 0.049 0.044 de int.
512000 0.283 0.094 0.088 0.155 0.100 0.133 0.122 0.103 0.092
1024000 0.646 0.196 0.190 0.327 0.211 0.279 0.256 0.216 0.196
2048000 1.460 0.417 0.398 0.705 0.454 0.583 0.541 0.451 0.408
4096000 3.388 0.906 0.862 1.498 0.978 1.216 1.143 0.945 0.843
6/1/16 Algoritmos e Estruturas de Dados 15
Eplogo: o bug do Timsort
Um grupo de cientistas descobriu em 2015 que o Timsort est errado.
No entanto, o erro s se manifestaria em arrays muito maiores do que os
que existem atualmente.
O erro est na ideia base da fuso:
Se A <= B+C ento funde-se A e B.
Se no, se B <= C, ento funde-se B e C.
Se no, vai-se buscar o prximo troo.
Nos casos em que tenha havido fuso, repete-se a tentativa de fuso.
Este esquema garante que temos sempre A > B+C e B > C, em cada passo do
algoritmo.
Ora, se os troos forem 120, 80, 25, 20, 30, temos 120 > 80+25 e 80 > 25;
tambm 80 > 25+20 e 25 > 20; mas 25 <= 20+30. Logo, funde-se 25 e 20.
Obtm-se 120, 80, 45, 30.
Isto significa que os comprimentos dos troos podem crescer mais
devagar do que se pensava e causar overflow no array dos comprimentos
dos troos.
Ver http://envisage-project.eu/proving-android-java-and-python-sorting-
algorithm-is-broken-and-how-to-fix-it/.
6/1/16 Algoritmos e Estruturas de Dados 16
Ainda outros algoritmos
Heapsort.
Relacionado com as filas com prioridade.
NlogN, sempre.
Introsort.
um quicksort introspetivo: quando nota que a
recursividade est a ficar muito profunda, muda
para Heapsort.
Assim, garante NLogN, sempre.
Lio n. 18
Tabelas
Tabelas
Tabelas naturais.
Tabelas sequenciais.
Tabelas de disperso.
Tabelas de encadeamentos separados.
Tabelas de endereamento aberto.
...
}
6/1/16 Algoritmos e Estruturas de Dados 4
Construtores
Oferecemos dois construtores: um que
permite indicar a capacidade inicial, outro que
usa a capacidade fixada por defeito:
@SuppressWarnings("unchecked")
public NaturalTable(int capacity)
{
this.size = 0;
values = (T[]) new Object[capacity];
}
public NaturalTable()
{
this(DEFAULT_CAPACITY);
}
Usamos a tcnica do {
private int i;
costume, mas observe public Keys()
a utilizao da funo {
i = advance(0);
advance: }
Funo de teste {
NaturalTable<String> table = new NaturalTable<String>(d);
while (!StdIn.isEmpty())
$ java ... NaturalTable 10 {
p 4 uuu String cmd = StdIn.readString();
p 7 fff if ("p".equals(cmd))
s {
4: uuu int x = StdIn.readInt();
7: fff String s = StdIn.readString();
capacity: 10 table.put(x, s);
size: 2 }
isEmpty? false else if ("g".equals(cmd))
p 100 aaa {
s int x = StdIn.readInt();
4: uuu String s = table.get(x);
7: fff StdOut.println(s);
100: aaa }
capacity: 101 else if ("d".equals(cmd))
size: 3 {
isEmpty? false int x = StdIn.readInt();
d 100 table.delete(x);
p 40 hhh }
i else if ("i".equals(cmd))
4 7 40 {
g 30 for (int x : table)
null StdOut.print(" "+ x);
g 1000 StdOut.println();
null }
g 40 else if ("s".equals(cmd))
hhh {
s StdOut.println(table);
4: uuu StdOut.println("size: " + table.size());
7: fff StdOut.println("isEmpty? " + table.isEmpty());
40: hhh }
capacity: 101 }
size: 3 }
isEmpty? false
6/1/16 Algoritmos e Estruturas de Dados 12
Tabelas sequenciais
Nas tabelas sequenciais, os pares chave-valor
so guardados numa lista.
Na nossa implementao, cada novo par
colocado cabea da lista.
A memria usada dinamicamente, justa.
Inseres e buscas tm complexidade linear.
Logo, no recomendvel que estas tabelas
sejam muito grandes.
Usaremos listas imutveis.
...
}
6/1/16 Algoritmos e Estruturas de Dados 15
Classe Empty<T> class Empty<T> extends List<T>
{
public int size()
Observe: {
return 0;
}
public T head()
{
throw new NoSuchElementException();
}
...
6/1/16 Algoritmos e Estruturas de Dados 16
Classe Cons<T>
Esta que trabalha verdadeiramente:
class Cons<T> extends List<T>
{
private final T value;
private final List<T> next;
Na classe Cons<T>:
public String join(String separator)
{
String result = value.toString();
if (!next.isEmpty())
result += separator + next.join(separator);
return result;
}
Na classe Empty<T>:
public List<T> append(List<T> other)
{
return other;
}
Na classe Cons<T>:
public List<T> append(List<T> other)
{
return next.append(other).cons(value);
}
Na classe Cons<T>:
public boolean has(T x)
{ Repare que ao apagar um elemento
return value.equals(x) || next.has(x); que no existe, a funo delete
}
constri uma lista nova, igual lista
public List<T> delete(T x) objeto.
{
return value.equals(x) ? next : next.delete(x).cons(value);
}
6/1/16 Algoritmos e Estruturas de Dados 21
Interface Iterable<T>
Convm que a lista tenha um iterador:
public abstract class List<T> implements Iterable<T>
{
...
}
6/1/16
... Algoritmos e Estruturas de Dados 22
Classes privadas
Na classe Empty<T>: Na classe Cons<T>:
private class Items implements Iterator<T> private Cons<T> self()
{ {
return this;
public boolean hasNext() }
{
return false; private class Items implements Iterator<T>
} {
private List<T> current = self();
public T next()
{ public boolean hasNext()
throw new UnsupportedOperationException(); {
} return !current.isEmpty();
}
public void remove()
{ public T next()
throw new UnsupportedOperationException(); {
} T result = current.head();
} current = current.tail();
return result;
}
Lio n. 19
Tabelas de disperso, encadeamentos separados
Tabelas de disperso
Tabelas naturais.
Tabelas sequenciais.
Tabelas de disperso
Tabelas de encadeamentos separados.
Tabelas de endereamento aberto.
public SeparateChaining()
{
this(DEFAULT_DIMENSION);
}
Lio n. 20
Tabelas de disperso, endereamento aberto
Tabelas de disperso, de novo
Tabelas naturais.
Tabelas sequenciais.
Tabelas de encadeamentos separados.
Tabelas de endereamento aberto.
public HashTable()
{
this(0); // default capacity is primes[0], i.e., 17.
}
6/1/16 Algoritmos e Estruturas de Dados 5
Funo get
Procuramos a chave circularmente a partir da
posio de disperso (isto , a partir do ndice
calculado pela funo hash).
A busca quando chegamos a uma posio livre ou
quando encontramos a chave:
public V get(K key)
{
int i = hash(key);
while (keys[i] != null && !key.equals(keys[i]))
i = (i+1) % capacity;
return values[i];
}
Note bem: se houver bastantes posies livres e se estas estiverem bem
distribudas, as buscas sero curtas. por isso (isto , para garantir que as buscas
so curtas) que no convm deixar os arrays encher muito.
6/1/16 Algoritmos e Estruturas de Dados 6
Funo privada putBasic
Se no for preciso redimensionar, comea como a
funo get, procurando a chave.
Se encontrar, reafeta o valor; se no, acrescenta a
chave na posio livre e o valor na posio
correspondente:
private void putBasic(K key, V value)
{
int i = hash(key);
while (keys[i] != null && !key.equals(keys[i]))
i = (i+1) % capacity;
if (keys[i] == null)
{
size++;
keys[i] = key;
}
values[i] = value;
}
6/1/16 Algoritmos e Estruturas de Dados 7
Funo put
Ser preciso redimensionar quando o fator de
carga maior do que o mximo fator de carga
permitido:
public void put(K key, V value)
{
if (loadFactor() >= maxLoadFactor)
{
assert resizeCount + 1 < primes.length;
// if it fails, it fails...
resize(resizeCount + 1);
}
putBasic(key, value);
}
6/1/16 Algoritmos e Estruturas de Dados 8
Fator de carga
O fator de carga o quociente do tamanho
pela capacidade:
public double loadFactor()
{
return (double) size / capacity;
}
claro que quanto maior for o fator de carga,
mais trabalho ter a tabela, na funo get e na
funo put.
public Keys()
{
i = advance(0);
}
...
6/1/16 } Algoritmos e Estruturas de Dados 13
O iterador dos valores
Por simetria, acrescentamos o iterador dos valores:
private class Values implements Iterator<V>
{
private int i;
public Values()
{ public Iterator<V> values()
i = advance(0); {
}
return new Values();
private int advance(int x) }
{
int result = x;
while (result < keys.length && keys[result] == null)
result++;
Para normalizar a nomenclatura,
return result; juntamos uma funo keys que
}
d o iterador da chaves (que
public boolean hasNext() tambm dado pela funo
{
return i < keys.length; iterator):
}
public Iterator<K> keys()
public V next()
{
{
V result = values[i++]; return new Keys();
i = advance(i); }
return result;
}
...
6/1/16
} Algoritmos e Estruturas de Dados 14
Funo toString
O resultado uma sequncia de linhas, uma para
cada posio nos dois arrays:
public String toString()
{
String result = "";
for (int i = 0; i < capacity; i++)
{
result += i + ":";
if (keys[i] != null)
result += " " + keys[i] + " " + values[i];
result += newLine;
}
return result;
}
Recorde:
private static String newLine = System.getProperty("line.separator");
10.00
nmero de passos
8.00
6.00
4.00
2.00
0.00
0 0.1 0.2 0.3 0.4 0.5 0.6 0.7 0.8 0.9 1
fator de carga
Isto d uma medida do Claramente, no devemos
desempenho no pior caso. deixar que o fator de carga
ultrapasse 80%, no mximo.
6/1/16 Algoritmos e Estruturas de Dados 19
Redimensionamento
A funo put redimensiona automaticamente:
public void put(K key, V value)
{
if (loadFactor() >= maxLoadFactor)
{
assert resizeCount + 1 < primes.length;
// if it fails, it fails...
resize(resizeCount + 1);
}
putBasic(key, value);
}
Testando o redimensionamento
s
0:
1:
2: 2 aaa
3:
4:
5:
Prosseguimos a p 1700 mmm
s
6:
7: 340 zzz
experincia anterior, 0: 340 zzz 8:
numa altura em que o 1: 1700 mmm 9:
10: 10 bbb
2: 2 aaa
tamanho era 6: 3: 172 sss 11:
4: 20 vvv 12: 197 vvv
5: 13:
p 23 ttt 14: 51 qqq
6: 23 ttt
p 340 zzz 15:
7: 16:
s
8: 17:
0: 340 zzz
9: 18:
1:
10: 10 bbb 19:
2: 2 aaa
11: 180 uuu 20: 20 vvv
3: 172 sss 21:
12: 197 vvv
4: 20 vvv 22:
13:
5: 23: 23 ttt
14:
6: 23 ttt 24: 172 sss
15:
7: 25:
16:
8: 26:
size: 9 27:
9:
isEmpty? false 28:
10: 10 bbb
load factor: 0.529 29:
11: 180 uuu
30:
12: 197 vvv
13: Aqui o fator de carga 31:
32: 180 uuu
14: ultrapassou o limite. No 33:
15:
16: prximo put haver 34:
35: 1700 mmm
size: 8 redimensionamento. 36:
isEmpty? false size: 10
load factor: 0.471 isEmpty? false
load factor: 0.270
6/1/16 Algoritmos e Estruturas de Dados 21
Aglomerao primria
Considere, como exemplo, uma tabela com capacidade 7,
inicialmente vazia. Ao chegar a primeira chave, a probabilidade
de ela vir a preencher a posio 3, por exemplo, igual de
ela preencher qualquer outra posio, ou seja 1/7.
Suponhamos que ela preenche a posio 3.
Agora chega a segunda chave. A probabilidade de esta vir a
preencher a posio 3 zero, porque a posio 3 j est
ocupada. Mas a probabilidade de vir a preencher a posio 4
2/7, a soma da probabilidade de a posio de disperso
calculada ser 3 com a probabilidade de ser 4.
Quer dizer, a probabilidade de uma nova chave ficar a seguir a
uma posio ocupada maior do que a probabilidade mdia.
Logo, h uma certa tendncia indesejvel para as chaves se
aglomerarem no vector das chaves, em vez de terem uma
distribuio uniforme.
6/1/16 Algoritmos e Estruturas de Dados 22
Dupla disperso
Evita-se a aglomerao primria usando a dupla disperso: em
vez de tentar apanhar uma posio livre linearmente na tabela
incrementa-se de um valor obtido por uma segunda funo de
disperso.
Agora, na funo get, por exemplo, avana-se no de 1 em 1
mas de h2 em h2, representando por h2 o resultado da
segunda funo de disperso:
public V get(K key)
{
int i = hash(key);
while (keys[i] != null && !key.equals(keys[i]))
i = (i+h2) % capacity;
return values[i];
}
O valor de h2 deve estar entre 2 e capacity-2 (inclusive). De facto, no convm
que seja 1 ou capacity-1, pois ento estaramos no caso normal; e no pode ser
0 ou capacity, porque assim a tabela no funcionaria. Qualquer outro valor serve,
admitindo que, como sempre, capacity um nmero primo. Se capacity no fosse
um nmero primo, nem todos os valores do intervalo [0..capacity[ seriam
apanhados, no ciclo da funo get, e a tabela no funcionaria.
6/1/16 Algoritmos e Estruturas de Dados 23
Paradoxo do dia de aniversrio
Qual a probabilidade de haver nesta sala duas pessoas ou mais
que fazem anos no mesmo dia?
Generalizando: qual a probabilidade de, escolhendo
sucessivamente K nmeros de um conjunto com N nmeros, haver
nos nmeros escolhidos dois ou mais nmeros iguais.
Bom, 1 menos a probabilidade no haver dois nmeros iguais,
entre os escolhidos.
H quantas sequncias com K elementos escolhidos entre os N?
NK.
H quantas sequncias com K elementos no repetidos escolhidos
entre os N? N!/(N-K)!
Todas as sequncias poder ser escolhidas com igual probabilidade.
Logo, se houver K pessoas na sala, a probabilidade de haver duas ou
mais com o mesmo dia de aniversrio :
Repare que para K = 0 ou para K = 1 a expresso
365!
vale 0. Realmente se houver zero pessoas ou uma (365 K )! s fazer as contas!
pessoa na sala, a probabilidade de haver duas que
1
365K
fazem anos no mesmo dia zero!
6/1/16 Algoritmos e Estruturas de Dados 24
Tabela paradoxal 0
1
0.000000
0.000000
2 0.002740
aniversrio.
18 0.346911
19 0.379119
20 0.411438
que parece...
29 0.680969
30 0.706316
Lio n. 21
rvores
rvores
rvores.
rvores simples.
rvores binrias.
rvores mutveis e rvores imutveis.
A funo size:
Repare: o mtodo pblico invoca uma
public int size() funo privada, recursiva, que trabalha
{
return size(root); sobre os ns. Ainda que tenham o
} mesmo nome (por convenincia), so
funes diferentes.
private int size(Node p)
{
return p == null ? 0 : 1 + size(p.left) + size(p.right);
}
6/1/16 Algoritmos e Estruturas de Dados 10
Mais funes da classe Tree<T> alternativa
Funo has:
public boolean has(T x)
{
return has(root, x);
}
Funo toString:
public String toString()
{
sempre o mesmo esquema: o
return stringOf(root); mtodo pblico e a funo recursiva
} privada.
private String stringOf(Node p)
{
return "(" + (p == null ? "" : p.value.toString() + stringOf(p.left) +
stringOf(p.right)) + ")";
}
6/1/16 Algoritmos e Estruturas de Dados 11
Funes de teste para a classe alternativa
Programamos na classe abstrata:
public abstract class Tree<T>
{
...
Lio n. 22
Exerccios com rvores imutveis
Exerccios com rvores imutveis
Escrever as rvores.
Ler as rvores.
Desenhar as rvores.
Experimentamos assim: 12
(12()())
public static void testAdd() 88
(12(88()())())
{
Tree<Integer> t = new Empty<Integer>(); 97
(12(88()())(97()()))
while (!StdIn.isEmpty())
5
{
int x = StdIn.readInt(); (12(88(5()())())(97()()))
2016
t = t.add(x);
StdOut.println(t); (12(88(5()())())(97(2016()())()))
-45
}
(12(88(5()())(-45()()))(97(2016()())()))
}
6/1/16 Algoritmos e Estruturas de Dados 3
Lendo as rvores
Com rvores de inteiros, a escrita parenttica
identifica univocamente a rvore. Logo deve ser
invertvel.
Quer dizer, dada uma cadeia parenttica que
representa uma rvore de inteiros, devemos
conseguir construir a rvore.
Faremos isso usando um mtodo de fbrica, isto ,
uma funo esttica que devolve um objeto do tipo
da classe:
public static Tree<Integer> fromString(String s)
{
...
}
"\\-?\\d+|\\(|\\)"
6/1/16 Algoritmos e Estruturas de Dados 5
Toquenizando a cadeia
Usamos a funo groups da classe RegularExpressions:
public static ArrayBag<String> groups(String s, String regex)
{
ArrayBag<String> result = new ArrayBag<>();
Pattern pattern = Pattern.compile(regex);
Matcher matcher = pattern.matcher(s);
while (matcher.find())
{
String z = matcher.group();
result.add(z);
}
return result;
}
54
-
23
18
58
90
53
18
77
40
45
77
39
23
60
80
97
15
41
-
-
-
6/1/16 Algoritmos e Estruturas de Dados 12
Desenhando com o Processing
Ganhando inspirao na funo diagram, abalancemo-nos
a desenhar rvores no Processing.
Cada rvore ser desenhada num retngulo cujo canto
superior esquerdo o ponto <x0, y0>.
Cada n ocupa um retngulo de largura w e altura h,
num quadriculado de retngulos destes.
O n um crculo de raio r, centrado horizontalmente
no retngulo do n e tangente por baixo ao lado
superior do retngulo.
Os arcos entre ns partem do centro do crculo e
chegam ao ponto mdio do lado superior do retngulo
do outro n.
Os arcos para rvores vazias tm altura igual a h/2 e vo
at ao lado correspondente do retngulo.
6/1/16 Algoritmos e Estruturas de Dados 13
Exemplos
15
11 23
4 12 18 28
// continue recursively
left.draw(p, x0, y0 + h, w, h, r);
right.draw(p, x+w, y0 + h, w, h, r);
}
if (right.isEmpty())
p.line((float)xc, (float)yc,
s acertar a aritmtica...
(float)(x+w), (float)(yc+h/2));
else
p.line((float)xc, (float)yc,
(float)(xc+w*(1+right.left().size())), (float)(y+h));
...
} NB: as funes da classe PApplet esperam floats, no doubles.
6/1/16 Por isso, convertemos
Algoritmos eno momento
Estruturas de Dadosda chamada. 18
Funo draw, desenhando as bolas
Esquerda, direita, vazio, no vazio:
public void draw(PApplet p, double x0, double y0, double w,
double h, double r)
{
... public final int COLOR_VALUES = Colors.BLACK;
public final int COLOR_TEXT = Colors.YELLOW;
// draw the nodes
p.fill(COLOR_VALUES);
p.stroke(COLOR_VALUES);
p.ellipseMode(PApplet.CENTER);
p.ellipse((float)xc, (float)yc, 2*(float)r, 2*(float)r);
p.textAlign(PApplet.CENTER, PApplet.CENTER);
p.fill(COLOR_TEXT);
p.text(value.toString(), (float)xc, (float)yc); ...
}
Na classe Empty<T>:
public Tree<T> left()
{
throw new NoSuchElementException();
}
Lio n. 23
rvores de busca
rvores de busca
rvores imutveis de busca.
Implementao.
Esquetes.
Estruturalmente, as rvores
de busca so rvores 3 32 58
44
binrias como as outras.
Apenas os valores esto
distribudos verificando
aquela propriedade. 12 43 47 63
4 8 +5= 4 8
1 6 9 1 6 9
Note bem: isto o que acontece com rvores
mutveis. No o que acontece com as nossas
rvores, que so imutveis.
5
6/1/16 Algoritmos e Estruturas de Dados 15
Acrescentar imutavelmente
Acrescentar imutavelmente envolve criar uma nova
rvore a cada nvel.
A cada nvel, a nova rvore partilha a rvore do
outro lado:
7 7 7
4 8 +5= 4 4 8
1 6 9 1 6 6 9
5
6/1/16 Notee Estruturas
Algoritmos bem: a rvore
de Dados original continua intacta. 16
Classe Cons<T>, apagar um elemento
Esta funo a mais trabalhosa de todas, na classe
Cons<T>.
J vimos que na classe Empty<T> trivial:
class Empty<T extends Comparable<T>> extends Tree<T>
{
public Tree<T> delete(T x)
{
return this;
}
}
7 4 7 8
4 1 6 8 9
1 6 9
Quer dizer: quando exatamente um dos filhos a rvore vazia, o resultado o
outro filho. Se ambos os filhos forem vazios, o resultado a rvore vazia (mas
este caso pode ser apanhado pelo caso anterior).
6/1/16 Algoritmos e Estruturas de Dados 18
Remover a raiz, caso complicado.
Se ambos os filhos no so vazios, a nova raiz ser o
elemento com valor imediatamente superior ao
valor da raiz eliminada, que precisamente a raiz da
primeira subrvore da subrvore direita:
5 7
3 8 3 8
1 4 7 9 1 4 9
A primeira subrvore do filho direito ter sempre
um filho vazio (o filho esquerdo), pelo menos, e
portanto a sua raiz pode ser removida usando a
tcnica da pgina anterior.
6/1/16 Algoritmos e Estruturas de Dados 19
A primeira subrvore
A primeira subrvore a subrvore cuja raiz fica
mais esquerda, quando desenhamos a rvore
(usando a funo draw):
class Cons<T extends Comparable<T>> extends Tree<T>
{
...
public Tree<T> first() 5 6
{
Tree<T> result = this; 3 8 2 8
if (!left.isEmpty())
result = left.first();
return result;
1 4 7 9 4 7 9
}
A laranja, a primeira subrvore
... de cada uma das rvores. 3 5
}
Na classe Empty<T>, a funo first lana uma exceo.
Tambm haver a funo last, por simetria.
6/1/16 Algoritmos e Estruturas de Dados 20
A ltima subrvore
Por simetria, a ltima subrvore a subrvore
cuja raiz fica mais direita, quando desenha-
mos a rvore:
class Cons<T extends Comparable<T>> extends Tree<T>
{
...
public Tree<T> last() 5 6
{
Tree<T> result = this; 3 8 2 9
if (!right.isEmpty())
result = right.last(); 1 4 7 9 4 7
return result;
} A cor de tijolo, a ltima subrvore
... de cada uma das rvores. 3 5 8
}
O esquete desenha a {
int x = StdIn.readInt();
Acrescentando valores...
Eliminando valores...
Lio n. 24
rvores de busca, complementos
rvores de busca, complementos
Funes de ordem.
Iterao.
Atravessamento.
Iteradores internos.
rvores de busca chave-valor.
public T maximum()
{
throw new UnsupportedOperationException();
}
public T select(int k)
{
throw new UnsupportedOperationException();
}
public T maximum()
{
return last().value();
}
...
}
Na classe Empty<T>:
class Empty<T extends Comparable<T>> extends Tree<T>
{
...
public T floor(T x)
{
return null;
}
public T ceiling(T x)
{
return null;
}
...
}
A explicao anloga da funo select.
TreeIteratorWide()
{
i = new Queue<>();
if (!Tree.this.isEmpty())
i.enqueue(Tree.this);
}
-
public static void testIterators() 82
{ -
Tree<Integer> t = new Empty<Integer>(); 71
-
int[] numbers = StdIn.readAllInts(); 65
for (int x : numbers) -
t = t.put(x); 51
StdOut.println(t); -
43
-
StdOut.println(t.diagram("", " ")); 28
-
Iterator<Integer> itDeep = t.iterator(); 20
-
while (itDeep.hasNext()) 19
StdOut.print(" " + itDeep.next()); -
StdOut.println(); 12
-
8
Iterator<Integer> itWide = t.iteratorWide(); -
while (itWide.hasNext()) 6
StdOut.print(" " + itWide.next()); -
StdOut.println(); 6 8 12 19 20 28 43 51 65 71 82 84 95
} 65 12 71 8 19 95 6 43 82 20 51 84 28
$
public BSTIterator()
{
i = new Stack<>();
if (!BST.this.isEmpty())
i.push(BST.this);
}
...
}
public K next()
{
BST<K, V> t = i.pop();
K result = t.key();
V v = t.value();
if (!t.left().isEmpty())
{
i.push(new BSTCons<K, V>(result, v, new BSTEmpty<K, V>(), t.right()));
i.push(t.left());
result = next();
}
else if (!t.right().isEmpty())
i.push(t.right());
return result;
}
6/1/16
... Algoritmos e Estruturas de Dados 33
Iterador interno de entreordem
Na classe abstrata:
public abstract void inorder(BiConsumer<K, V> action);
Na classe BSTEmpty<K,V>:
public void inorder(BiConsumer<K, V> action)
{
// nothing to do
}
Na classe BSTCons<K,V>:
public void inorder(BiConsumer<K, V> action)
{
left.inorder(action);
action.accept(key, value);
right.inorder(action);
}
6/1/16 Algoritmos e Estruturas de Dados 34
$ java ... BST
Lio n. 25
Outras rvores
Outras rvores
rvores equilibradas.
rvores AVL, rvores rubinegras e rvores
chanfradas.
rvores dois-trs.
rvores rubinegras imutveis.
65 80 71 24 4
32 44 81 31 99 5 52
12 16 61
32 12
Esta no
2 59 33 7 perfeitamente
equilibrada.
91 14 11 41 42 54 1
8 15
Inserir 81.
Inserir 70.
Inserir 30.
6/1/16 Algoritmos e Estruturas de Dados 10
rvores dois-trs, evoluo (2)
(Pgina anterior.)
Inserir 25.
O nmero de
nveis aumentou!
Inserir
19, 65,
93.
O n 65+66 partiu-se
o o 66 subiu.
Inserir 68.
O n 14+19 partiu-se e o 19
subiu; o n 25+30 partiu-se e o
Inserir 23. 25 subiu; o n 63+75 partiu-se
e o 64 subiu. O nmero de
nveis aumentou.
this.value = value;
this.left = left;
this.right = right;
this.size = 1 + left.size() + right.size();
assert invariant();
}
6/1/16 Algoritmos e Estruturas de Dados 19
Invariante das dois-trs binrias
anlogo pr-condio do construtor:
public boolean invariant()
{
return left.invariant() && right.invariant() &&
(left.isEmpty() == right.isEmpty()) &&
(left.isEmpty() || value.compareTo(left.valueRight()) > 0) &&
(right.isEmpty() || value.compareTo(right.valueLeft()) < 0);
}
public T valueRight()
{
return value;
}
6/1/16 Algoritmos e Estruturas de Dados 20
Funo has
A funo has anloga das rvores binrias
de busca:
public boolean has(T x)
{
boolean result = true;
int cmp = x.compareTo(value);
if (cmp < 0)
result = left.has(x);
else if (cmp > 0)
result = right.has(x);
return result;
}
this.valueLeft = valueLeft;
this.valueRight = valueRight;
this.left = left;
this.middle = middle;
this.right = right;
this.size = 2 + left.size() + middle.size() + right.size();
assert invariant();
6/1/16} Algoritmos e Estruturas de Dados 28
Invariante das dois-trs ternrias
, de novo, anlogo pr-condio do construtor:
public boolean invariant()
{
return left.invariant() && middle.invariant() && right.invariant() &&
(left.isEmpty() == middle.isEmpty()) &&
(middle.isEmpty() == right.isEmpty()) &&
(valueLeft.compareTo(valueRight) < 0) &&
(left.isEmpty() || valueLeft.compareTo(left.valueRight()) > 0) &&
(right.isEmpty() || valueRight.compareTo(right.valueLeft()) < 0);
}
Funo putr,
int cmpLeft = x.compareTo(valueLeft);
int cmpRight = x.compareTo(valueRight );
if (cmpLeft == 0 || cmpRight == 0)
return result;
assert left.isEmpty() && middle.isEmpty() && right.isEmpty()
para rvores
|| !left.isEmpty() && !middle.isEmpty() && !right.isEmpty();
if (left.isEmpty() && middle.isEmpty() && right.isEmpty())
{
if (cmpLeft < 0)
result = new FourCons<>(x, valueLeft, valueRight, left, left, left, left);
else if (cmpRight > 0)
ternrias
result = new FourCons<>(valueLeft , valueRight, x, left, left, left, left);
else
result = new FourCons<>(valueLeft , x, valueRight, left, left, left, left);
}
else
{
assert !left.isEmpty() && !middle.isEmpty() && !right.isEmpty();
if (cmpLeft < 0)
{
TwoThreeTree<T> t = left.putr(x);
if (t.isTransient())
{
t = t.split();
result = new FourCons<>(t.value(), valueLeft, valueRight, t.left(), t.right(), middle, right);
}
else
result = new ThreeCons<>(valueLeft, valueRight, t, middle, right);
}
else if (cmpRight > 0)
{
TwoThreeTree<T> t = right.putr(x);
if (t.isTransient())
{
t = t.split();
result = new FourCons<>(valueLeft, valueRight, t.value(), left, middle, t.left(), t.right());
}
else
result = new ThreeCons<>(valueLeft, valueRight, left, middle, t);
}
else
{
TwoThreeTree<T> t = middle.putr(x);
if (t.isTransient())
{
t = t.split();
result = new FourCons<>(valueLeft, t.value(), valueRight, left, t.left(), t.right(), right);
}
else
result = new ThreeCons<>(valueLeft, valueRight, left, t, right);
}
}
return result;
}
...
6/1/16 Algoritmos e Estruturas de Dados 38
Classe FourCons<T>, split e isTransient
A funo split simples: o resultado uma
rvore binria de rvores binrias:
public TwoCons<T> split()
{
TwoCons<T> newLeft = new TwoCons<>(valueLeft, left, middleLeft);
TwoCons<T> newRight = new TwoCons<>(valueRight, middleRight, right);
return new TwoCons<>(valueMiddle, newLeft, newRight);
}
Lio n. 26
rvores red-black
rvores red-black
rvores dois-trs.
rvores red-black imutveis.
Inserir 81.
Inserir 30.
Inserir 70.
Inserir
72
O n 65+66 partiu-se
o o 66 subiu.
this.value = value;
this.left = left;
this.right = right;
this.size = 1 + left.size() + right.size();
assert invariant();
}
...
6/1/16 Algoritmos e Estruturas de Dados 15
Invariante das rvores pretas
Como de costume, anlogo pr-condio
do construtor:
public boolean invariant()
{
return left.invariant() && right.invariant()
&& (left.isEmpty() || value.compareTo(left.value()) > 0)
&& (right.isEmpty() || value.compareTo(right.value()) < 0)
&& (right.isEmpty() || right.isBlack())
&& (!left.isEmpty() || right.isEmpty());
}
if (cmp < 0)
{ Este parte corresponde a
RedBlackTree<T> t = left.putr(x);
inserir do lado esquerdo. Para
if (t.isTransient())
o lado direito anlogo.
{
t = t.split();
result = ThreeCons(t.value(), value, t.left(), t.right(), right);
}
else
result = new BlackTree<>(value, t, right);
}
else
...
// Remember: this is a black node: if the left subtree is empty, the right subtree must be empty
assert (!left.isEmpty() || right.isEmpty());
if (cmp < 0)
{
RedBlackTree<T> t = left.putr(x);
if (t.isTransient())
{
t = t.split();
result = ThreeCons(t.value(), value, t.left(), t.right(), right);
}
else
result = new BlackTree<>(value, t, right);
}
else
{
RedBlackTree<T> t = right.putr(x);
this.value = value;
this.left = left;
this.right = right;
this.size = 1 + left.size() + right.size();
assert invariant();
}
...
6/1/16 Algoritmos e Estruturas de Dados 33
rvores castanhas, split e isTransient
Tal como na classe FourCons, as nicas operaes
interessantes so split e isTransient.
Ambas so anlogas s da classe FourCons
A funo split constri rvore uma preta com
subrvores pretas:
protected BlackTree<T> split()
{
BlackTree<T> newLeft = new BlackTree<>(valueLeft, left, middleLeft);
BlackTree<T> newRight = new BlackTree<>(valueRight, middleRight, right);
return new BlackTree<>(valueMiddle, newLeft, newRight);
}
Lio n. 27
Grafos e buscas em grafos
Grafos
Grafos em programao.
Grafos dirigidos e no dirigidos.
Grafos pesados.
Busca em largura.
Busca em profundidade.
Joo Rute
Lus
3
1 3
2
Vera Ana
@SuppressWarnings("unchecked")
public Graph(int nVertices)
{
this.nVertices = nVertices;
edges = new Bag<>();
adj = (Bag<Edge>[]) new Bag[nVertices];
for (int i = 0; i < nVertices; i++)
adj[i] = new Bag<Edge>();
}
... De incio, fica tudo vazio.
}
Lio n. 28
Grafos: Prim e Dijkstra
Grafos: Prim e Dijkstra
Conectividade.
rvore de cobertura mnima.
Caminho mais curto.
ConnectedComponents(Graph g)
{
Os clculos fazem-se no
...
}
construtor.
public MinimumSpanningTree(Graph g)
{
assert new ConnectedComponents(g).count == 1;
this.g = g;
}