Estruturas de Dados - Giga Mundo

Propaganda
http://www.computacao.gigamundo.com
ESTRUTURA DE DADOS I
Christiano Lima Santos
http://www.computacao.gigamundo.com
Tipos de Dados e
Tipos Abstratos de Dados
(Aula 1)
Christiano Lima Santos
http://www.computacao.gigamundo.com
Sumário




Motivação
Tipos de Dados
Operações
Tipos Primitivos ou
Escalares
–
–
–
–
–
Tipos Inteiros
Tipos Reais
Tipos Lógicos
Tipo Caracter
Funções Para
Conversão

Tipos Coleções ou
Não-Escalares
–
–
–



Tipo Vetor
Tipo Registro
Tipo Conjunto
Tipos Abstratos de
Dados
Alocação de Memória
Vantagens e
Desvantagens da
Alocação Dinâmica
http://www.computacao.gigamundo.com
Motivação

Por que estudar os tipos de dados?

Duas são as principais preocupações em um
projeto de software
–
–
Os procedimentos a serem executados;
Os dados sobre os quais os procedimentos
atuam;
http://www.computacao.gigamundo.com
Motivação

“Estruturas de Dados” busca descrever
modelos de estruturas de dados e
procedimentos
–
Exemplos: Arrays, Registros, Listas, Pilhas, Filas
e Árvores, etc.
http://www.computacao.gigamundo.com
Motivação

Os tipos de dados e operações determinam
as estruturas de dados
–
Exemplo: em uma pilha ou fila você possui
operações push e pop para colocar e retirar
elementos dela;

A forma como os dados são inseridos ou removidos é
que difere uma estrutura da outra!
http://www.computacao.gigamundo.com
Tipos de Dados

Define a forma como um dado deve ser armazenado
ou recuperado, bem como os possíveis valores que
ele pode assumir ou as operações que podem ser
efetuadas sobre os mesmos
–
Exemplo em Pascal:


integer permite valores inteiros e operações de adição,
multiplicação, subtração e divisão;
string permite valores literais e operações de concatenação;
http://www.computacao.gigamundo.com
Tipos de Dados

Primitivos, derivados ou coleções;
–

Os principais tipos primitivos são: inteiro, real,
lógico, caracter, ponteiro;
Estáticos ou dinâmicos (instanciados em
tempo de execução);
http://www.computacao.gigamundo.com
Operações

Um conjunto de instruções a fim de manipular um
determinado tipo de dado a fim algum objetivo;
–
–
–
–
–
–
Criação (declaração)
Percurso
Busca
Alteração
Retirada
Inserção (em tipos dinâmicos)
http://www.computacao.gigamundo.com
Tipos Primitivos ou Escalares

Inteiro (integer, longint, etc.);

Real (real, double, etc.);

Lógico (boolean);

Caracter (char);
http://www.computacao.gigamundo.com
Tipos Inteiros

Operações numéricas contidas no conjunto
dos números inteiros:
–

Soma, subtração, multiplicação, divisão inteira,
resto da divisão;
Permitem comparações de igualdade e/ou
de desigualdade;
http://www.computacao.gigamundo.com
Tipos Reais

Satisfaz as operações e comparações
possíveis com tipos inteiros;

Operações numéricas contidas no conjunto
dos números reais:
–
Soma, subtração, multiplicação, divisão;
http://www.computacao.gigamundo.com
Tipos Lógicos

Permite operações lógicas (booleanas):
–

E, OU, NÃO;
Deve-se ter muito cuidado na construção de
expressões lógicas
–
Quanto maiores elas são, maiores as chances de
cometermos equívocos.
http://www.computacao.gigamundo.com
Tipo Caracter

Permite a representação de um único caracter;

Operações de igualdade e desigualdade;

Por ser armazenado internamente como um valor
inteiro, podemos fazer um “casting” e efetuar outras
operações.
http://www.computacao.gigamundo.com
Funções para conversão

De real para inteiro:
–

De caracter para inteiro:
–

Ord;
De inteiro para caracter:
–

Trunc, Floor, Ceil, Round;
Char;
Obs: Dependendo de quais os tipos/classes
envolvidos, podemos efetuar “typecasting”;
http://www.computacao.gigamundo.com
Tipos Coleções ou Não-Escalares

Vetor;

Registro;

Conjunto.
http://www.computacao.gigamundo.com
Tipo Vetor

Coleção de dados homogênea indexada que
pode ser acessada por meio de um índice
numérico;

var v = array [1..5] of integer;

v[3];
http://www.computacao.gigamundo.com
Tipo Registro

Coleção de dados heterogênea cujas informações
podem ser acessadas por meio de um campo;

var r = record
c1: integer;
c2: boolean;
end;

r.c1;
http://www.computacao.gigamundo.com
Tipo Conjunto

Coleção de objetos (ou informações)
correlatos que podem estar presentes ou
não em um dado momento;

var c = set of (V1, V2, V3);

c := [V1, V2];
V1 in c;

http://www.computacao.gigamundo.com
Tipos Abstratos de Dados

Segundo a Wikipédia:
–

Especificação de um conjunto de dados e
operações que podem ser executadas sobre
esses dados;
Exemplo:
–
Quando usamos arrays e registros para criar uma
estrutura de dados em vez de usar variáveis de
tipos primitivos.
http://www.computacao.gigamundo.com
Tipos Abstratos de Dados

Vetores, registros e conjuntos são
interessantes...
–
... Mas há um problema, são estáticos!

O que acontece se eu tiver um vetor de 5
posições e precisar de outras 1000?

E se meu vetor tiver 100000 posições e eu
somente uso 5, isso é bom?
http://www.computacao.gigamundo.com
Alocação de Memória

Alocação estática  Variável alocada ocupa
espaço fixo e contíguo na memória;

Alocação dinâmica  Variável alocada
ocupa espaço variável e é criada segundo a
necessidade do programa.
http://www.computacao.gigamundo.com
Vantagens e Desvantagens da
Alocação Dinâmica

Se alocamos dinamicamente, podemos aumentar e
diminuir o tamanho de nossa estrutura quando
quisermos!

Entretanto, necessitaremos de mais algumas
operações para buscar, inserir e/ou remover
informações;

Além disso, um array (estático) de vinte posições
geralmente ocupa menos espaço que uma lista
cujos elementos foram criados um a um
dinamicamente.
http://www.computacao.gigamundo.com
Referências Bibliográficas

[Não foram definidas]
http://www.computacao.gigamundo.com
Matrizes
(Aula 2)
Christiano Lima Santos
http://www.computacao.gigamundo.com
Sumário

Definição e Representação de Matrizes

Compactação de Matrizes
–
–
–
Matrizes Diagonais
Matrizes Triangulares
Matrizes Esparsas
http://www.computacao.gigamundo.com
Definição e Representação de Matrizes

Na Matemática, uma matriz pode ser
considerada um conjunto de informações
numéricas que podem ser referenciadas por
meio de dois parâmetros, comumente
chamados linha e coluna;
A =
1
2
0
2
0
1
3
3
2
4
1
5
http://www.computacao.gigamundo.com
Definição e Representação de Matrizes

Na Computação, podemos representar as
matrizes matemáticas por meio de estruturas
conhecidas como vetores ou arrays, onde
cada posição/valor pode ser referenciada por
um ou mais parâmetros (dependendo da
quantidade de dimensões de nosso vetor);
var A = array [1..3, 1..4] of real;
http://www.computacao.gigamundo.com
Definição e Representação de Matrizes

Enquanto que na Matemática uma matriz possui
sempre duas dimensões, na Computação podemos
chamar qualquer vetor de matriz, podendo assim ter
uma ou mais dimensões;
–
Matrizes unidimensionais;
–
Matrizes bidimensionais;
–
Matrizes n-dimensionais.
http://www.computacao.gigamundo.com
Compactação de Matrizes

Quanto memória ocupa uma matriz 5000 x
5000 de reais?
–
–

Um valor real = 4 bytes;
Aproximadamente 100 MB!
E se somente alguns poucos elementos da
matriz fossem diferentes de zero,
poderíamos reduzir o tamanho dela?
http://www.computacao.gigamundo.com
Compactação de Matrizes

Como representar de forma compactada:
–
Matrizes Diagonais;
–
Matrizes Triangulares;
–
Matrizes Esparsas;
http://www.computacao.gigamundo.com
Matrizes Diagonais

Os elementos da diagonal de uma matriz
são: a[1,1], a[2,2], a[3,3], ... a[n,n];

Podemos armazená-los, então, em uma
matriz unidimensional de n elementos.
http://www.computacao.gigamundo.com
Matrizes Triangulares

Podem ser superior ou inferior;

Podemos armazenar todos os elementos da
parte triangular em uma matriz
unidimensional de m elementos (inclui os
elementos da diagonal).
http://www.computacao.gigamundo.com
Matrizes Esparsas

Podem ser n-dimensionais;

Podemos armazenar somente os elementos
diferentes de zero em uma matriz unidimensional;

Problemas:
–
Como saber qual o índice de cada elemento na matriz?

–
Armazenar também o índice (tupla índice-valor);
E se um dos elementos for alterado para um valor nãonulo?

Deve-se reservar algumas posições vazias para o caso de
incluir novos elementos.
http://www.computacao.gigamundo.com
Exercícios


