fundamentos da programação - ulisboa

33
Fundamentos da Programação Capítulo 5: Listas

Upload: others

Post on 19-Oct-2021

4 views

Category:

Documents


0 download

TRANSCRIPT

Page 1: Fundamentos da Programação - ULisboa

Fundamentos da Programação

Capítulo 5: Listas

Page 2: Fundamentos da Programação - ULisboa

Algoritmos de procura• Procura de informação

• É uma das nossas atividades quotidianas• Procuramos páginas com determinadas palavras no Google• Livros em bibliotecas• Produtos em supermercados, etc.

• É uma das atividades importantes num sistema computacional• Parece ser muito simples, a eficiência levanta problemas

• Procura da palavra “Python”' no Google: devolve cerca de 312 milhões de resultados em 0.57 segundos

Page 3: Fundamentos da Programação - ULisboa

Algoritmos de procura• A procura é frequentemente executada recorrendo a listas• Função procura, recebe como argumentos uma lista lst e um elemento (a chave)

• Devolve o índice do elemento da lista cujo valor é igual a chave• Convencionamos que, se chave não pertencer à lista, a função devolve -1

Page 4: Fundamentos da Programação - ULisboa

Algoritmos de procuraProcura sequencial

Page 5: Fundamentos da Programação - ULisboa

Algoritmos de procuraProcura sequencial

def procura(lst, chave):

for i in range(len(lst)):

if lst[i] == chave:

return i

return -1

Page 6: Fundamentos da Programação - ULisboa

Algoritmos de procuraProcura bináriaA procura sequencial pode exigir a inspeção de todos os elementos da lista

A procura binária é mais eficiente, exigindo que os elementos da lista encontrem ordenados

• Consideramos o elemento que se encontra no meio da lista• Se for igual ao que estamos a procurar, então a procura termina• Se é menor, o elemento procurado não se encontra na primeira metade da lista. Repetimos

o processo para a segunda metade da lista• Se é maior, o elemento procurado não se encontra na segunda metade da lista. Repetimos

processo para a primeira metade da lista

Em cada passo, o número de elementos a considerar é reduzido para metade

Page 7: Fundamentos da Programação - ULisboa

Algoritmos de procuraProcura binária

2 5 9 10 11 20Procurar

0 1 2 3 4 5

linf lsupmeio

10

2 5 9 10 11 20

0 1 2 3 4 5

linf lsup

meio

2 5 9 10 11 20

0 1 2 3 4 5

linf,lsup,meio

Page 8: Fundamentos da Programação - ULisboa

Algoritmos de procuraProcura binária 2 5 9 10 11 20

Procurar

0 1 2 3 4 5

linf lsupmeio

12

2 5 9 10 11 20

0 1 2 3 4 5

linf lsup

meio

2 5 9 10 11 20

0 1 2 3 4 5

linf,lsup,meio

2 5 9 10 11 20

0 1 2 3 4 5

linflsup

Page 9: Fundamentos da Programação - ULisboa

Algoritmos de procuraProcura bináriadef procura(lst, chave):

linf = 0lsup = len(lst) - 1while linf <= lsup:

meio = (linf + lsup) // 2if chave == lst[meio]:

return meioelif chave > lst[meio]:

linf = meio + 1else:

lsup = meio - 1return -1

Page 10: Fundamentos da Programação - ULisboa

Algoritmos de ordenação• Uma lista ordenada facilita a procura

• Procura sequencial vs. procura binária

• Na nossa vida quotidiana, ordenamos as coisas para tornar a procura mais fácil, e não porque somos arrumados

• Supermercado sem produtos agrupados• Biblioteca sem livros ordenados

• Estudo de alguns algoritmos para ordenar os valores contidos numa lista

Page 11: Fundamentos da Programação - ULisboa

Algoritmos de ordenaçãoOrdenação por borbulhamento• Percorre os elementos a ordenar, comparando elementos adjacentes, trocando

os pares de elementos que se encontram fora de ordem• De um modo geral, uma única passagem pela sequência de elementos não

ordena a lista, pelo que é necessário efetuar várias passagens• A lista encontra-se ordenada quando se efetua uma passagem completa em