De volta às aulas? De volta aos jogos. 
Vamos criar um simulador de exploração espacial (modo texto,
claro)! Crie um universo que possa ser “navegado
tridimensionalmente” por meio da indicação de três
coordenadas X, Y e Z, onde o jogador precisa pilotar uma nave
até um dos planetas existentes.
–
–
–
–
–
–
O sistema de coordenadas de nosso “universo” vai de 0 a 4100
(para cada coordenada);
Temos um total de 100 planetas no espaço;
Para facilitar para o jogador, cada vez que ele indicar as
coordenadas, dizer quão longe ele está do planeta mais próximo;
O jogo encerra quando ele encontrar um dos planetas;
Os planetas são criados em posições aleatórias a cada vez que é
gerada uma nova partida;
E há um total de combustível para o jogador, o qual é consumido
de acordo com a distância percorrida!
http://www.computacao.gigamundo.com
Referências Bibliográficas

VELOSO, Paulo, SANTOS, Clésio,
AZEREDO, Paulo, FURTADO, Antônio,
Estruturas de Dados, Editora Campus Ltda
http://www.computacao.gigamundo.com
Recursividade
(Aula 3)
Christiano Lima Santos
http://www.computacao.gigamundo.com
Sumário





Definição de Recursão
Exemplo de Recursão
Recursão versus Iteração
Observações
Referências Bibliográficas
http://www.computacao.gigamundo.com
Definição de Recursão

Possibilidade de um objeto buscar definir-se
em função dele próprio;

Na Computação, um método é recursivo
quando ele invoca a si próprio a fim de
resolver um problema;
http://www.computacao.gigamundo.com
Definição de Recursão

Na Matemática, podemos encontrar
claramente a recursividade na resolução de
problemas por meio de recorrência;
–
Fatorial de um número;
–
Potenciação;
–
Seqüência de Fibonacci.
http://www.computacao.gigamundo.com
Exemplo de Recursão

Recorrência para encontrar um elemento da
seqüência de Fibonacci:
–
–
–
x1 = 1;
x2 = 1;
xn = xn-1 + xn-2;
http://www.computacao.gigamundo.com
Exemplo de Recursão

Função em Pascal:
function fibonacci(n: integer): integer;
begin
if (n < 1) then
fibonacci := 0
else if (n <= 2) then
fibonacci := 1
else
fibonacci := fibonacci(n-1) + fibonacci(n-2);
end;
http://www.computacao.gigamundo.com
Recursão versus Iteração

Iteração na definição de algoritmos – cada um dos
“passos”/repetições de um comando de repetição
(“loop”);

Diversos problemas resolvidos de forma recursiva
podem ser resolvidos de forma iterativa;
–
–
Chamadas recursivas precisam salvar o “contexto” atual da
execução do programa a fim de recuperá-lo após a
execução de cada chamada recursiva;
A implementação do cálculo do fatorial de forma iterativa,
por exemplo, consome menos memória e processamento.
http://www.computacao.gigamundo.com
Recursão versus Iteração

Por outro lado, há problemas que não podem ser
resolvidos de forma iterativa;
–

Percorrer uma árvore para encontrar um elemento, por
exemplo;
Além disso, recursão é muito útil na resolução de
diversos problemas que possam se beneficiar do
“dividir-para-conquistar”, exemplos:
–
–
–
Ordenação por meio de quicksort ou mergesort;
Programação dinâmica;
Diversas técnicas de busca em grafos.
http://www.computacao.gigamundo.com
Observações

Quando escrevendo funções recursivas, atente-se a:
–
–
–
Ordem em que cada comando deve aparecer dentro da
função – o resultado final pode ser totalmente diferente se
trocarmos duas linhas de código de lugar!
Definição de todos os casos base – se esquecermos de
definir um dos casos base e o algoritmo procurar por ele
em algum momento, ele não saberá que é um caso de
parada e continuará a sua execução, talvez
indefinidamente!
Cuidado com a passagem de parâmetros por valor ou por
referência.
http://www.computacao.gigamundo.com
Referências Bibliográficas

COSTA, Raimundo M, Programação
Pascal, 1995

WIKIPÉDIA, Recursividade em Ciência da
Computação, disponível em
http://pt.wikipedia.org/wiki/Recursividade_(ci
ência_da_computação)
http://www.computacao.gigamundo.com
Noções de Complexidade de
Algoritmos
(Aula 4)
Christiano Lima Santos
http://www.computacao.gigamundo.com
Sumário



Motivação
Alguns Mitos
Como Medir a Eficiência de
um Algoritmo?
–
–
–



Avaliação Empírica
Contagem do Número de
Operações Efetuadas
Determinação da
Complexidade Assintótica
de um Algoritmo
Notação O
Notação Ω
Notação θ

Principais Classes de
Comportamento Assintótico
–

Os “Três Casos”
–
–
–


Tabela Comparativa das
Principais Classes
O Melhor Caso
O Pior Caso
O Caso Médio
Calculando a
Complexidade para cada
Caso
Referências Bibliográficas
http://www.computacao.gigamundo.com
Motivação

Quais os dois recursos de hardware mais
importantes para a execução de um
algoritmo?
–
–

Tempo de processamento;
Quantidade de memória consumida;
Devemos, então, observar quanto de cada
recurso nossos algoritmos consomem;
–
Temos que medir quanto de cada recurso nossos
programas utilizam!
http://www.computacao.gigamundo.com
Motivação

Um exemplo bem simples é o caso de dois
programas que precisam fazer a ordenação
de um grande conjunto de dados:
–
–
–
Cada qual deles pode usar uma abordagem bem
diferente do outro;
Desta forma, cada qual pode resolver o problema
com mais ou menos tempo, ocupando mais ou
menos memória;
Como exímios Cientistas da Computação,
buscamos sempre compreender e trabalhar com
a melhor solução possível!
http://www.computacao.gigamundo.com
Alguns Mitos

Basta um computador mais rápido para resolver o
problema;
–

Pena que até mesmo um grande cluster com dezenas de
computadores não conseguem resolver eficientemente
alguns problemas somente por “força bruta”;
Ninguém efetua cálculo de complexidade ou busca
de solução mais eficiente em um sistema!
–
É, se você considerar somente os sistemas do tipo
“controle de locadora”, pois sistemas de tempo real,
simulações físicas, sistemas para cálculos estatísticos e
estimativas razoavelmente pesadas e tantos outros
precisam!
http://www.computacao.gigamundo.com
Alguns Mitos

Por que eu tenho que aprender sobre isso?
Eu posso simplesmente contratar alguém!
–
Pois é, que tal alguém da área de Computação?
Ei, esse alguém é você!
http://www.computacao.gigamundo.com
Como Medir a Eficiência de um
Algoritmo?

Avaliação empírica (medir o tempo de
execução);

Contagem do número de operações
efetuadas;

Determinação da complexidade assintótica
de um algoritmo;
http://www.computacao.gigamundo.com
Avaliação Empírica

Experimento 1: Verificar o tempo que dois programas
levam para efetuar uma busca em um array e recuperar
um dado;
–
–

Primeiro programa: 750 ns;
Segundo programa: 600 ns;
Qual programa é mais eficiente?
–
–
–
E se o primeiro foi executado em um core duo de 2,4 GHz
cada, e o segundo em um 486 DX2?
E se ambos foram executados na mesma máquina, mas o
segundo executou em paralelo com algum outro programa?
Somente por avaliação empírica, conseguimos ter certeza de
qual o programa mais eficiente?
http://www.computacao.gigamundo.com
Considerações sobre a Avaliação
Empírica

Em meu supercomputador o programa “rodou” normal...
–

Programas podem possuir “casos especiais” para alguns tipos
de casos
–

... Mas nos computadores do cliente não!
Deve-se então aumentar o número de casos de testes tentando
cobrir o maior número possível de situações;
Em uma dada linguagem, um programa pode ser mais eficiente
do que quando implementado em outra linguagem;
–
Não estamos analisando o algoritmo em si, mas somente o
programa!
http://www.computacao.gigamundo.com
Contagem do Número de Operações
Efetuadas

Experimento 2: Dado o algoritmo abaixo, vamos contar
quantas operações são necessárias para calcular fatorial(5):
function fatorial (n: integer): longint;
var f, i: integer;
begin
if (n < 0) then
f := -1
else
begin
f := 1;
for i := 1 to n do
f := f*i;
end;
fatorial := f;
end;
http://www.computacao.gigamundo.com
Contagem do Número de Operações
Efetuadas

No algoritmo anterior:
–
–
–
–

fatorial(1)  5 operações;
fatorial(5)  13 operações;
fatorial(10)  23 operações;
fatorial(n)  2*n + 3;
Perceba que para calcular o fatorial de um
número N qualquer, vamos executar 2*N
operações, ou seja, um número de
operações diretamente proporcional;
http://www.computacao.gigamundo.com
Considerações do Número de
Operações Efetuadas

Em Computação, geralmente não nos preocupamos com a
eficiência do algoritmo quando tratando poucos elementos
–
–

Se são poucos, por pior que nosso algoritmo seja, provavelmente
ele executará rápido e sem ocupar muito espaço!
2*n + 3 operações parecem piores que n2 operações para n = 0, 1
ou 2;
Entretanto, quanto maior o número de elementos ou o valor do
dado de entrada...
–
–
Para n = 1.000, 2*n + 3 é 2003;
Mas e se nosso algoritmo executasse n2 operações? 1.000.000!
http://www.computacao.gigamundo.com
Determinação da Complexidade
Assintótica de um Algoritmo