que não é necessário trocar a ordem de nenhum elemento

Page 12: Fundamentos da Programação - ULisboa

Algoritmos de ordenaçãoOrdenação por borbulhamento

Page 13: Fundamentos da Programação - ULisboa

Algoritmos de ordenaçãoOrdenação por borbulhamento

def ordena(lst):maior_indice = len(lst) - 1 nenhuma_troca = False # garante que o ciclo while é executadowhile not nenhuma_troca:

nenhuma_troca = Truefor i in range(maior_indice):

if lst[i] > lst[i+1]:lst[i], lst[i+1] = lst[i+1], lst[i]nenhuma_troca = False

maior_indice = maior_indice - 1

Page 14: Fundamentos da Programação - ULisboa

Algoritmos de ordenaçãoOrdenação por seleção• Percorre os elementos a ordenar e, em cada passagem, coloca um elemento

na sua posição correta• Na primeira passagem, coloca-se o menor elemento na sua posição correta,

na segunda passagem, o segundo menor, e assim sucessivamente

Page 15: Fundamentos da Programação - ULisboa

Algoritmos de ordenaçãoOrdenação por seleção

Page 16: Fundamentos da Programação - ULisboa

Algoritmos de ordenaçãoOrdenação por seleçãodef ordena(lst):

for i in range(len(lst)):

pos_menor = i

for j in range(i + 1, len(lst)):

if lst[j] < lst[pos_menor]:

pos_menor = j

lst[i], lst[pos_menor] = lst[pos_menor], lst[i]

Page 17: Fundamentos da Programação - ULisboa

Ordenação usando listas de índices• Os algoritmos de ordenação que apresentámos efetuam a ordenação de forma

destrutiva• A lista inicial é alterada para a lista ordenada

• Uma alternativa consiste em criar uma lista auxiliar contendo os índices (posições na lista original) dos elementos ordenados, não alterando a lista original mas apenas a lista dos índices

• Permite manter várias “vistas” ordenadas sobre a mesma lista• Exemplo informação sobre os voos de um aeroporto

Page 18: Fundamentos da Programação - ULisboa

Ordenação usando listas de índicesOrdenação por borbulhamento

Page 19: Fundamentos da Programação - ULisboa

Ordenação usando listas de índicesOrdenação por borbulhamento

Page 20: Fundamentos da Programação - ULisboa

Ordenação usando listas de índicesOrdenação por borbulhamento

def ordena(lst):maior_indice = len(lst) - 1ind = list(range(len(lst)))nenhuma_troca = Falsewhile not nenhuma_troca:

nenhuma_troca = Truefor i in range(maior_indice):

if lst[ind[i]] > lst[ind[i+1]]:ind[i], ind[i+1] = ind[i+1], ind[i]nenhuma_troca = False

maior_indice = maior_indice - 1 return ind

Page 21: Fundamentos da Programação - ULisboa

Ordenação usando listas de índicesOrdenação por borbulhamento

def devolve_ordenada(lst, indices):res = [] # vamos construir a lista ordenadafor i in range(len(lst)):

res = res + [lst[indices[i]]]return res

Page 22: Fundamentos da Programação - ULisboa

Considerações sobre eficiência• A procura binária é mais eficiente do que a procura sequencial

• O que é que isto significa?

• Métodos para comparar a eficiência de algoritmos• Eficiência de um algoritmo• Uma medida grosseira do trabalho envolvido na execução de um

algoritmo

Page 23: Fundamentos da Programação - ULisboa

Considerações sobre eficiência• O trabalho envolvido na execução de um algoritmo poder variar drasticamente

com os dados fornecidos• Se a lista estiver ordenada, a ordenação por borbulhamento só necessita de uma

passagem

• Encontrar uma medida do trabalho que seja independente dos valores particulares dos dados utilizados na sua execução

• Ordem de crescimento avaliação grosseira dos recursos exigidos pelo algoritmo à medida que a quantidade de dados manipulados aumenta

• Isolar uma operação que seja fundamental para o algoritmo, e contar o número de vezes que esta operação é executada

• Para o caso dos algoritmos de procura e de ordenação, esta operação é a comparação (dados dois elementos, qual deles é o maior?)

Page 24: Fundamentos da Programação - ULisboa

Considerações sobre eficiência• A medida de eficiência de um algoritmo de procura ou de ordenação é o número

de comparações que estes efetuam• Dados dois algoritmos, o algoritmo que efetuar o menor número de

comparações é o mais eficiente

Page 25: Fundamentos da Programação - ULisboa

Considerações sobre eficiência• Na procura sequencial, percorremos a sequência de elementos até encontrar o

elemento desejado• Se o elemento desejado se encontrar na primeira posição da lista, necessitamos apenas de

uma comparação• Poderemos ter de percorrer toda a lista, se o elemento procurado não se encontrar na lista

• O número médio de comparações cai entre estes dois extremos, pelo que o número médio de comparações na procura sequencial é

𝑛2

em que 𝑛 é o número de elementos na lista

Page 26: Fundamentos da Programação - ULisboa

Considerações sobre eficiência• Na procura binária reduzimos para metade o número de elementos a considerar

sempre que efetuamos uma comparação• Se começarmos com 𝑛 elementos, o número de elementos depois de uma passagem é 𝑛/2• O número de elementos depois de duas passagens é 𝑛/4 e assim sucessivamente

• No caso geral, o número de elementos depois de 𝑖 passagens é !"!• O algoritmo termina quando o número de elementos é menor do que 1, ou seja,

terminamos depois de 𝑖 passagens quando!"! < 1

ou𝑙𝑜𝑔"(𝑛) < 𝑖

Page 27: Fundamentos da Programação - ULisboa

Considerações sobre eficiência• Para uma lista com 𝑛 elementos, a procura binária não exige mais do que 𝑙𝑜𝑔"(𝑛) passagens

• Em cada passagem efetuamos três comparações• Uma comparação na instrução if e duas comparações para calcular a expressão que

controla o ciclo while

• O número de comparações exigido pela procura binária é inferior ou igual a

3. 𝑙𝑜𝑔"(𝑛)

Page 28: Fundamentos da Programação - ULisboa

Considerações sobre eficiência• Na ordenação por borbulhamento e por seleção

12 . (𝑛

" − 𝑛)

Page 29: Fundamentos da Programação - ULisboa

Notação do O-maiúsculo• A preocupação com a eficiência está relacionada com problemas que envolvem

um número muito grande de elementos• Se a lista em que efetuamos uma procura tiver 100 000 000 elementos

• A procura sequencial requer uma média de 50 000 000 comparações• A procura binária requer, no máximo, 61 comparações

• Aproximação da quantidade de trabalho necessário em função do número de elementos considerados

• Notação matemática conhecida por notação do O-maiúsculo• Usada para descrever o comportamento de uma função em termos de outra

função mais simples, quando o seu argumento tende para o infinito

Page 30: Fundamentos da Programação - ULisboa

Notação do O-maiúsculoSejam f(x) e g(x) duas funções com o mesmo domínio definido sobre o conjunto dos números reais. Escrevemos

𝑓 𝑥 = 𝑂(𝑔 𝑥 )

se e só se existir uma constante positiva 𝑘, tal que para valores suficientemente grandes de x,

𝑓(𝑥) ≤ 𝑘. 𝑔(𝑥)

ou seja, a partir de um valor 𝑥# 𝑘. 𝑔(𝑥) dominar 𝑓(𝑥)

Page 31: Fundamentos da Programação - ULisboa

Notação do O-maiúsculoA ordem de magnitude de uma função é igual à ordem do seu termo que cresce mais rapidamenteA ordem de magnitude de 𝑛" + 𝑛 é 𝑛"

O(𝑛" + 𝑛) = 𝑛"

• A procura binária é de ordem 𝑂(𝑙𝑜𝑔! 𝑛 )• A procura sequencial é de ordem 𝑂(𝑛)• Tanto a ordenação por borbulhamento como a ordenação por seleção são de

ordem 𝑂(𝑛")

Page 32: Fundamentos da Programação - ULisboa

Duração comparativa

Page 33: Fundamentos da Programação - ULisboa