Definição de Complexidade
–

Quantidade de "trabalho" necessária para a execução de
um algoritmo, expressa em função das operações
fundamentais, as quais variam de acordo com o algoritmo,
e em função do volume de dados;
Complexidade Assintótica
–
–
Trata-se de uma função que expressa a relação entre o
volume de dados ( n ) e o tempo ( t ) necessário para o
processamento dos mesmos;
No algoritmo do experimento 2, poderíamos dizer que:
f(n) = 2*n + 3
http://www.computacao.gigamundo.com
Determinação da Complexidade
Assintótica de um Algoritmo

Notações O (“O Grande”), Ω (Omega) e θ
(Theta);

Obs: Funções assintoticamente nãonegativas;
http://www.computacao.gigamundo.com
Notação O

Dadas duas funções f e g, diz-se que f está na
ordem O de g ( f = O(g) ) se:
f(n) ≤ c * g(n)
Para algum c positivo e para todo n suficientemente
grande.
g(n) é, então, o limite assintótico superior (upper
bound) de f(n)

Exemplos:
3x2 + 5 = O ( x2 )
x3/2 = O ( x3)
1 + 2 + 3 + ... + x = O ( x2 )
http://www.computacao.gigamundo.com
Notação Ω

Dadas duas funções f e g, diz-se que f está na
ordem O de g ( f = Ω(g) ) se:
f(n) ≥ c * g(n)
Para algum c positivo e para todo n suficientemente
grande.
g(n) é, então, o limite assintótico inferior (lower
bound) de f(n)

Exemplos:
3x3 + 5 = Ω ( x2 )
x3/2 = Ω ( x3/3)
http://www.computacao.gigamundo.com
Notação θ

Dadas duas funções f e g, diz-se que f está
na ordem O de g ( f = θ(g) ) se:
f(n) ≥ c1 * g(n) e f(n) ≥ c2 * g(n)
Para algum c1 e c2 positivos e para todo n
suficientemente grande.

Exemplo:
3x3+ 5 = θ ( x3 )
http://www.computacao.gigamundo.com
Principais Classes de Comportamento
Assintótico




O (1) : O uso do algoritmo independe do tamanho de n.
Neste caso as instruções do algoritmo são executadas
um número fixo de vezes;
O (log n): ocorre tipicamente em algoritmos que
resolvem um problema transformando-o em problemas
menores;
O (n): linear – Um conjunto de operações de tamanho
constante é aplicado a cada elemento da entrada;
O (n log n): Ocorre em algoritmos que resolvem um
problema quebrando-o em problemas menores,
resolvendo cada um deles independentemente e depois
juntando as soluções;
http://www.computacao.gigamundo.com
Principais Classes de Comportamento
Assintótico



O (n2): quadrático. Algoritmos desta ordem de
complexidade ocorrem quando os itens de dados são
processados aos pares, muitas vezes em um loop
dentro de outro. Úteis para resolver problemas de
tamanhos relativamente pequenos;
O (nk): polinomial – OK para k pequeno;
O (kn), O (n!), O (nn): exponencial – Geralmente não são
úteis sob o ponto de vista prático. Eles ocorrem na
solução de problemas quando se usa força bruta para
resolvê-los.
http://www.computacao.gigamundo.com
Tabela Comparativa das Principais
Classes
CLASSE NOTAÇÂO O
constante
O(1)
logaritmico
O(lg n)
linear
O(n)
O(n lg n)
O(n lg n)
quadrático
O(n²)
cúbico
O(n³)
exponencial
O(2^n)
n=10
1
3,32
10
33,2
100
1000
1024
n=100
1
6,64
100
664
10000
1000000
10^30
n=1000
1
9,97
1000
9970
1000000
10^9
10^301
... n=1000000
1
19,93
1000000
199,3*10^5
10^12
10^18
10^301030
http://www.computacao.gigamundo.com
Os “Três Casos”

Para qualquer algoritmo, sempre há situações em
que ele resolverá de forma muito rápida e outras em
que “nem tanto”;
–
Exemplo: ordenação dos dados de um vetor



Se ele já estiver ordenado? Ótimo!
E se os dados estiverem em ordem inversa? Dependendo do
algoritmo, pode ser muito ruim;
Desta forma, para determinar a eficiência de um
algoritmo, precisamos conhecer a sua complexidade
para o melhor caso, o pior caso e o caso médio.
http://www.computacao.gigamundo.com
Melhor Caso

Caso para o qual o algoritmo executa da
melhor forma possível:
–
–
–
Menor número de instruções;
Menor tempo de processamento necessário;
Menor consumo de memória.
http://www.computacao.gigamundo.com
Pior Caso

Ao contrário do melhor caso, este é o caso
para o qual o algoritmo executa da pior
forma possível;
http://www.computacao.gigamundo.com
Caso Médio

A complexidade para o caso médio é dada
por meio de cálculo tempo médio esperado
para a resolução de um problema qualquer,
independente de como os dados estão (se
ordenados ou não, etc);
http://www.computacao.gigamundo.com
Calculando a Complexidade Para Cada
Caso

Geralmente, é necessário conhecer qual o
volume de dados que atende a cada um dos
casos e, então, busca-se definir a função
matemática que expressa o número de
operações necessárias para cada caso;

No caso de algoritmos recursivos, deve-se
determinar primeiro a fórmula de recorrência
capaz de expressá-los e, então, “resolvê-la”.
http://www.computacao.gigamundo.com
Referências Bibliográficas

MADEIRA, Gonçalo, Complexidade
Computacional, disponível em
http://w3.ualg.pt/~hshah/algoritmos/aula8/Aula8.htm

SILVA, Elton, Análise Assintótica da
Complexidade de Algoritmos, disponível em
http://www.decom.ufop.br/prof/elton/cic210/cap2.pdf
http://www.computacao.gigamundo.com
Exercícios Sobre Matrizes,
Recursividade e Complexidade de
Algoritmos
(Aula 5)
Christiano Lima Santos
http://www.computacao.gigamundo.com
Primeiro Exercício

Implemente um programa capaz de armazenar e
recuperar dados de uma matriz triangular inferior;

Qual a ordem de complexidade desse algoritmo
para:
–
–
–

Armazenar n elementos;
Para recuperar um elemento qualquer, dada a sua posição
na matriz inicial;
Para buscar a posição de um elemento qualquer, dado o
valor do elemento;
Você consegue identificar quais são os casos pior,
médio e melhor?
http://www.computacao.gigamundo.com
Segundo Exercício

Implemente um programa que localiza uma
substring dentro de outra string;

Qual a ordem de complexidade desse algoritmo
para:
–
–

Encontrar uma letra em uma frase de tamanho N;
Encontrar uma palavra de tamanho K em uma frase de
tamanho N;
Você consegue identificar quais são os casos pior,
médio e melhor?
http://www.computacao.gigamundo.com
Terceiro Exercício

Implemente um programa que armazena os
telefones armazenados em ordem alfabética de
acordo com os nomes das pessoas seguindo a
seguinte “fórmula”:
–


Toda vez que for inserir um novo telefone, procura qual
será a posição correta dele e, para inseri-lo ali, move antes
todo mundo daquela posição em diante para uma após e,
então, copia seus dados para lá (inserção direta);
Qual a ordem de complexidade deste algoritmo?
Você consegue identificar quais são os casos pior,
médio e melhor?
http://www.computacao.gigamundo.com
Quarto exercício

Implemente a função de potenciação de
forma recursiva;

Qual a complexidade deste algoritmo?

Faça uma comparação das vantagens e
desvantagens desta implementação em
relação à iterativa.
http://www.computacao.gigamundo.com
Ponteiros e Alocação Dinâmica
(Aula 6)
Christiano Lima Santos
http://www.computacao.gigamundo.com
Sumário









Motivação;
Definição de ponteiro;
Tipos de ponteiro;
Apontando para um endereço nulo;
Apontando e recuperando uma variável;
Apontando e Invocando um Subprograma;
Alocação Dinâmica de Memória;
Alocando e desalocando memória;
Referências Bibliográficas.
http://www.computacao.gigamundo.com
Motivação

Por que estudar alocação dinâmica se podemos
criar todas as estruturas de forma estática?

O que acontece em um programa com alocação
estática quando precisamos de estruturas maiores
do que as que foram criadas?

Ponteiros e alocação dinâmica permite-nos criar
diversos Tipos Abstratos de Dados;
–
É fácil criá-los somente com alocação estática? Como
seria?
http://www.computacao.gigamundo.com
Definição de ponteiro

Tipo de variável que “aponta” para um outro
endereço de memória;

O conteúdo de uma variável ponteiro é o endereço
de memória para o qual está apontando;

Um ponteiro pode referenciar e “des-referenciar”;
http://www.computacao.gigamundo.com
Definição de ponteiro

Um ponteiro pode apontar para:
–
Uma área com informação (uma variável ou
conteúdo de uma variável);
–
Uma rotina (procedimento ou função);
–
Endereço nulo.
http://www.computacao.gigamundo.com
Tipos de Ponteiro

Tipado – irá interpretar o dado do endereço
referenciado segundo o seu tipo;
–
Declaração:


var p : ^integer;
Não-Tipado – não está associado a um tipo,
logo, é necessário fazer o typecasting da
informação referenciada a fim de acessá-la;
–
Declaração:

var p : Pointer;
http://www.computacao.gigamundo.com
Apontando para um endereço nulo

Em Pascal, nil representa um endereço nulo que
qualquer ponteiro pode apontar;
ponteiro := nil;
if ponteiro = nil then
writeln(‘Não está apontando’)
else
writeln(‘Está apontando para ’, ponteiro);
http://www.computacao.gigamundo.com
Apontando e Recuperando uma
variável
program ponteiro1;
uses crt;
var p: ^integer;
a: integer;
BEGIN
a := 12;
p := @a;
writeln(‘O endereço de a é: ’, p);
writeln(‘O valor de a é: ’, p^);
p^ := 6;
writeln(‘O novo valor de a é: ’, p^, ‘. Confirmando: ’, a);
readkey;
END.
http://www.computacao.gigamundo.com
Apontando e Invocando um
Subprograma
program ponteiro2;
uses crt;
var D: procedure(Arg: Byte);
procedure rotina1(Arg: Byte);
Begin
writeln('Rotina 1 recebeu ', Arg);
end;
procedure rotina2(Arg: Byte);
Begin
writeln('Rotina 2 recebeu ', Arg);
end;
BEGIN
D := @rotina2;
D(10); { Irá imprimir: 'Rotina 2 recebeu 10' }
END.
http://www.computacao.gigamundo.com
Alocação Dinâmica de Memória

É a criação (reserva) de um endereço de
memória para uma dada variável do tipo
ponteiro;

Geralmente, quando alocamos
dinamicamente um endereço de memória,
devemos desalocá-la (na alocação estática,
o compilador é encarregado disso).
http://www.computacao.gigamundo.com
Alocando e Desalocando Memória
program ponteiro3;
uses crt;
var p: ^integer;
BEGIN
new(p);
p^ := 12;
writeln(‘Endereço apontado: ’, p);
writeln(‘Valor armazenado: ’, p^);
readkey;
dispose(p);
END.
Não confunda nil com new!
http://www.computacao.gigamundo.com
Referências Bibliográficas

Blog de João Morais,
http://blog.joaomorais.com.br/2008/08/23/po
nteiros.html

http://www2.dc.ufscar.br/~bsi/materiais/ed/u7
.html
http://www.computacao.gigamundo.com
Listas
(Aula 7)
Christiano Lima Santos
http://www.computacao.gigamundo.com
Sumário



Definição de Lista
Características
Tipos de Implementação
–
–
Lista Seqüencial
Lista Encadeada ou Dinâmica



Outros Tipos de Listas
Implementação de uma Lista
Referências Bibliográficas
http://www.computacao.gigamundo.com
Definição de Lista

TAD que permite representação e
manipulação de seus elementos de forma
linear;

Também chamada lista linear;
L  e1, e2, ... , en;
http://www.computacao.gigamundo.com
Características

Uma coleção de dados homogênea;

Itens dispostos em seqüência;

Quantificável;

Ordenável;
http://www.computacao.gigamundo.com
Tipos de Implementação

Seqüencial

Encadeada ou Dinâmica
http://www.computacao.gigamundo.com
Lista Seqüencial

Os itens são armazenados em posição
contígua na memória;

Podem ser implementadas por meio de um
array!

O programa executa um determinado cálculo
para encontrar a posição na memória em
que se encontra o elemento ei;
http://www.computacao.gigamundo.com
Lista Encadeada ou Dinâmica


A lista cresce dinamicamente, isto é, cada novo
elemento é criado e inserido nela em tempo de
execução;
Se é criado em tempo de execução, precisamos
usar ponteiros... Onde estará o ponteiro para cada
elemento?
–

Cada elemento possui o ponteiro para o próximo elemento;
Listas podem ser encadeadas, duplamente
encadeadas ou n-uplamente encadeadas (só
depende de sua criatividade)!
http://www.computacao.gigamundo.com
Outros Tipos de Listas

Podemos precisar de listas que satisfaçam
certas restrições quanto à forma de
recuperar um elemento ou de inserção do
mesmo;
–
Pilhas;
–
Filas.
http://www.computacao.gigamundo.com
Implementação de uma Lista

Lista Seqüencial
var lista: array [1..N] of integer;

Lista Encadeada
type PNo = ^TNo;
TNo = record
valor: integer;
proximo: PNo;
end;
var lista: TNo;
http://www.computacao.gigamundo.com
Referências Bibliográficas

[Não foram definidas]
http://www.computacao.gigamundo.com
Buscas em Listas
(Aula 8)
Christiano Lima Santos
http://www.computacao.gigamundo.com
Sumário



Definição de Busca
Tipos de Busca
Busca Seqüencial

Implementação
Complexidade

–
–

Busca Binária
–
–
Implementação
Complexidade
Busca Interpolada
–
–

Implementação
Complexidade
Comparando os Três
Métodos
Referências
Bibliográficas
http://www.computacao.gigamundo.com
Definição de Busca

Operação de percurso de uma estrutura de
dados e recuperação de uma informação
baseado em algum campo-chave;

Recuperação de informações em uma lista é
uma operação importante e o tempo que
operações de inserção, remoção e busca
levam para serem processadas afetam
diretamente a eficiência de um algoritmo.
http://www.computacao.gigamundo.com
Tipos de Busca

Busca Seqüencial  baseia-se no percurso de
todos os elementos de uma lista de forma
seqüencial;

Busca Binária  baseia-se no percurso dos
elementos de uma lista levando em consideração o
valor de chave esperado e o valor encontrado;

Busca Interpolada  similar à busca binária,
introduz cálculo de próxima posição a ser verificada
levando em consideração os valores dos
“elementos-limite”.
http://www.computacao.gigamundo.com
Busca Seqüencial

“Se você não sabe por onde começar,
comece pelo começo”;

Não se conhece uma ordenação dentro da
lista;

Somos forçados a verificar um por um.
http://www.computacao.gigamundo.com
Busca Seqüencial - Implementação
function buscaSeq(lista: TLista; tamanho, chave: integer): integer;
var i : integer;
Begin
For i := 1 to tamanho do
If lista[i] = chave then
Begin
buscaSeq := i;
exit;
End;
buscaSeq := -1;
End;
http://www.computacao.gigamundo.com
Busca Seqüencial - Complexidade

Qual a complexidade para:
–
O melhor caso;
–
O pior caso;
–
O caso médio.
http://www.computacao.gigamundo.com
Busca Binária

Quando os elementos de uma lista estão
ordenados segundo um campo-chave,
podemos tirar proveito disso;
–
–
–
O primeiro elemento é o menor;
O último elemento é o maior;
O elemento do meio... é o do meio!
http://www.computacao.gigamundo.com
Busca Binária






Suponha uma lista com valores ordenados de forma crescente;
Dado um intervalo [A, B] (inicialmente, A é 1 e B é o tamanho da
lista), calculo um elemento X = floor((A + B) / 2);
Se lista[X] é o valor que procuro, retorno a posição / elemento
encontrado;
Senão, se lista[X] é maior que o valor que procuro, então devo
olhar o intervalo que possui os valores menores que lista[X], ou
seja, [A, X-1];
Senão, se lista[X] é menor que o valor que procuro, então devo
olhar o intervalo que possui os valores maiores que lista[X], ou
seja, [X+1, B];
Repito todo o processo até encontrar (ou não!) o elemento.
http://www.computacao.gigamundo.com
Busca Binária - Implementação
function buscaBin(lista: TLista; tamanho, chave: integer): integer;
var A, B, X: integer;
Begin
A := 1;
B := tamanho;
While (A <= B) do
Begin
X := floor( (A + B) / 2);
If lista[X] = chave then
Begin
buscaBin := X;
exit;
End
Else If lista[X] < chave then
A := X + 1
Else
B := X - 1;
End;
buscaBin := -1;
End;
http://www.computacao.gigamundo.com
Busca Binária - Complexidade

Qual a complexidade para:
–
O melhor caso;
–
O pior caso;
–
O caso médio.
http://www.computacao.gigamundo.com
Busca Interpolada

Similar à busca binária, leva em conta a
ordenação dos dados de uma lista;

Entretanto, em vez de “olhar” sempre o
elemento mediano, efetua um cálculo que
busca estimar onde o elemento desejado
deve estar.
http://www.computacao.gigamundo.com
Busca Interpolada

Se tenho uma lista ordenada crescente com
50 elementos, o primeiro é o 1 e o último é o
1000, onde provavelmente estará o 999?
–
Próximo do início;
–
No meio;
–
Próximo do fim.
http://www.computacao.gigamundo.com
Busca Interpolada

Basta mudar o cálculo do termo X:
X := 1 + floor((tamanho - 1)*(chave – lista[A])/(lista[B] –
lista[A]));
http://www.computacao.gigamundo.com
Busca Interpolada - Implementação
function buscaInterp(lista: TLista; tamanho, chave: integer): integer;
var A, B, X: integer;
Begin
A := 1;
B := tamanho;
While (A <= B) do
Begin
X := 1 + floor((tamanho - 1)*(chave – lista[A])/(lista[B] – lista[A]));
If lista[X] = chave then
Begin
buscaInterp := X;
exit;
End
Else If lista[X] < chave then
A := X + 1
Else
B := X - 1;
End;
buscaInterp := -1;
End;
http://www.computacao.gigamundo.com
Busca Interpolada - Complexidade

Qual a complexidade para:
–
O melhor caso;
–
O pior caso;
–
O caso médio.
http://www.computacao.gigamundo.com
Comparando os Três Métodos

Em que ocasiões o busca seqüencial é melhor?

O que é melhor: busca interpolada ou busca
binária?

E se na busca binária / interpolada
comparássemos também os valores dos
extremos com o valor da chave, melhoraríamos
a eficiência?
http://www.computacao.gigamundo.com
Referências Bibliográficas

[Não foram definidas]
http://www.computacao.gigamundo.com
Listas Encadeadas
(Aula 9)
Christiano Lima Santos
http://www.computacao.gigamundo.com
Sumário










Definição de Lista Encadeada
Listas Encadeadas Estáticas
Listas Encadeadas Dinâmicas
Listas Encadeadas Simples
Operações em Listas Encadeadas
Definindo nossa Lista Encadeada
Inserção na Lista Encadeada
Busca na Lista Encadeada
Remoção na Lista Encadeada
Referências Bibliográficas
http://www.computacao.gigamundo.com
Definição de Lista Encadeada

Toda lista linear onde cada elemento
(geralmente chamado nó) possui algum
apontador para o próximo elemento;
|

|
...
Esse encadeamento produz a estrutura
linear da lista.
|
http://www.computacao.gigamundo.com
Lista Encadeadas Estáticas



Alguns autores consideram
a possibilidade de listas
encadeadas criadas de
forma estática;
0
Exemplo de lista
encadeada não dinâmica;
O apontadores são
inteiros.
4
1
Carlos
5
2
Erica
-1
3
Beth
1
4
Ana
3
5
Davi
2
http://www.computacao.gigamundo.com
Listas Encadeadas Dinâmicas

Permitem a inserção de novos elementos
com menos restrições quanto à posição (não
precisa ser contígua) ou quantidade.
http://www.computacao.gigamundo.com
Listas Encadeadas Simples

Cada nó possui um único apontador para o próximo
nó;

Para fins de facilitar a inserção, alteração (quando
ordenada), remoção e busca pelo valor presente em
um nó qualquer da lista, podemos eleger um campo
(ou atributo) do nó para ser o campo-chave do
mesmo;

Podem ser implementadas com listas seqüenciais
ou dinâmicas.
http://www.computacao.gigamundo.com
Operações em Lista Encadeada

Criação;

Inserção;

Busca / Recuperação;

Remoção.
http://www.computacao.gigamundo.com
Definindo Nossa Lista Encadeada
(opção 1)
type PNo = ^TNo;
TNo = record
valor: integer;
proximo: PNo;
end;
TLista = PNo;
http://www.computacao.gigamundo.com
Definindo Nossa Lista Encadeada
(opção 2)
type PNo = ^TNo;
TNo = record
valor: integer;
proximo: PNo;
end;
TLista = record
primeiro: PNo;
ultimo: PNo;
tamanho: integer;
end;
http://www.computacao.gigamundo.com
Inserção na Lista Encadeada
//Inserção no fim da Lista
procedure inserirFim(var a: TLista; var v: integer);
var p, t: PNo;
Begin
new(p);
p^.valor := v;
p^.proximo := nil;
if a = nil then
a := p
else
begin
t := a;
while (t^.proximo <> nil) do
t := t^.proximo;
t^.proximo := p;
end;
end;
http://www.computacao.gigamundo.com
Inserção na Lista Encadeada
//Inserção no início da Lista
procedure inserirInicio(var a: TLista; var v: integer);
var p, t: PNo;
Begin
new(p);
p^.valor := v;
p^.proximo := a;
a := p;
end;
http://www.computacao.gigamundo.com
Inserção na Lista Encadeada
//Inserção ordenada
procedure inserirOrdenado(var a: TLista; var v: integer);
var p, t: PNo;
Begin
new(p);
p^.valor := v;
p^.proximo := nil;
if a = nil then
a := p
else if a^.valor >= v then
begin
p^.proximo := a;
a := p;
end
else
begin
t := a;
while ((t^.proximo <> nil) && ((t^.proximo^).valor < v)) do
t := t^.proximo;
if (t.proximo = nil) then
t^.proximo := p
else
begin
p^.proximo := t^.proximo;
t^.proximo := p;
end;
end;
end;
http://www.computacao.gigamundo.com
Busca na Lista Encadeada
//Busca Seqüencial
function buscaSeq(a: TLista; v: integer): PNo;
var t: PNo;
Begin
t := a;
while ((t <> nil) && (t^.valor <> v))
t := t^.proximo;
buscaSeq := t;
End;
http://www.computacao.gigamundo.com
Busca na Lista Encadeada

Em Listas Encadeadas Dinâmicas, Busca
Binária ou Interpolada, é possível? Há
vantagens em seu uso em relação à Busca
Seqüencial?
http://www.computacao.gigamundo.com
Remoção na Lista Encadeada

Como seria a remoção de um elemento em uma lista
encadeada? E a remoção de todos os elementos?

No caso de remoção de um elemento (e), tomar o cuidado para
garantir que o anterior (t) dele passe a apontar para o sucessor
dele (t.proximo := e.proximo);

No caso de remoção de todos os elementos, a idéia é percorrer
todos os elementos da lista, removendo-os (dispose);

Cuidado para não remover um elemento antes de guardar a
referência para o próximo  como saber quem é o próximo
elemento de um elemento que não mais existe?
http://www.computacao.gigamundo.com
Referências Bibliográficas

[Não foram definidas]
http://www.computacao.gigamundo.com
Pilhas & Filas
(Aula 10)
Christiano Lima Santos
http://www.computacao.gigamundo.com
Sumário

Definição de Pilha
–
–

Definição de Fila
–
–


Exemplo de Pilha no Mundo Real
Implementação de uma Pilha
Exemplo de Fila no Mundo Real
Implementação de uma Fila
Exercícios
Referências Bibliográficas
http://www.computacao.gigamundo.com
Definição de Pilha

Toda lista linear onde o último elemento a
entrar é o primeiro a sair (ou o primeiro a
entrar é o último a sair, FILO);

Para satisfazer esta condição, basta que a
inserção e remoção sejam feitas na mesma
extremidade da lista (head);
–
Obviamente, não é necessário ordenar;
http://www.computacao.gigamundo.com
Exemplo de Pilha no Mundo Real

Um baralho de cartas, colocadas uma a uma
sobre a mesa, umas sobre as outras,
formando um monte;

A carta mais ao topo (a primeira a ser
removida) foi a última a ser colocada sobre o
monte;
http://www.computacao.gigamundo.com
Implementação de uma Pilha
type PNo = ^TNo;
TNo = record
valor: integer;
proximo: PNo;
end;
TPilha = record
head: PNo;
end;
function push(var pilha: TPilha; valor: integer): Boolean;
function pop(var pilha: TPilha): integer;
http://www.computacao.gigamundo.com
Implementação de uma Pilha

Push: Nada mais é que o nosso método
inserirInicio!

Pop: Como devemos inserir e remover da
mesma extremidade da lista, devemos então
remover do início, devolvendo então o valor
daquele elemento.
http://www.computacao.gigamundo.com
Implementando o Método Push
function push(var pilha: TPilha; valor: integer): Boolean;
var p, t: PNo;
Begin
new(p);
p^.valor := v;
p^.proximo := pilha.head;
pilha.head := p;
push := true;
end;
http://www.computacao.gigamundo.com
Implementando o Método Pop
function pop(var pilha: TPilha): integer;
var p: PNo;
Begin
if (pilha.head = nil) then
pop := -1
else
begin
p := pilha.head;
pilha.head := pilha.head^.proximo;
pop := p^.valor;
dispose(p);
end;
end;
http://www.computacao.gigamundo.com
Definição de Fila

Toda lista linear onde o primeiro elemento a
entrar é o primeiro a sair (FIFO);

Para satisfazer esta condição, basta que a
inserção seja feita em uma extremidade (tail)
da lista e a remoção seja feita na outra
extremidade (head);
–
Obviamente, também não é necessário ordenar;
http://www.computacao.gigamundo.com
Exemplo de Fila no Mundo Real

Muitas coisas são ordenadas por fila;

A fila de um banco por exemplo;
–

... e a fila do RESUN?
Muitos processos e requisições em um
computador são organizados e gerenciados
por meio de filas.
http://www.computacao.gigamundo.com
Implementação de uma Fila
type PNo = ^TNo;
TNo = record
valor: integer;
proximo: PNo;
end;
TFila = record
head: PNo;
tail: PNo;
end;
function push(var pilha: TFila; valor: integer): Boolean;
function pop(var pilha: TFila): integer;
http://www.computacao.gigamundo.com
Implementação de uma Fila

Push: Apesar de inserir no final, nós não
precisaremos percorrer toda a fila para
inserir no fim;
–

Nós mantemos um ponteiro para o último
elemento!
Pop: A remoção continua sendo feita na
cabeça, o que facilita muito as coisas.
http://www.computacao.gigamundo.com
Implementando o Método Push
function push(var fila: TFila; valor: integer): Boolean;
var p, t: PNo;
Begin
new(p);
p^.valor := v;
p^.proximo := nil;
if (fila.tail = nil) then
fila.head := p
else
fila.tail^.proximo := p;
fila.tail := p;
push := true;
end;
http://www.computacao.gigamundo.com
Implementando o Método Pop
function pop(var fila: TFila): integer;
var p: PNo;
Begin
if (fila^.head = nil) then
pop := -1;
else
begin
p := fila;
fila^.head := fila^.head^.proximo;
if (fila^.head = nil) then
fila^.tail := nil;
pop := p^.valor;
dispose(p);
end;
end;
http://www.computacao.gigamundo.com
Exercício





Crie um jogo para ser disputado por duas pessoas com dois
“modos” (o modo pilha e o modo fila) e a opção de sair;
Primeiro, Deve-se escolher quantos números serão
embaralhados e ocultos e qual o modo de organização dos
mesmos;
Em segundo lugar, o jogo deverá ir inserindo cada número (0
<= K <= 9) na pilha/fila, mostrando um de cada vez na tela
(lembre-se de limpar ela por inteiro a cada número mostrado);
Após isso, os jogadores devem alternar-se tentando adivinhar
qual o próximo número a ser removido do jogo. Ganha quem
não errar. Caso acabem todos os números, declarar empate;
Quando os jogadores escolherem sair, mostrar o placar final e
encerrar o jogo.
http://www.computacao.gigamundo.com
Referências Bibliográficas
http://www.computacao.gigamundo.com
Outros Tipos de Listas
(Aula 11)
Christiano Lima Santos
http://www.computacao.gigamundo.com
Sumário

Lista Duplamente Encadeada
–
–

Lista Circular
–
–


Declaração
Operações
Declaração
Operações
Exercícios
Referências Bibliográficas
http://www.computacao.gigamundo.com
Lista Duplamente Encadeada

Uma estrutura de dados linear que se utiliza de dois
ponteiros (um apontando o elemento anterior e outro
o posterior) a fim de permitir percorrer a mesma não
somente avançando, como também recuando;
I
|
|
|
...
|
http://www.computacao.gigamundo.com
Lista Duplamente Encadeada

Vantagem:
–

Facilidades na hora de procurar um elemento,
principalmente se o mesmo estiver antes da atual
posição pesquisada;
Desvantagem:
–
Nas inserções, remoções e alterações, isso
significa mais ponteiros para atualizar, o que
pode levar programadores não muito bons a
cometer falhas (o que não é o caso de vocês!).
http://www.computacao.gigamundo.com
Declaração de uma Lista Duplamente
Encadeada (opção 1)
type PNo = ^TNo;
TNo = record
valor: integer;
anterior: PNo;
proximo: PNo;
end;
TLista = PNo;
http://www.computacao.gigamundo.com
Declaração de uma Lista Duplamente
Encadeada (opção 2)
type PNo = ^TNo;
TNo = record
valor: integer;
anterior: PNo;
proximo: PNo;
end;
TLista = record
primeiro: PNo;
ultimo: PNo;
tamanho: integer;
end;
http://www.computacao.gigamundo.com
Operações em Lista Duplamente
Encadeada

Operações Básicas:
–
–
–
–

Criação;
Inserção;
Busca / Recuperação;
Remoção;
Como seriam essas operações em uma Lista
DE se ela não estiver ordenada? E se estiver
ordenada?
http://www.computacao.gigamundo.com
Lista Circular

Estrutura de dados linear em que o último elemento aponta
para o primeiro;

Lista em que todo elemento possui um “sucessor” (o sucessor
do último é o primeiro elemento);

Pode-se adotar encadeamento simples, duplo ou outro
qualquer;
http://www.computacao.gigamundo.com
Lista Circular

Observações:
–
Não há mais elementos apontando para nil, logo
não podemos mais identificar o último elemento
desta forma!

–
Mas podemos parar quando percebermos que o
próximo é o “primeiro elemento” (apontado pela lista
circular);
Podemos até mesmo deslocar a “cabeça” da lista
sem que se perca a referência para nenhum dos
elementos;

Mas isso não é interessante caso a lista seja ordenada.
http://www.computacao.gigamundo.com
Declaração de uma Lista Circular
(opção 1)
type PNo = ^TNo;
TNo = record
valor: integer;
proximo: PNo;
end;
TLista = PNo;
http://www.computacao.gigamundo.com
Declaração de uma Lista Circular
(opção 2)
type PNo = ^TNo;
TNo = record
valor: integer;
proximo: PNo;
end;
TLista = record
primeiro: PNo;
tamanho: integer;
end;
http://www.computacao.gigamundo.com
Operações em Lista Circular

Operações Básicas:
–
–
–
–

Criação;
Inserção;
Busca / Recuperação;
Remoção;
Como seriam essas operações em uma Lista
Circular se ela não estiver ordenada? E se
estiver ordenada?
http://www.computacao.gigamundo.com
Exercícios

Implemente as operações de inserção,
busca, alteração e remoção para:
–
Lista duplamente encadeada não-ordenada;
–
Lista duplamente encadeada ordenada;
–
Lista circular.
http://www.computacao.gigamundo.com
Referências Bibliográficas

[Não foram definidas]
http://www.computacao.gigamundo.com
Árvores
(Aula 12)
Christiano Lima Santos
http://www.computacao.gigamundo.com
Sumário









Definição de Árvore
Representação Gráfica
Classificação das Árvores
Declaração de uma Árvore
N-ária
Declaração de uma Árvore
Não N-ária
Nível de um Nó
Altura ou Profundidade de
uma Árvore
Percurso de uma Árvore
Inserção em uma Árvore








Remoção em uma Árvore
Árvores Binárias
Árvores Binárias de Busca
Inserção em uma Árvore
Binária de Busca
Busca em uma Árvore
Binária de Busca
Deleção em uma Árvore
Binária de Busca
Comparações entre Ordens
de Complexidade
Referências Bibliográficas
http://www.computacao.gigamundo.com
Definição de Árvore

Estrutura de dados não linear;

Um grafo totalmente conexo e acíclico;

Analogia a uma árvore (reino vegetal):
–
–
–
Raiz;
Folhas;
“galhos” ou sub-árvores – conceito de poda.
http://www.computacao.gigamundo.com
Representação Gráfica
http://www.computacao.gigamundo.com
Classificação das Árvores

Uma árvore pode ser classificada de
diversas formas diferentes, uma delas é pelo
número máximo de nós-filhos que cada nópai pode ter:
–
–
–
–
–
Binária (dois nós);
Ternária (três nós);
Quaternária (quatro nós);
N-ária (N nós);
Não N-ária (quando não conhecemos ou não há
um número máximo de nós-filhos para cada nópai).
http://www.computacao.gigamundo.com
Declaração de uma Árvore N-ária
const N = 2;
type
PNo = ^Tno;
TNo = record
valor: integer;
filhos: array [1..N]
of PNo;
end;
TArvore = PNo;
http://www.computacao.gigamundo.com
Declaração de uma Árvore Não N-ária
type
PNo = ^TNo;
TNo = record
valor: integer;
irmao: PNo;
filho: PNo;
end;
TArvore = PNo;
http://www.computacao.gigamundo.com
Nível de um Nó

Refere-se à distância do mesmo até a raiz;
0
1
2
3
http://www.computacao.gigamundo.com
Altura ou Profundidade de uma Árvore

É o nível máximo que um nó da árvore
atinge;
0
1
2
3
A altura desta árvore é 3!
Ela possui 4 níveis!
http://www.computacao.gigamundo.com
Percurso de uma Árvore

Também conhecido como travessia;

Consiste em percorrer (em uma dada ordem) todos
os nós de um árvore ou até encontrar algum que
satisfaça ao problema em questão;

É empregado, por exemplo, na busca de um nó a
partir de uma chave;
http://www.computacao.gigamundo.com
Percurso de uma Árvore

Tipos
–
–
–
Pré-ordem / pre-order;
Em-ordem / in-order;
Pós-ordem / pos-order.
http://www.computacao.gigamundo.com
Percurso Pré-Ordem

Processa primeiro a informação do nó atual,
para só então processar a informação de
seus filhos;
função x (no)
Início
processa no;
aplica função x para cada filho de no;
Fim;
http://www.computacao.gigamundo.com
Percurso Pré-Ordem
function buscaTelefone(no: PNode; nome: String): String;
var s: String;
Begin
if no = nil then
buscaTelefone := “”
else if no.nome = nome then
buscaTelefone := no.telefone
else
begin
s := buscaTelefone(no.filho1, nome);
if s <> “” then
buscaTelefone := s
else
begin
s := buscaTelefone(no.filho2, nome);
if s <> “” then
buscaTelefone := s
else
buscaTelefone := “”;
end;
end;
End;
http://www.computacao.gigamundo.com
Percurso Em-Ordem

Neste caso, um filho (ou parte dos filhos) é
processado primeiro, o nó atual é então processado
e, por fim, o outro filho (ou parte dos filhos);
função x (no)
Início
aplica função x para parte dos filhos de no;
processa no;
aplica função x para parte dos filhos de no;
Fim;
http://www.computacao.gigamundo.com
Percurso Pós-Ordem

Neste caso, todos os filhos do nó atual devem ser
processados antes que o mesmo o seja;
função x (no)
Início
aplica função x para cada filho de no;
processa no;
Fim;
http://www.computacao.gigamundo.com
Inserção em uma Árvore

Cria-se o novo nó (método new) e popula-se
o mesmo com as informações desejadas;

Pode utilizar algum critério para determinar
em qual nó e em qual posição o novo nó
deverá ficar;

O pai deve apontar para o filho.
http://www.computacao.gigamundo.com
Remoção em uma Árvore




Utiliza-se de um outro ponteiro ( t ) para apontar
para o objeto que se deseja remover;
Após isso, reorganiza-se seus filhos a fim de que
seu pai possa apontara para esses e ninguém ficar
“abandonado”, eliminando o vínculo entre a árvore e
o nó-alvo;
Por fim, elimina-se o nó (método dispose);
E se nosso objetivo for remover TODOS os nós de
uma árvore, qual método de percurso você
utilizaria? Por quê?
http://www.computacao.gigamundo.com
Árvores Binárias

Árvores onde cada nó possui no máximo dois filhos;

Muito usadas em computação;

Cada nível pode ter no máximo 2N nós, onde N é o
valor do nível;

Quantidade de níveis que uma árvore binária com N
nós pode ter:
–
–
Máximo: N; (árvore degenerada)
Mínimo: Log2 N + 1; (árvore completa)
http://www.computacao.gigamundo.com
Árvores Binárias

Dado um nó qualquer, ele possuirá uma subárvore esquerda e uma sub-árvore direita
(podendo qualquer uma delas ou ambas não
possuir elementos);
Sub-árvore
direita
Sub-árvore
esquerda
http://www.computacao.gigamundo.com
Árvores Binárias de Busca

Ou árvores de busca binária (tanto faz!);

São árvores em que é possível determinar em que
direção buscar um dado nó a partir do valor do pai e
levando-se em consideração alguma regra quanto à
disposição dos filhos;
–
–

Nós com valores menores que o pai à esquerda, nós com
valores maiores que o pai à direita;
Nós que satisfazem uma condição expressa pelo pai de um
lado e nós que não satisfazem do outro;
O que acontecerá se a árvore de busca não estiver
bem balanceada?
http://www.computacao.gigamundo.com
Inserção em uma Árvore Binária de
Busca
function inserir(var arvore: TArvore; valor:
integer): boolean;
var p, t: PNode;
Begin
new(p);
p.valor := valor;
p.filho[1] := nil;
p.filho[2] := nil;
if arvore = nil then
arvore := p
else
begin
t := arvore;
while t <> nil do
begin
if (t^.valor > valor) then
begin
if t^.filho[1] = nil then
begin
t^.filho[1] := p; inserir := true; exit;
end
else
t := t^.filho[1];
end
else if t^.valor < valor then
begin
if t^.filho[2] = nil then
begin
t^.filho[2] := p; inserir := true; exit;
end
else
t := t^.filho[2];
end
else
begin
inserir := false;
exit;
end;
end;
inserir := false;
end;
http://www.computacao.gigamundo.com
Busca em uma Árvore Binária de
Busca
function buscar(arvore:
TArvore; valor: integer):
PNode;
var t:PNode;
Begin
if (arvore = nil) then
buscar := nil
else
begin
t := arvore;
while (t <> nil) do
begin
if t^.valor > valor then
t := t^.filho[1]
else if t^.valor < valor
then
t := t^.filho[2]
else
begin
buscar := t;
exit;
end;
end;
buscar := nil;
end;
end;
http://www.computacao.gigamundo.com
Deleção em uma Árvore Binária de
Busca

Caso 1: Remover um nó que não possui
filhos
http://www.computacao.gigamundo.com
Deleção em uma Árvore Binária de
Busca

Caso 2: Remover um nó que possui um filho
http://www.computacao.gigamundo.com
Deleção em uma Árvore Binária de
Busca

Caso 3: Remover um nó que possui dois filhos
–
–
Escolher o nó mais à esquerda da sub-árvore direita (ou mais à
direita da sub-árvore esquerda) para “substituí-lo;
Com isso, teremos que remover o nó selecionado de onde ele
está  abordagem recursiva.
http://www.computacao.gigamundo.com
Comparações entre Ordens de
Complexidade
http://www.computacao.gigamundo.com
Referências Bibliográficas

[Não foram definidas]
http://www.computacao.gigamundo.com
Árvores AVL
(Aula 13)
Christiano Lima Santos
http://www.computacao.gigamundo.com
Sumário



Definição de Árvore AVL
Representação Gráfica
Operações
–
–
–
Inserção
Remoção
Rotação

Simples
–
À Esquerda
– À Direita

–

Dupla
Pesquisa
Referências Bibliográficas
http://www.computacao.gigamundo.com
Definição de Árvore AVL

Trata-se de uma Árvore de Busca Binária
Auto-Balanceada, isto é, que mantém o
balanceamento de sua árvore em cada
operação executada;

A maior diferença possível entre os níveis de
dois nós-folhas é 1;
http://www.computacao.gigamundo.com
Representação Gráfica
Árvore Não-Balanceada
Árvore AVL (Balanceada)
http://www.computacao.gigamundo.com
Operações

Inserção

Remoção

Rotação
–
–
Simples (à esquerda ou à direita);
Dupla.
http://www.computacao.gigamundo.com
Inserção

Efetua-se a busca pelo nó (igual a qualquer
outra árvore de busca binária);

Insere-se o nó;

Verifica-se se ela está balanceada, caso não
esteja, efetuar rotação (simples ou dupla) até
que esteja.
http://www.computacao.gigamundo.com
Remoção

Efetua-se a busca pelo nó (igual a qualquer outra
árvore de busca binária);

Rotaciona-se até que o mesmo seja um nó-folha e
remova-o;
–

Por quê? A remoção de um nó sem filhos é o caso mais
simples!
Verifique se a árvore se encontra balanceada, caso
não esteja, efetue rotações.
http://www.computacao.gigamundo.com
Rotação

Operação em que a ordem dos nós em uma
árvore de busca binária pode ser invertida a
fim de manter o balanceamento da mesma;

Pode ser simples (um único passo,
rotacionando à esquerda ou à direita) ou
dupla (efetuando mais de uma vez a rotação,
em qualquer combinação de rotações
simples);
http://www.computacao.gigamundo.com
Rotação Simples

Ocorre quando o nó desbalanceado e o seu
filho estão no mesmo sentido de inclinação
da árvore;

Formam “uma linha reta”;
http://www.computacao.gigamundo.com
Rotação à Esquerda

Dado um nó X com um filho à direita Y e este tendo um
filho à esquerda Z;

Pseudo-código:
Seja Y o filho à direita de X;
Torne X o filho à esquerda de Y;
Torne o filho à esquerda de Y (Z) o filho à direita de
X;
http://www.computacao.gigamundo.com
Rotação à Direita

Dado um nó X com um filho à esquerda Y e este tendo
um filho à direita Z;

Pseudo-código:
Seja Y o filho à esquerda de X;
Torne X o filho à direita de Y;
Torne o filho à direita de Y (Z) o filho à esquerda de
X;
http://www.computacao.gigamundo.com
Rotação Dupla

Ocorre quando o nó desbalanceado está em
um sentido da inclinação e o seu filho em
outro;

Formam, assim, “um joelho”.
http://www.computacao.gigamundo.com
Pesquisa

O tempo médio para encontrar um elemento
em uma árvore AVL é da ordem de O (log n)

Aproximadamente 1.44 log2 n no pior caso
http://www.computacao.gigamundo.com
Referências Bibliográficas

http://www.csi.uottawa.ca/~stan/csi2514/appl
ets/avl/BT.html - Aplicação interessante para
compreender árvores AVL

http://pt.wikipedia.org/wiki/Árvore_AVL
http://www.computacao.gigamundo.com
Classificação de Dados
(Aula 14)
Christiano Lima Santos
http://www.computacao.gigamundo.com
Sumário










Por que estudar métodos para classificação de
dados?
Alguns tipos de algoritmos de classificação
Seleção Direta (Selection Sort)
Inserção Direta (Insertion Sort)
Método da Bolha (Bubble Sort)
Método do Balde (Bucket Sort)
QuickSort
MergeSort
HeapSort
Referências Bibliográficas
http://www.computacao.gigamundo.com
Por que estudar métodos para
classificação de dados?

Qual a importância da ordenação dos dados quando
se deseja uma busca mais eficiente ou classificar os
mesmos segundo algum critério?

Há muita diferença entre o tempo de processamento
de um algoritmo de ordenação O(n log n) e o tempo
de um algoritmo de ordenação O(n2), quando
executados sobre uma base com um milhão de
dados?

Sendo assim, torna-se interessante o estudo dos
diversos tipos de algoritmos de ordenação?
http://www.computacao.gigamundo.com
Alguns Tipos de Algoritmos de
Classificação







Seleção direta (selection sort)
Inserção direta (insertion sort)
Método da Bolha (bubble sort)
Método do “Balde” (bucket sort)
Quicksort
Mergesort
Heapsort
http://www.computacao.gigamundo.com
Seleção Direta (Selection Sort)

Definição
–
Trata-se de um algoritmo de comparação in-loco, isto é, executa
comparações e operações de troca na própria estrutura original,
sem necessidade de usar uma estrutura auxiliar;
–
É o algoritmo mais simples de implementar, infelizmente, é
também o mais ineficiente de todos os aqui apresentados;
–
Dado um array/lista não ordenado, varre-o por completo
procurando o primeiro menor elemento presente no mesmo,
trocando o mesmo de lugar com o primeiro elemento do array;
Após isso, procura o segundo menor elemento presente no
mesmo e troca de posição com o segundo elemento do array.
Procede desta forma até processar os N elementos;
http://www.computacao.gigamundo.com
Seleção Direta (Selection Sort)

Ilustração
http://www.computacao.gigamundo.com
Seleção Direta (Selection Sort)

Implementação
function selecaoDireta(var a: array
[1..N] of real):boolean;
var i, j, menor : integer;
v: real;
begin
for i := 1 to N do
begin
menor := i;
for j := i+1 to N do
begin
if a[menor] > a[j] then
menor := j;
end;
if menor <> i then
begin
v := a[i];
a[i] := a[menor];
a[menor] := v;
end;
end;
selecaoDireta := true;
end;
http://www.computacao.gigamundo.com
Seleção Direta (Selection Sort)

Complexidade
–
Tanto para o pior caso, quanto para o caso médio
e para o melhor caso, o algoritmo sempre
precisará efetuar:




N operações para encontrar o primeiro menor elemento;
N-1 operações para encontrar o segundo menor
elemento;
...
1 operação para encontrar o n-ésimo menor elemento;
Total: 1 + 2 + ... + N = N(N+1)/2 = O(n2)
http://www.computacao.gigamundo.com
Inserção Direta (Insertion Sort)

Definição
–
Dado um array/lista Y não ordenado, inicia com
uma lista X vazia. Pega o primeiro elemento de Y
e varre toda a lista X procurando a posição
correta para inseri-lo e, então, o insere. Pega o
segundo elemento e também varre toda a lista X,
procurando a posição correta e insere-o. Procede
desta forma até processar os N elementos;
http://www.computacao.gigamundo.com
Inserção Direta (Insertion Sort)

Ilustração
http://www.computacao.gigamundo.com
Inserção Direta (Insertion Sort)

Implementação
function insercaoDireta(var y:
array [1..N] of real):boolean;
var x,t: TLista;
i: integer;
begin
x := nil;
for i := 1 to N do
insercaoOrdenada(x, y[i]);
t := x;
i := 1;
while (x <> nil) do
begin
y[i] := x^.valor;
x := x^.proximo;
dispose(t);
t := x;
end;
insercaoDireta := true;
end;
http://www.computacao.gigamundo.com
Inserção Direta (Insertion Sort)

Complexidade
–
–
–
Melhor Caso: O(n), pois ele simplesmente pegará
cada elemento e inserirá na cabeça da lista;
Pior Caso: O(n2), pois para cada elemento ele
terá que inseri-lo na cauda da lista, o que
significará 1 + 2 + 3 + ... + N = N(N+1)/2
operações;
Caso Médio: O(n2).
http://www.computacao.gigamundo.com
Método da Bolha (Bubble Sort)

Definição
–
Varre do início ao fim, sempre checando se o elemento xi é
menor ou igual ao xi+1. Se for, passa para o próximo par
(xi+1 e xi+2), caso não seja, inverte suas posições e recua
uma posição para checar então com o anterior (xi-1 e xi).
Procede desta forma até varrer toda a estrutura e chegar ao
fim;
–
Este algoritmo de classificação também é in-loco, isto é,
dispensa a utilização de estruturas auxiliares para efetuar a
classificação dos dados.
http://www.computacao.gigamundo.com
Método da Bolha (Bubble Sort)

Ilustração
http://www.computacao.gigamundo.com
Método da Bolha (Bubble Sort)

Implementação
function
metodoDaBolha(insercaoDireta
(var y: array [1..N] of
real):boolean;
var i: integer;
c: real;
begin
i := 1;
while (i < N) do
begin
if (y[i] <= y[i+1]) then
i := i + 1
else
begin
c := y[i];
y[i] := y[i+1];
y[i+1] := c;
i := i – 1;
if (i < 1) then
i := 1;
end;
metodoDaBolha := true;
end;
http://www.computacao.gigamundo.com
Método da Bolha (Bubble Sort)

Complexidade
–
–
–
Melhor Caso: O(n), pois passa uma vez só por
cada par (todos os dados já estão ordenados);
Pior Caso: O(n2), onde os dados estão na ordem
inversa e portanto levará executará 1 + 2 + ... + N
trocas;
Caso médio: O(n2);
http://www.computacao.gigamundo.com
Método do Balde (Bucket Sort)

Definição
–
Cria K buckets identificados e ordenados segundo algum
critério (buckets contendo elementos de 1 a 10, buckets
contendo elementos de 11 a 20, etc.) e então armazena os
elementos dentro de cada bucket correspondente. Após
isso, pode-se aplicar a cada bucket o algoritmo de
ordenação que melhor convier;
–
Este método geralmente se utiliza de um array de buckets
como estrutura auxiliar, cada qual podendo ser
implementado como um array ou uma lista.
http://www.computacao.gigamundo.com
Método do Balde (Bucket Sort)

Ilustração
http://www.computacao.gigamundo.com
Método do Balde (Bucket Sort)

Implementação (pseudo-código)
function bucket-sort(array, n) is
buckets ← new array of n empty lists
for i = 0 to (length(array)-1) do
insert array[i] into buckets[position(array[i], k)]
for i = 0 to n - 1 do
next-sort(buckets[i])
return the concatenation of buckets[0], ..., buckets[n-1]
http://www.computacao.gigamundo.com
Método do Balde (Bucket Sort)

Implementação
function metodoDoBalde(var y: array [1..N] of real; k:
integer):Boolean;
var bucket: array [1..k] of record
slots: array [1..N] of real;
index: integer;
end;
menor, maior: real;
i,j,c: integer;
http://www.computacao.gigamundo.com
Método do Balde (Bucket Sort)

Implementação (continuação)
begin
menor := y[1];
maior := y[1];
for i := 1 to N do
begin
if y[i] > maior then
maior := y[i];
if y[i] < menor then
menor := y[i];
end;
http://www.computacao.gigamundo.com
Método do Balde (Bucket Sort)

Implementação (continuação)
for i := 1 to N do
begin
j := 1 + k*(y[i] - menor)/(maior – menor + 1);
bucket[j].index := bucket[j].index + 1;
bucket[j].slots[bucket[j].index] := y[i];
end;
c := 1;
http://www.computacao.gigamundo.com
Método do Balde (Bucket Sort)

Implementação (continuação)
for j := 1 to k do
begin
selecaoDireta(bucket[j].slots, bucket[j].index);
for i := 1 to bucket[j].index do
begin
y[c] := bucket[j].slots[i];
c := c + 1;
end;
end;
metodoDoBalde := true;
end;
http://www.computacao.gigamundo.com
Método do Balde (Bucket Sort)

Complexidade
–
Depende do algoritmo de classificação a ser
usado em cada bucket;
http://www.computacao.gigamundo.com
Quicksort

Definição
–
Algoritmo “dividir para conquistar”. Escolhe um pivô dentro
da lista de dados a ordenar e cria dois grupos, um com os
números menores que ele (à esquerda) e outro com
números maiores que ele (à direita). Após isso, o algoritmo
é executado para cada grupo, escolhendo-se novamente
um pivô e dividindo-se em dois grupos menores. O
processo procee até que cada grupo contenha somente um
elemento, concatenando todos e formando uma lista
ordenada;
http://www.computacao.gigamundo.com
Quicksort

Ilustração
[Ops! Não escrevi aqui!]
http://www.computacao.gigamundo.com
Quicksort

Implementação
function quicksort(var y: array [1..N] of real,
IniVet, FimVet: integer): boolean;
var i, j: integer;
pivo, aux: real;
Início
i := IniVet;
j := FimVet;
pivo := y[(IniVet + FimVet) div 2];
repeat
while (y[i] < pivo) AND (i < FimVet) do
i := i + 1;
while (y[j] > pivo) AND (j > FimVet) do
j := j – 1;
if (i <= j) then
begin
aux := y[i];
y[i] := y[j];
y[j] := aux;
i := i + 1;
j := j – 1;
end;
until (i > j);
if (j > IniVet) then
quicksort(y, IniVet, j);
if (i < FimVet) then
quicksort(y, i, FimVet)
end;
http://www.computacao.gigamundo.com
Quicksort

Complexidade
[Ops! Não escrevi aqui!]
http://www.computacao.gigamundo.com
Mergesort

Definição
–
Também algoritmo “dividir para conquistar”.
“Quebra” a lista em listas menores, até que cada
lista contenha somente um elemento, quando
então começa a ordená-las fazendo um “merge”,
isto é, juntando duas listas diferentes por vez
mantendo a nova ordem dos elementos;
http://www.computacao.gigamundo.com
Mergesort

Ilustração
[Ops! Não escrevi aqui!]
http://www.computacao.gigamundo.com
Mergesort

Implementação
[Ops! Não escrevi aqui!]
http://www.computacao.gigamundo.com
Mergesort

Complexidade
[Ops! Não escrevi aqui!]
http://www.computacao.gigamundo.com
Heapsort

Definição
–
Utiliza uma árvore binária chamada “heap” para
ordenar os dados. Todo o problema aqui resumese à criação desta árvore, bem como a remoção
de cada nó da mesma sem alterar a ordenação.
http://www.computacao.gigamundo.com
Heapsort

Ilustração
[Ops! Não escrevi aqui!]
http://www.computacao.gigamundo.com
Heapsort

Implementação
[Ops! Não escrevi aqui!]
http://www.computacao.gigamundo.com
Heapsort

Complexidade
[Ops! Não escrevi aqui!]
http://www.computacao.gigamundo.com
Referências Bibliográficas

[Não foram definidas]
Download