Você está na página 1de 89

ALGORÍTMO E PROGRAMAÇÃO DE COMPUTADORES II

PARA EXECUTAR SOMENTE UMA CELULA, SEPARO ELA COM # E NA ABA


codigo, cell mode, run cell
Semana 1- Gerenciamento de memória, arquivos e depuração
de programas
Videoaula 1 - Tipos mutáveis e não mutáveis em Python
Gerenciamento Quando fazemos uma atribuição: >>> a = 3
de memória o objeto int com valor 3 e o nome a são criados. Objeto = TIPO (depende do
valor que é atribuído à variável) + VALOR
Python cria uma tabela com todas as variáveis, que ‘apontam’ para um objeto
Ex. Tipos diferentes de objeto
>>> a = 3 (tipo int)
>>> b = 3.0 (tipo float)
>>> c = 'hello' (tipo str (string)– usa-se ‘ ‘)
>>> d = [2, 3, 5, 8, 11] - (tipo lst)
Quando altero a varíavel a para 6
>>> a = 6
Python cria novo objeto na memória do tipo int e a variável aponta para ele
não mais para o 3
Int, bool, float, str e complex = IMUTÁVEL
Quando altero um elemento de uma list, não é criado novo objeto, ele é
alterado:
>>> d = [2, 3, 5, 8, 11]
>>> d[3] = 7

Lst = MUTÁVEL
Para mudar variável do tipo int:
>>> a = 3 >>> a = 6
>>> b = a

Se mudo um item de uma lista que é correspondente a duas variáveis, item


ser alterado nas duas listas:
Passagem de parâmetros para funções: INT
Quando adiciono uma variável a = 3 e defino uma função def g(x): x = 5,
alterar a função para g(a), internamente o Python altera x para 3 e logo em
seguida, ao receber a definição de x = 5, ele o altera, contudo a variável a
continua como 3.

Passagem de parâmetros para funções: LST


Quando defino uma função def h(lst): e defino que primeiro elemento receba
o valor 5 (Lst [0] = 5), criando a lista com os elementos 3, 6, 9, 12 (>>>myList =
[3, 6, 9, 12] e fazendo a chamada na função h (>>> h(myList))determino que a
função h(lst) receba o myList. Executando a função h (lst[0] = 5), o primeiro
item da myList será alterado para 5.
Assim, se eu chamar novamente o myList, retorna a lista alterada para [5, 6, 9,
12]

Videoaula 2 - Arquivos
Arquivos Sequência de bytes armazenada em memória secundária*.
Existem dois tipos de arquivos:
- Arquivos texto (.txt, .html, .py, etc.) (há codificação dos bytes em caracteres
que são legíveis pelos seres humanos)
- Arquivos binários (.exe, .mp3, .jpg, etc.) (não são codificados)
*Memória primária é a memória do computador (RAM), componente que a
memória usa para armazenar temporariamente os dados que serão
processados pelo processador
Memória secundária: componentes do computador que armazena dados que
não são voláteis (quando desligo o computador os dados não se apagam). Ex.
HD, Pen Drive, Nuvem, para armazenar dados nessas memórias, utilizamos os
arquivos.

Sistemas de Componente do computador que organiza os arquivos e provê meios para


arquivos criá-los, acessá- los e modificá-los.
Fornece uma visão uniforme dos arquivos, embora possam estar
armazenados em diferentes dispositivos.
Arquivos são agrupados em pastas ou diretórios.
Para localizar um arquivo, é necessário especificar seu nome e sua (sub)pasta.
1º Caminho absoluto para acessar example.txt: /Users/Iperkovic/example.txt
(especifico o caminho da raíz até o arquivo)
2º Caminho relativo: acesso outra pasta a partir do local que estou no sistema
de arquivo. Acessar example.txt a partir de Shared:
../Users/Iperkovic/example.txt

Acessando Processar um arquivo consiste em três passos:


arquivos 1. Abrir um arquivo para leitura ou escrita
2. Ler os dados do arquivo ou escrever nele
3. Fechar o arquivo
Função open():
>>> open('example.txt', 'r') (recebe 2 parâmetros: caminho + modo de
abertura)

No caso de arquivos binários, a sequência de bytes não é codificada ou


decodificada usando alguma codificação (ASC-II, UTF-8, etc.)
Funções para leitura ou escrita de arquivos:
Infile - varíavel que aponta para o arquivo aberto.
Infile.read (n) - faz a leitura de n caracteres
Fechando um Chamamos a função close () para fechar o arquivo (avisar o sistema para
arquivo liberar os recursos/informações sobre o arquivo aberto).
Exemplo def readFile(filename):
infile = open(filename, 'r')
content = infile.read()
infile.close()
wordList = content.split() (a função split divide por palavras o texto)
print(wordList)
return len(wordList), len(content) (returna a informa de quantas palavras há
no arquivo (len(wordList) e quantos caracteres há len (content))

n_words, n_chars (caracteres) = readFile('teste.txt') quando o arquivo está na


mesma pasta do python, não preciso colocar o caminho absoluto dele
Escrevendo um Para escrever dados em um arquivo, precisamos abri-lo em modo escrita:
arquivo >>> outfile = open('teste.txt', 'w') (se o arquivo já existir e eu abrir ele em
modo escrita, vai sobrescrever o arquivo)

Usamos a função write(), que escreve strings no arquivo aberto, retornando o


número de caracteres escritos.
>>> outfile.write('Olá classe!\n')

Para escrever outros dados que não são string, devemos convertê-los ou usar
o método format():
>>> idade = 30
>>> outfile.write('Sua idade é '+str(idade)+' anos.\n') (posso transforma essa
variavel para o tipo string e então concatenamos na frase que desejamos ou
usamos a format, que transforma o dado em sua respectiva string e coloca no
lugar das {})
>>> outfile.write('Sua idade é {} anos.\n'.format(idade))

Vídeo de apoio - Depuração de programas


ATIVIDADE AVALIATIVA:
Semana 2: Programação orientada a objetos e modularização

VIDEOAULA 3

Programação Orientada a Objetos (POO) I


Programação Todo programa pode ser escrito como uma combinação de comandos
Estruturada envolvendo:
- Estruturas de sequência
- Estruturas de seleção
- Estruturas de repetição
Utilizam-se funções para separar o programa em pequenas partes, facilitando a
modularização, reúso e manutenção de código.

- Procedimentos são implementados em blocos e a comunicação entre eles se


dá pela passagem de parâmetros
- Um programa estruturado, quando em execução, é caracterizado pelo
acionamento de procedimentos, cujas tarefas são manipular os dados
Programação - Dados e procedimentos são encapsulados em um só elemento denominado
Orientada a objeto
Objetos: - O estabelecimento da comunicação entre objetos (envio e recebimento de
mensagens) caracteriza a execução do programa
Objeto Entidade que formaliza o modo pelo qual compreendemos algo no domínio do
problema
Reflete a capacidade do sistema de guardar informações sobre o elemento
abstraído, interagir com ele ou ambas as coisas
Entidade o mais próximo possível das entidades do mundo real
A um objeto estão sempre associados: seu estado e seu comportamento
Exemplo
Atributos: - cor: vermelho; - ano: 2012; velocidade: 0 km/h; combustível: Etanol
Métodos: - acelerar() - frear(), - virar(), - acionar_farol()
Atributos são propriedades/estado
Métodos é o comportamento
Classe conjunto de objetos semelhantes: atributos e métodos que resumem as
características comuns de vários objetos
A principal diferença entre classe e objeto é que objeto constitui uma entidade
concreta com tempo e espaço de existência, enquanto a classe é tão somente
uma abstração
Na prática, definimos uma classe, e depois a instanciamos por meio da criação
de um objeto.
Ex. Livro = classe
Biblia, Relatório, Dicionário são objetos
Criando objetos de classes predefinidas:
objetos em >>> import fractions
Python >>> frac1 = fractions.Fraction(1, 2)
>>> frac2 = fractions.Fraction(3, 4)
Classe = Fraction
Objetos = frac1 e frac2, que são instâncias da classe.

Definindo uma classe


Classe Point

Atributos: x e y
Métodos: setx(), sety(), get(), move()
Videoaula 4 - Programação Orientada a Objetos II
Sobrecarga de Operadores que são definidos diferentemente para múltiplas classes
operadores Exemplo: operador +
>>> 2 + 4
6
>>> [2, 3, 4] + [5]
[2, 3, 4, 5]
>>> 'abc' + 'de'
'abcde'
Como a linguagem Python é orientada a objetos, os operadores aritméticos são,
na essência, chamados a métodos definidos na respectiva classe do primeiro
operando
Assim, x+y é o equivalente a x.__add__(y), sendo que o método __add__() é
definido na classe de x
class Point():
def __init__(self, x=0, y=0):
self.x = x
self.y = y

def __repr__(self):
return '({},{})'.format(self.x, self.y)

def __add__(self, other):


if type(other) == Point:
return Point(self.x + other.x, self.y + other.y)
else:
return Point(self.x + other, self.y + other)
Outros
operadores

Herança Técnica fundamental em POO, usada para criar e organizar classes reutilizáveis.
Serve para reutilizar ou alterar os métodos de classes já existentes, bem como
adicionar novos atributos e métodos a fim de adaptar as classes a novas
situações.

Exemplo: suponha que queremos definir uma classe Lista, que contenha um
método adicional: choice(), que irá retornar aleatoriamente um elemento
existente na lista
Poderíamos definir uma classe MyList contendo todos os métodos necessários:
import random
class MyList:
def __init__(self, initial = []):
self.lst = initial
def __len__(self):
return len(self.lst)
def append(self, item):
self.lst.append(self, item)
Seria necessário, entretanto, redefinir mais de 30 métodos da classe list, a fim
de usá-la da mesma forma que uma lista.

Ao invés, podemos fazer uma "extensão" da classe list, por meio de herança:
import random
class MyList(list):
def choice(self):
return random.choice(self)
Dizemos que MyList é uma subclasse da classe list, e list é uma superclasse de
MyList.
Exercício Considere uma entidade Funcionário, que possui nome, data de admissão e
salário. Implemente sua classe, definindo também alguns métodos para
manipulação dos atributos. Em seguida, considere a entidade Gerente, que
também é um funcionário. Além dos atributos de funcionário, um gerente
também contém um bônus, que é uma porcentagem adicional aplicada no seu
salário. Implemente a classe Gerente como uma extensão de Funcionário.

FAZER FAZER
Texto-base - Introdução a Computação Usando Python (Ler:
Capítulo 8 – Programação Orientada a Objetos) - Ljubomir
Perkovic
Classes Se forem projetadas especificamente para determinada aplicação tornarão o
programa de aplicação mais intuitivo e mais fácil de desenvolver, depurar, ler e
manter.
namespaces propriedade das classes que permite expõe ao usuário os métodos que podem ser
detalhados aplicados aos objetos da classe (ou seja, instâncias da classe), mas encapsula o
modo como os dados contidos nos objetos são armazenados e como os métodos da
classe são implementados.

A finalidade do namespace é armazenar os nomes dos atributos de classe.

Ex.a função setx() é uma função definida no namespace Ponto. Ela apanha não
apenas um, mas dois argumentos: o objeto Ponto que está invocando o método e uma
coordenada x

não apenas as classes, mas cada objeto Python tem seu próprio namespace separado
Ex. Instanciamos (Um objeto é uma instância de uma classe) um novo objeto
do tipo Ponto e lhe damos o nome ponto, como em
>>> ponto = Point()
Como um namespace é associado ao objeto ponto, podemos usá-lo para armazenar
valores:
>>> ponto.x = 3
POO paradigma de desenvolvimento de software que alcança modularidade e
portabilidade de código, organizando programas de aplicação em torno de
componentes que são classes e objetos.
Definindo uma Antes de implementarmos a classe Ponto (ponto refere-se a um objeto do tipo Ponto),
nova classe precisamos decidir como ela deverá se comportar, ou seja, quais métodos ela deverá
aceitar.

Para criar um objeto Ponto, usaríamos o construtor padrão da classe Ponto =


construtores padrão list() ou int()para criar um objeto de lista ou de inteiro.
Métodos da o modo como desejamos que a classe Ponto se comporte.
Classe Ponto Ex. setx() e sety():
>>> ponto.setx(3)
>>> ponto.sety(4)
coordenadas definidas = método get():
>>> ponto.get()
(3, 4)
O método get() retornaria as coordenadas do ponto como um objeto tuple (tuple = list,
mas é imutável, é declarada entre (XX, XX, XX) é uma boa opção quando
queremos trabalhar com informações diferentes em uma
mesma variável e quando queremos que esses dados não
sofram alterações. ela não é completamente imutável,
pois quando armazena outro objeto, como uma lista, os
dados armazenados nesse elemento podem ser
modificados. É preciso entender, porém, que nesse caso não
é alterado a estrutura da tupla, apenas o conteúdo desse
objeto, que é passado por referência). Agora, para mover o ponto três
unidades para baixo, usaríamos o método move():
>>> ponto.move(0,-3)
>>> ponto.get()
(3, 1)
Também deverá ser possível alterar as coordenadas do ponto:
>>> ponto.sety(-2)
>>> ponto.get()
(3, -2)

método setx(): Aqui, temos um lugar para a coordenada x de um objeto Ponto. Ela é
armazenada no namespace associado a ela. O método setx() seria implementado desta
maneira:
def setx(ponto, coordx):
ponto.x = coordx

implementação O formato da instrução de definição de classe é:


da classe Ponto class <Nome da Classe>:
<variável da classe 1> = <valor>
<variável da classe 2> = <valor>
...
def <método da classe 1>(self, arg11, arg12, ...):
<implementação do método da classe 1>
def <método da classe 2>(self, arg21, arg22, ...):
<implementação do método da classe 2>
A primeira linha de uma definição de classe consiste na palavra-chave class
seguida por <Nome da Classe>, o nome dessa classe. Em nosso exemplo, o nome
foi Ponto.
As definições dos atributos de classe vêm após a primeira linha. Cada definição é
recuada em relação à primeira linha. Os atributos de classe podem ser métodos de
classe ou variáveis de classe. Na classe Ponto, quatro métodos de classe foram
definidos, mas nenhuma variável de classe. Uma variável de classe é aquela cujo
nome é definido no namespace da classe.

palavra usada para definir uma nova classe


reservada class A instrução class é muito semelhante à instrução def. Uma instrução def define uma
nova função e lhe dá um nome; uma instrução class define um novo tipo e lhe dá um
nome. Após a palavra-chave class vem o nome da classe, assim como o nome da
função vem após a instrução def. Outra semelhança com definições de função é a
docstring abaixo da instrução class: ela será processada pelo interpretador Python
como parte da documentação para a classe, assim como para funções.
Self primeiro argumento que se refere ao objeto Ponto invocando o método setx() é
denominado self, em vez de ponto.
O nome do primeiro argumento, na verdade, pode ser qualquer coisa; o que
realmente importa é que ele sempre se refira ao objeto que chama o método. Porém,
a convenção entre os desenvolvedores Python é usar o nome self para o objeto no
qual o método é chamado, e seguimos essa mesma convenção.
Namespace Espaços dentro da classe para colocar valores. cada objeto Python tem seu próprio
namespace separado
Instanciar Alocar um espaço na memória
Atributos da Métodos da classe, são definidos em um bloco de código endentado (anexado,
classe engrenado), logo abaixo da linha
Variáveis de Namespace de um objeto, ex. X e y, definida no namespace self
instância
Variável local Definida no namespace local da chamada de uma função
Função dir () namespaces de a e b deverão ter alguma relação com o namespace Ponto, que
contém os métodos de classe que podem ser invocados sobre os objetos a e b.
Podemos verificar isso usando a função dir() do Python,
Assim como para qualquer outro namespace, você pode usar a
função embutida dir() para descobrir todos os nomes definidos no
namespace list:
>>> dir(list)
['__add__', '__class__', '__contains__', '__delattr__',
__init__ Para poder usar um construtor Ponto() com argumentos de entrada, temos que incluir
explicitamente um método chamado _ _init_ _() à implementação da classe Ponto.
Quando acrescentado a uma classe, ele será chamado automaticamente pelo
interpretador Python sempre que um objeto for criado. Em outras palavras, quando o
Python executar
Point(3,4)
ele criará um objeto Ponto “vazio” primeiro e depois executará
self.__init__(3, 4)

* Como o método _ _init_ _() é chamado toda vez que um objeto é instanciado, o construtor
Ponto() agora deverá ser chamado com dois argumentos. Isso significa que a chamada do
construtor sem um argumento resultará em um erro:
Classe conteiner
Classe de fila
Operadores Ex. Operador +, seu método é __add__
sobrecarregado Ex. X.__add__(y) <==> x+y
Um operador sobrecarregado é um operador que foi definido para várias classes.
s
Para cada classe, a definição – e, portanto, o significado – do operador é diferente.
Assim, por exemplo, o operador + foi definido para as classes int, list e str. Ele
implementa adição de inteiros para a classe int, concatenação de lista para a classe
list e concatenação de strings para a classe str.

Se não sei qual o método do operador digito helo(int), help (str) ou hel(list)
Operado Método Número Lista e String
r
x+y x.__add__(y) Adição Concatenação
x-y x.__sub__(y) Subtração —
x*y x.__mul__(y) Multiplicação Autoconcatenação
x/y x.__truediv__(y) Divisão —
x // y x.__floordiv__(y) Divisão de —
inteiros
x%y x.__mod__(y) Módulos —
x == y x.__eq__(y) Igual a
x != y x.__ne__(y) Não igual a
x>y x.__gt__(y) Maior que
x >= y x.__ge__(y) Maior ou igual a
x<y x.__lt__(y) Menor que
x <= y x.__le__(y) Menor ou igual a
repr(x) x.__repr__() Representação de string canônica
str(x) x.__str__() Representação de string informal
len(x) x.__len__() — Tamanho da
coleção
<type>(x <type>.__init__(x) Construtor
)
__repr__ Representa string canônica
__eq__ Inplanta para que o operador == retorne True
Herança Uma classe também pode ser “estendida” em uma nova classe por meio da herança
de classe. Nesta seção, apresentaremos a segunda técnica.
Atividade
Avaliativa

Errei, coloquei VVVV e acertei 😊


Errei coloquei b (1, 2, 3, 4) e acertei 😊
Semana 3
Recursão: Chamamos a mesma função (em um loop) mas
com diferentes parâmetros.
Desenvolver funções recursivas auxiliam na proposta de soluções para
problemas complexos, mas é importante saber usá-las para que o programa
não seja afetado pelo desempenho.
Recursão Uma função é dita recursiva quando é definida em seus próprios termos, direta
ou indiretamente.
Por exemplo, podemos modificar a função abaixo, que imprime os elementos
de uma lista, para que seja recursiva:

1º chamamos a função inicial, ela imprimirá rec i = 0


2º dentro dessa função é verificado se o i <3 (if i < len(l))
3º Sendo menor, Imprime o elemento,
4º é feita a chamada recursiva (imprime_rec(l, i +1)), é aberto um novo escopo
dentro da função interior e são passados novamente os parâmetros.
Esses passos seguirão até a função se tornar falsa.
>>> l = [1, 2, 3]
>>> imprime_rec(l)
Efeitos da A cada chamada:
recursão - Empilham-se na memória os dados locais (variáveis e parâmetros) e o
endereço de retorno.
- A funcão corrente só termina quando a função chamada terminar.
- Executa-se a nova chamada (que também pode ser recursiva)
- Ao retornar, desempilham-se os dados da memória, restaurando o estado
antes da chamada recursiva
Mesmo resultado, mas com duplicação de código:

Quando usar? Dependendo do problema, a recursão pode ser bem ou mal empregada.
Geralmente, se existe uma versão simples e não recursiva da função, ela deve
ser usada.
Usamos recursão quando o problema pode ser definido recursivamente de
forma natural.
Como usar? Necessário definir 3 pontos:
1) Definir o problema de forma recursiva, ou seja, em termos dele mesmo
Ex. • n! = n * (n – 1)! (n-1 é a chamada recursiva)
2) Definir a condição de término (ou condição básica)
•n=0
3) A cada chamada recursiva, deve-se tentar garantir que se está mais próximo
de satisfazer a condição de término
• A cada chamada, n é decrementado (diminuir o valor de um número)
Exemplo Implementar uma função recursiva em Python para calcular o fatorial de um
número inteiro positivo passado como parâmetro.
Exercício Implementar uma função recursiva para calcular o n-ésimo termo da sequência
de Fibonacci.
Considere os três pontos definidos para o problema:
1) f(0) = 0, f(1) = 1, f(n) = f(n-1) + f(n-2) p/ n>=2
2) n=0 ou n=1
3) n deve ser decrementado a cada chamada
def fib_rec(n):
if n < 2: (todos resultado < 2 é = a ele mesmo, por
isso retorna n)
return n
else: (se ele for >= 2, devo usar a função abaixo)
return fib_rec(n-1) + fib_rec(n-2)

Quiz da video
aula

Como a condição é para todo n>=1, retorna-se 1, o programa sempre retornará


1
Video aula 6 Problema: n-ésimo termo de Fibonacci
Quem é melhor?

No caso acima, embora a função interativa tenha muito mais linhas de código,
ela retornará o resultado mais rápido porque não há empilhamento e
desempilhamento como na função recursiva
Recursão vs. Problema: n-ésimo termo de Fibonacci
Iteração Quem é melhor?
Estimativa de tempo para Fibonacci
Memoização Técnica de otimização que armazena os resultados de chamadas de funções
custosas, e que retorna o valor armazenado quando a função é chamada
novamente.
Exemplo: fatorial:

Dict() - dicionário, cria um vetor no qual os elementos colocados são chamados


de chaves (cada quadrado é uma chave única e aponta para um valor
armazenado na memória)

M[n] - é uma chave


N*fat(n-1) é o valor, que será armazenado na memória
m.get(n)! - utilizado para verificar se a chave já foi utilizada, se ela não foi
utilizada, retornará none
Quando isso acontece vamos para:
Else:
M[n] = n*fat(n-1)
return m [n]

Exemplo: n-ésimo termo da sequência de Fibonacci:

Exercícios Dada uma lista l de n números, implemente uma função recursiva que retorna o
maior elemento do conjunto.

Dada uma lista l de n números, implemente uma função recursiva que retorna a
soma de todos os elementos do conjunto.
QUIZ
VIDEOAULA

QUIZ
Atividade
Avaliativa
Errei correto é b (I e III)
Semana 4: pilhas, filas e árvores
Video aula 7 Pilhas
Chamada de Qual o resultado da execução da função A?
funções Qual a dificuldade para se fazer esse cálculo?
Possíveis soluções?

Dificuldade:
- O que estava sendo executado quando uma função foi interrompida?
- Para onde voltar agora que se chegou ao fim de uma função?
Solução:
- A cada chamada da função, armazenar o endereço de retorno (e.g. função e
número da linha).
- Como armazenar o endereço de retorno de chamadas sucessivas?
Solução: pilha!
Pilha Definição: estrutura para armazenar um conjunto de elementos, da seguinte
forma:
- Novos elementos sempre entram no 'topo' da pilha
- O único elemento que se pode retirar da pilha em um dado momento é o
elemento do topo

Principais usos: modelagem de situações onde é preciso 'guardar para mais


tarde' vários elementos e lembrar sempre do último elemento armazenado.
A cada comando call
- Empilha (push) o endereço para retornar depois
- Passa a executar a nova função
A cada comando return
- Desempilha (pop) o último endereço armazenado
- Passa a executar a partir do endereço desempilhado

Operações usuais:
- push(): empilha um elemento na pilha
- pop(): desempilha o elemento no topo da pilha
- top(): acessa o elemento do topo, sem desempilhá-lo
- empty(): verifica se a pilha está vazia
Texto base diferentemente da fila (FIFO), em uma pilha o último a entrar nela, é o primeiro a
sair (Last-In, First-Out — LIFO)
Onde as pilhas são usadas?
Talvez a mais famosa utilização de pilhas em computação esteja no gerenciamento
de chamadas de função de um programa. Uma pilha pode ser usada para manter
informações sobre as funções de um programa que estejam ativas, aguardando por
serem terminadas. Considere o seguinte exemplo:
1 def ola():
2 print "olá, "
3 mundo()
4
5 def mundo():
6 print "mundo!"
7
8 def olamundo():
9 ola()
10
11 olamundo()
A primeira função a ser chamada é a olamundo(), que por sua vez chama a função
ola(), então a função olamundo() é empilhada, pois seu término depende do
término da função ola(). Essa, por sua vez, chama a função mundo() e é
empilhada. Ao terminar a execução da função mundo(), a função ola() é
desempilhada e sua execução termina de onde havia parado (chamada à função
mundo()). Como não há mais nada a ser executado nessa função, sua execução
termina, e a função olamundo()é desempilhada e sua execução continua,
encerrando assim o programa.
Para adicionar um elemento no final de uma lista, basta usar
o método append(). E para remover o último elemento da lista?
.pop(tamanho_da_lista-1) é o que devemos fazer. E para obter o
tamanho da lista, podemos usar a função len(). Então:
1 def desempilha(self):
2 return self.dados.pop(len(dados)-1)
Ou então, podemos usar self.dados.pop(-1). O acesso ao índice -
1é a forma pythônica de se referir ao último elemento de uma
sequência.
1 def desempilha(self):
2 return self.dados.pop(-1)
Outra operação fundamental que deve estar disponível em uma
Pilha, é um método que retorne um booleano indicando se a
pilha está vazia. Um jeito bem simples seria usando a builtin
len() sobre a nossa lista interna self.dados e verificando se
ela retorna 0como resultado.
1 def vazia(self):
2 return len(self.dados) == 0

Pilha
1 class Pilha(object):
2 def __init__(self):
3 self.dados = []
4
5 def empilha(self, elemento):
6 self.dados.append(elemento)
7
8 def desempilha(self):
9 if not self.vazia():
10 return self.dados.pop(-1)
11
12 def vazia(self):
13 return len(self.dados) == 0
Exercício Implementar um programa em Python que realiza a conversão decimal para
binário usando pilha
Class Pilha():
def__init__(self):
self.data =[]

def push(self, x):


self.data.append(x)

def pop(self):
if len(self, data) > 0:
return self.data.pop(-1)

def top(self):
if len(self.data) > 0:
return self.data[-1]

def empty(self):
return not len(self.data) > 0

p = Pilha()
num = 13
while num >0:
resto = num % 2
num = num // 2
p.push(resto)

while not p.empty():


print(p.pop())
QUIZ

Videoaula 8 Filas
Problema: fila Quais operações possíveis?
de banco - Entrar na fila: quem entra, entra onde?
- Sair da fila: quem sai, sai de onde?
- Avançar na fila
Fila Definição: estrutura para armazenar um conjunto de elementos, que funciona
da seguinte forma:
- Novos elementos sempre entram no fim da fila
- O único elemento que pode ser retirado da fila, em um determinado
momento, é seu primeiro elemento

Para que serve?


Modelar situações em que é preciso armazenar um conjunto ordenado de
elementos, no qual o primeiro elemento a entrar no conjunto será também o
primeiro elemento a sair, e assim por diante.
Operações usuais:
- inserir(): insere um elemento no fim da fila
- remover(): remove o primeiro elemento da fila
- empty(): verifica se a fila está vazia
- top(): para verificar qual serio o elemento a ser retirado
Texto base é uma estrutura utilizada especificamente para armazenamento temporário de
dados na memória.
Diferentemente de uma lista, que também serve para esse fim, uma fila possui
regras quanto a qual elemento será retirado e onde será inserido um novo
elemento.
Em uma lista, é possível inserir elementos em qualquer posição e retirar quaisquer
elementos, não importando sua posição. Em uma fila, os novos elementos que são
inseridos são sempre posicionados ao final dela.

 .append(elemento): adiciona elemento ao final da lista;


 .insert(índice, elemento): insere elemento após a posição índice;
 .pop(índice): remove e retorna o elemento contido na posição índice.
Para inserir elementos, podemos usar o método append(), que insere um
elemento ao final de uma lista. Para a retirada de elementos, podemos utilizar o
método pop(x), que retira e retorna um elemento da posição x.
1 >>> fila = [10, 20, 30, 40, 50]
2 >>> fila.append(60) # insere um elemento no final
3 da fila
4 >>> print fila
5 [10, 20, 30, 40, 50, 60]
6 >>> print fila.pop(0) # remove o primeiro elemento
7 da lista
8 10
9 >>> print fila
10 [20, 30, 40, 50, 60]
>>> print fila.pop(0) # remove o primeiro elemento
11
da lista
12
20
13
>>> print fila
14
[30, 40, 50, 60]
15 >>> print fila.pop(0) # remove o primeiro elemento
16 da lista
30
>>> print fila
[40, 50, 60]

: “e se eu fizesse o contrário, inserindo no início e removendo do final, funcionaria


também como uma fila?” Sim, funcionaria. Pois, da mesma forma, teríamos a
política do primeiro a entrar, primeiro a sair também conhecida como First-In,
First-Out, ou simplesmente FIFO.
Fila
1 class Fila(object):
2 def __init__(self):
3 self.dados = []
4
5 def insere(self, elemento):
6 self.dados.append(elemento)
7
8 def retira(self):
9 return self.dados.pop(0)
10
11 def vazia(self):
12 return len(self.dados) == 0
Exercício Implementar um programa de gerenciamento de duas filas em um banco:
prioritária e normal. Seu programa deverá permitir que pessoas sejam inseridas
no fim de cada fila, dependendo da idade de cada uma (acima de 60 anos entra
na fila prioritária). A saída de pessoas da fila deve ocorrer da seguinte forma: a
cada duas pessoas que saem da fila prioritária, uma sai da fila normal.

FAZER FAZER FAZER


QUIZ

Video aula 9 Listas


Apesar de a linguagem Python oferecer um mecanismo simples e intuitivo para
criação e manipulação de listas, é importante conhecermos suas variações.
Dependendo do caso, será necessário escolher diferentes implementações para
melhorar a performance da aplicação.
Maneiras de se Há basicamente 4 maneiras de se implementar listas:
implementar - Sequencial vs. Encadeada
listas - Estática vs. Dinâmica
Sequencial vs. Na alocação sequencial os elementos são inseridos em sequência na memória,
Encadeada i.e. sequência física.
Permite acesso aos elementos por meio de índices
Na alocação encadeada os elementos não estão necessariamente em posições
adjacentes de memória, i.e. possuem uma sequência lógica.
Usa-se um ponteiro para o primeiro elemento, e cada elemento possui um
ponteiro para o Próximo

Quando utilizar sequencial ou encadeada?


- No caso da abordagem sequencial a vantagem é poder acessar os elementos
por meio dos índices, porém a memória pode ser mal utilizada.
- Na abordagem encadeada há otimização de memória, mas perde-se o acesso
direto aos elementos intermediários da lista.
Obs. a linguagem Python implementa listas usando a abordagem sequencial.
Estática vs. Variação quanto ao tipo de alocação de memória utilizado.
Dinâmica Na alocação estática toda memória é alocada mesmo sem ser utilizada.
Na alocação dinâmica a memória é alocada sob demanda, à medida que a lista
cresce
Quando utilizar alocação estática ou dinâmica?
- A alocação dinâmica permite gerenciar melhor a memória, sendo útil quando
não sabemos de antemão quantos elementos iremos armazenar na lista.
- A alocação estática é mais simples, pois a alocação é feita apenas uma vez.
Porém, pode ser que a memória seja alocada mesmo sem uso.
Obs. a linguagem Python implementa listas usando a abordagem dinâmica.
Outras Listas podem variar também em outros aspectos:
variações - Ordenada vs. não ordenada
- Linear vs. não linear
- Homogênea vs. heterogênea
Video aula 10 Árvores
Em listas, temos uma linearidade dos elementos: nós adjacentes, com a
identificação de sucessor e antecessor.
Diversas aplicações necessitam de estruturas mais complexas do que listas
lineares.
- Listas não lineares: árvores, grafos, etc.

Motivação Inúmeros problemas podem ser representados e tratados por árvores.


Permitem tratamento computacional eficiente quando comparadas a
estruturas mais genéricas como grafos (que são mais flexíveis e, portanto, mais
complexos).
Árvores são ótimas para busca.
Conceitos Uma árvore T é um conjunto finito de elementos denominados nós ou vértices,
tal que:
- T é uma árvore vazia, ou
- Existe um nó especial R, chamado raiz de T; os nós restantes constituem um
único conjunto vazio ou são divididos em m conjuntos não vazios que são as
subárvores de R, sendo que cada subárvore é, por sua vez, uma árvore.
Nós filhos, pais, tios, irmãos e avô.
Grau de saída de um nó e grau da árvore.
Nó folha e nó interior.
Nível e altura de um nó e altura de uma árvore.
Árvores binárias Árvores com grau 2, ou seja, cada nó pode ter 2 filhos, no máximo.

Árvores binárias Também chamadas 'árvores de pesquisa' ou 'árvores ordenadas'.


de busca (ABB) Definição: uma árvore binária com raiz R é uma ABB se:
- a chave (informação) de cada nó da subárvore da esquerda de R é menor do
que a chave do nó R
- a chave de cada nó da subárvore da direita de R é maior do que a chave do nó
R.
- as subárvores esquerda e direita também são ABBs.

Por que ABBs são eficientes?


Para se buscar em uma ABB:
- Em cada nó, compara-se o elemento buscado com o elemento presente
- Se menor, percorre-se a subárvore esquerda
- Se maior, percorre-se a subárvore direita.
- Desce-se verticalmente até as folhas, no pior caso, sem passar por mais de um
nó em um mesmo nível.
- Assim, no pior caso, a busca passa por tantos nós quanto for a altura da
árvore.
Exemplo de busca: elemento E

Texto base Árvores são estruturas de dados muito versáteis que são utilizadas na solução de
uma enorme gama de problemas, como na otimização de consultas e na indexação
de bancos de dados, na geração de códigos para compressão de dados, na análise
sintática de código por compiladores, na representação da estrutura de diretórios
em um sistema de arquivos, etc.

As árvores são estruturas de dados hierárquicas nas quais os dados são


armazenados por nós, sendo o primeiro destes chamado de nó raiz. Cada nó de
uma árvore possui um nó pai (exceto o nó raiz) e possui nós filhos (exceto os nós
folha).

Na figura acima, o nó raiz é o 8, e ele tem como filhos os nós de chave 4, 2, 9 e 1. O


nó 4 é pai dos nós 6 e 7. Estes dois, assim como os nós de chave 5, 2 e 1, são
chamados de folhas por não terem filhos (ou seja, seus filhos são nulos).
Uma árvore pode ser composta por uma ou mais subárvores. A figura abaixo
destaca as subárvores que compõem uma outra árvore.

Árvores Binárias
Uma árvores binária é um tipo especial de árvore, em que cada nó pode ter no
máximo 2 filhos, um à esquerda e um à direita do nó.

Árvores Binárias de Busca


As Árvores Binárias de Busca são árvores binárias com a seguinte propriedade:
todos os nós pertencentes à subárvore esquerda de qualquer nó possuem chave
menor que a chave do mesmo, e em que os nós da subárvore à sua direita
possuem chave maior que a chave do nó em questão. Essa propriedade deve ser
válida para todas as subárvores, possibilitando a realização de buscas mais
eficientes, pois podemos comparar a chave procurada com a chave de um nó e
decidir se devemos continuar a busca somente na subárvore à esquerda ou à
direita do nó, reduzindo assim a quantidade de nós a serem visitados na busca.

Implementação de uma Árvore Binária de Busca


Uma árvore nada mais é do que um conjunto de nós, e cada nó é um objeto com
uma chave, um valor e uma referência aos seus dois filhos (esquerdo e direito). A
chave serve para identificar o nó e o valor armazena os dados que o nó representa.
Por exemplo, em um sistema de arquivos que utiliza uma árvore para
representação da hierarquia de diretórios, a chave do nó poderia ser o nome do
arquivo e o valor poderia ser uma referência ao conteúdo do arquivo em si.
Em Python, podemos definir um nó (BSTNode – de Binary Search Tree Node) de
árvore da seguinte forma:
1 class BSTNode(object):
2 def __init__(self, key, value=None, left=None,
3 right=None):
4 self.key = key
5 self.value = value
6 self.left = left
self.right = right
Os campos left e right são as referências a outros nós, o campo key guarda a
chave utilizada para identificar o nó e value representa o valor que desejamos
armazenar nele.
A construção de um nó, com chave 42, sem valor armazenado e sem filhos pode ser
feita da seguinte forma:
1 root = BSTNode(42)
Esse código cria a seguinte árvore:

Se quisermos adicionar filhos ao nó 42, podemos fazer:


1 root.left = BSTNode(10)
2 root.right = BSTNode(90)
O que faz com que a árvore fique:

Se quisermos adicionar um filho esquerdo ao nó de valor 10, recém criado,


podemos fazer:
1 root.left.left = BSTNode(2)
O encadeamento feito acima gera a seguinte árvore:

Implementação da busca
O código abaixo implementa o algoritmo de busca descrito acima para a classe
BSTNode, através do método get:
1 class BSTNode(object):
2 def __init__(self, key, value=None, left=None,
3 right=None):
4 self.key = key
5 self.value = value
6 self.left = left
7 self.right = right
8
9 def get(self, key):
10 if key < self.key:
11 return self.left.get(key) if self.left
else None
12
elif key > self.key:
13
return self.right.get(key) if self.right
14
else None
else:
return self
Observe que este é um método recursivo, o que é condizente com a estrutura da
árvore, que também é uma estrutura recursiva, com um nó sendo definido com
base nele próprio. A função tem como condição de parada o nó ser nulo (None).
Quando isso acontece, significa que chegamos ao fim de um galho da árvore sem
ter encontrado a chave, isto é, a chave não existe na árvore.
Para realizar uma busca pela chave 4, devemos fazer o seguinte (onde tree é uma
referência ao nó raiz da árvore):
1 tree = BSTNode(8)
2 ...
3 found = tree.get(4)
4 if found:
5 print(found)
O método get apresentado acima poderia ser refatorado, evitando a duplicação de
código:
1 def get(self, key):
2 """Retorna uma referência ao nó de chave key
3 """
4 if self.key == key:
5 return self
6 node = self.left if key < self.key else self.right
7 if node is not None:
8 return node.get(key)
Inserção em uma Árvore Binária de Busca
Uma inserção em uma árvore binária de busca deve respeitar a propriedade
fundamental dessa estrutura, mantendo menores à esquerda e maiores à direita.
Para que isso seja possível, é interessante que a interface de programação da nossa
árvore ofereça um método que faça a inserção de um elemento garantindo tal
propriedade.
O algoritmo para a inserção funciona de forma semelhante à busca. Vamos
descendo na árvore com o objetivo de encontrar o local certo onde o elemento
deve ser inserido, verificando sempre se devemos continuar o percurso na
subárvore à esquerda ou à direita do nó. Diferentemente da busca, na inserção
nossa travessia termina ao encontrarmos um nó folha, no qual o elemento a ser
inserido é adicionado como filho — à esquerda, se o elemento a ser adicionado for
menor que o nó, ou à direita, caso contrário.
Implementação da inserção
Assim como a busca, o método para inserção também pode ser implementado de
forma recursiva. Veja o código abaixo:
1 class BSTNode(object):
2 def __init__(self, key, value=None, left=None,
3 right=None):
4 self.key = key
5 self.value = value
6 self.left = left
7 self.right = right
8
9 def add(self, node):
10 if node.value < self.value:
11 if self.left is None:
self.left = node
12
else:
13
self.left.add(node)
14
15 else:
16 if self.right is None:
17 self.right = node
18 else:
self.right.add(node)
Como podemos ver no método add, a inserção percorre a árvore até encontrar
uma folha onde o novo nó pode ser inserido. Isso ocorre quando, no percurso da
árvore, encontramos um nó que não possui um filho do lado esquerdo (quando o
valor que estivermos inserindo for menor que o nó) ou do lado direito (quando o
valor do nó que estivermos inserindo for maior que o valor do nó).
Novamente, para eliminar um pouco a repetição de código, o método add poderia
ser refatorado para:
1 def add(self, key):
2 """Adiciona elemento à
3 subárvore
4 """
5 side = 'left' if key <
6 self.key else 'right'
7 node = getattr(self,
8 side)
9 if node is None:
setattr(self, side,
BSTNode(key))
else:
node.add(key)
Porém, nosso algoritmo de inserção um problema: ele pode deixar desbalanceada
a árvore após algumas inserções.
Balanceamento de árvore
Manter uma árvore bem organizadinha é um pouquinho mais complicado, pois é
necessário que mantenhamos o balanceamento da árvore. Para entendermos
melhor esse conceito, vamos ver um exemplo que ilustra o pior caso em uma
árvore binária de busca não balanceada, que ocorre quando os elementos são
inseridos de forma ordenada:
Para evitar situações como esta, existem algoritmos que são usados durante a
inserção de um elemento e que promovem uma reorganização dos nós da árvore
para que seu layout fique mais balanceado. Para compreender melhor o conceito
de balancemento de uma árvore, precisamos compreender antes o conceito de
altura de uma árvore, que é definido pela quantidade de arestas no caminho mais
longo entre a raiz e as folhas. A figura abaixo ilustra uma árvore de altura 3, que é a
quantidade de arestas entre a raiz e a folha mais distante dela (de valor 4).
Uma árvore balanceada é uma árvore na qual a altura de uma subárvore não pode
ser muito maior do que a altura da sua irmã. Para manter uma árvore balanceada,
após cada inserção, devemos verificar se a árvore permanece balanceada e, em
caso negativo, ela deve ser reorganizada, trocando os encadeamentos entre os
nós. Isso pode ser um pouco custoso, mas compensa no momento de fazer a busca
por algum elemento. Os tipos mais conhecidos de árvores binárias balanceadas
são: as Árvores AVL e as Árvores Rubro-Negras.
Remoção de A remoção de um elemento é um pouco mais complicada do que a inserção e
busca de um elemento. Existem 3 situações diferentes e que requerem diferentes
um abordagens para a remoção de um elemento:
elemento 1. o nó a ser removido é um nó folha
2. o nó a ser removido possui somente um filho
3. o nó a ser removido possui dois filhos

Remoção de um nó folha
Imagine que desejamos remover o nó 4 da árvore acima. Para isso, basta fazer com
que o campo left do nó 6 passe a apontar para None, e o coletor de lixo elimina o
nó da memória pra gente em algum momento.
Remoção de um nó que possui um filho
Agora, desejamos remover o nó 10. Para isso, temos que fazer com que o nó pai do
nó 10 (8) passe a apontar para o único filho de 10 (14).
Remoção de um nó que possui dois filhos
Este é o caso mais complicadinho. Imagine que queremos remover o nó 3, que
possui como filhos a subárvore que tem como raiz o nó 1 e a subárvore do nó 6.
Para remover o nó 3, é preciso que algum dos outros nós assuma o papel de raiz da
subárvore. O melhor candidato para assumir esse posto é o nó cuja chave é mais
próxima da chave do nó a ser removido.
Uma forma prática de encontramos tal valor é procurar o menor valor contido na
subárvore à direita do nó a ser removido, isto é, o nó mais à esquerda da
subárvore à direita. Na árvore do exemplo, esse nó é o nó de chave 4.
Implementação
O código abaixo implementa a remoção de um elemento. O método remove
primeiramente encontra o nó a ser removido — é isso que as chamadas recursivas
fazem — para depois fazer a remoção do elemento no código dentro do else. O
método _min retorna o nó que contém o menor elemento em uma subárvore, isto
é, o elemento mais à esquerda na subárvore em questão. Já o método
_remove_min retira da subárvore o menor elemento, sendo usado para remover de
sua posição o elemento que será utilizado como substituto ao elemento a ser
removido, no caso deste possuir dois filhos.
1 class BSTNode(object):
2
3 def __init__(self, key, value=None, left=None,
right=None):
4 self.key = key
5 self.value = value
6 self.left = left
7 self.right = right
8
9 def remove(self, key):
10 if key < self.key:
11 self.left = self.left.remove(key)
12 elif key > self.key:
13 self.right = self.right.remove(key)
14 else:
15 # encontramos o elemento, então vamos
removê-lo!
16
if self.right is None:
17
return self.left
18
if self.left is None:
19
return self.right
20 #ao invés de remover o nó, copiamos os
21 valores do nó substituto
22 tmp = self.right._min()
23 self.key, self.value = tmp.key, tmp.value
24 self.right._remove_min()
25 return self
26
27 def _min(self):
28 """Retorna o menor elemento da subárvore que
29 tem self como raiz.
30 """
31 if self.left is None:
32 return self
33 else:
34 return self.left._min()
35
36 def _remove_min(self):
37 """Remove o menor elemento da subárvore que
38 tem self como raiz.
39 """
40 if self.left is None: # encontrou o min, daí
pode rearranjar
return self.right
self.left = self.left._removeMin()
return self
Os dois primeiros ifs dentro do else (linhas 16 e 18) tratam o caso em que o nó a
ser removido não possui filhos ou possui somente um filho. Observe que se o nó
não possuir filho à direita, o filho à esquerda é retornado ao chamador, que é o
próprio método remove na linha 11 ou 13.
Da linha 21 em diante tratamos o caso em que o nó a ser removido possui os dois
filhos. A linha 21 obtém o elemento que irá substituir o elemento a ser removido. A
linha seguinte copia os valores do nó substituto para o nó a ser “removido” (repare
que acabamos não removendo o nó, mas sim copiando os valores do nó substituto
para o seu lugar). Depois disso, removemos o elemento substituto de sua posição
original, chamando o método _remove_min.
Texto de apoio Python 3 – conceitos e aplicações
Hashable: o Diz-se que um objeto é hashable quando ele tem um valor hash que não se
altera durante o ciclo de vida do objeto e que pode ser comparado ao hash de
que é isso? outros objetos.
Conjuntos Por definição, dentro do conjunto, só haverá uma ocorrência de cada elemento,
independentemente de quantas vezes se tente adicioná-lo.
Um conjunto pode ser criado de duas maneiras: utilizando dados entre chaves, { }
ou a função set. É possível existir um conjunto vazio. E apenas objetos hashable
podem ser membros de um conjunto.
existem dois tipos de conjunto: o set e o frozenset. Em praticamente tudo eles são
iguais, a única e fundamental diferença entre ambos é que o frozenset é imutável
e, uma vez criado, não pode ter seus membros alterados, incluídos ou removidos.

>>> a = {1, 2, 3, 4, 5} # cria um set com cinco elementos


>>> a {1, 2, 3, 4, 5}
>>> type(a) <class ‘set’>
>>> len(a) 5 # a função len() pode ser usada
>>> b = set(‘12345’) # caso 2
>>> b
{‘1’, ‘4’, ‘5’, ‘3’, ‘2’} # cria um novo set com cinco elementos
>>> type(b) <class ‘set’>
>>> c = {‘12345’} # caso 3
>>> c
{‘12345’} # cria um conjunto com um elemento
>>> type(c) <class ‘set’>
>>> d = {} # este comando não cria um conjunto
>>> type(d) # vazio, mas sim um dicionário
<class ‘dict’>
>>> d = set() # conjuntos vazios são criados assim
>>> type(d) <class ‘set’>
É possível criar um conjunto vazio e adicionar elementos posteriormente,
porém, deve-se tomar um cuidado. Conjuntos vazios devem ser criados com a
função set sem passar qualquer parâmetro. O uso de chaves sem conteúdo criará
um dicionário vazio, e não um conjunto, como já mostrado.
Conteúdos de listas e tuplas podem ser utilizados para produzir conjuntos, e
vice-versa. O Exemplo 6.3 mostra a conversão de uma lista para conjunto. Note
que, ao fazer essa operação, os elementos repetidos presentes na lista foram
eliminados no conjunto. Essa é uma maneira conveniente de eliminar repetições de
valores em listas e tuplas, pois é possível converter de volta o conjunto para uma
lista ou tupla.
QUIZ COM
OBJETIVO
EDUCACIONAL
Atividade
avaliativa

Errei, correto é e. Pilha


Errei, correto d. Apenas I
Errei cooreto é a (append (x) e pop (-1)

SEMANA 5 - Pilhas, filas e árvores


Videoaula 11 - Algoritmos clássicos de ordenação I
Ordenação Ordenação é largamente utilizada
Ex. Função sort ()
- Listas telefônicas e dicionários
- Grandes sistemas de BD e processamento de dados - Etc.
Algoritmos de ordenação são ilustrativos (escolho o melhor para determinada
situação)
- Como resolver problemas computacionais
- Como lidar com estruturas de dados
- Como desenvolver algoritmos elegantes e como analisar e comparar seus
desempenhos

Definição: organizar uma sequência de elementos de modo que os mesmos


estabeleçam alguma relação de ordem.
Diz-se que os elementos k1, ..., kn estarão dispostos de modo que k1 ≤ k2 ≤ ... ≤
kn.

Ocasionalmente, dá menos trabalho buscar um elemento em um conjunto


desordenado do que ordenar primeiro e depois buscar. (se for uma única busca,
é mais fácil num deseordenado)
Por outro lado, se a busca for uma operação frequente, vale a pena ordenar
(pode ser feita apenas uma vez).
Depende das circunstâncias!
Terminologia Ordenação de registros, em que cada registro é ordenado por sua chave.
Ordenação interna vs. externa:
- Interna: se todos os registros cabem na memória principal.
- Externa: se os dados não cabem na memória principal, precisando ser
armazenados em disco.
Ordenação estável: ordem original de registros com chaves iguais é preservada
após a ordenação. Ex. 7,2,3,3,5,6,1,3 – ao ordenar o 1º 3 deve aparecer antes
do 2º e do 3º (1,2,3,3,3,5,6,7)
Bubble sort Um dos métodos mais conhecidos e intuitivos.
Ideia básica:
- Percorrer o conjunto várias vezes.
- A cada iteração, comparar cada elemento com seu sucessor (v[i] com v[i+1]) e
trocá-los de lugar caso estejam na ordem incorreta
Bubble sort: passo 1
• Vetor inicial
• X = (25 , 57 , 48 , 37 , 12 , 92 , 86 , 33)
• X[0] com X[1] (25 com 57) não ocorre permutação
• X = (25 , 57 , 48 , 37 , 12 , 92 , 86 , 33)
• X[1] com X[2] (57 com 48) ocorre permutação
• X = (25 , 48 , 57 , 37 , 12 , 92 , 86 , 33)
• X[2] com X[3] (57 com 37) ocorre permutação
• X = (25 , 48 , 37 , 57 , 12 , 92 , 86 , 33)
• X[3] com X[4] (57 com 12) ocorre permutação
• X = (25 , 48 , 37 , 12 , 57 , 92 , 86 , 33)
• X[4] com X[5] (57 com 92) não ocorre permutação
• X = (25 , 48 , 37 , 12 , 57 , 92 , 86 , 33)
• X[5] com X[6] (92 com 86) ocorre permutação
• X = (25 , 48 , 37 , 12 , 57 , 86 , 92 , 33)
• X[6] com X[7] (92 com 33) ocorre permutação
• X = (25 , 48 , 37 , 12 , 57 , 86 , 33 , 92)
Agora se faz com os elementos anteriores, isso é n-1 elementos
• Vetor após passo 1
• X = (25 , 48 , 37 , 12 , 57 , 86 , 33 , 92)
• X[0] com X[1] (25 com 48) não ocorre permutação
• X = (25 , 48 , 37 , 12 , 57 , 86 , 33 , 92)
• X[1] com X[2] (48 com 37) ocorre permutação
• X = (25 , 37 , 48 , 12 , 57 , 86 , 33 , 92)
• X[2] com X[3] (48 com 12) ocorre permutação
• X = (25 , 37 , 12 , 48 , 57 , 86 , 33 , 92)
• X[3] com X[4] (48 com 57) não ocorre permutação
• X = (25 , 37 , 12 , 48 , 57 , 86 , 33 , 92)
• X[4] com X[5] (57 com 86) não ocorre permutação
• X = (25 , 37 , 12 , 48 , 57 , 86 , 33 , 92)
• X[5] com X[6] (86 com 33) ocorre permutação
• X = (25 , 37 , 12 , 48 , 57 , 33 , 86 , 92)
• X[6] com X[7] (86 com 92) não ocorre permutação
• X = (25 , 37 , 12 , 48 , 57 , 33 , 86 , 92)
Depois do primeiro passo
- Vetor: (24, 48, 37, 12, 57, 86, 33, 92)
- O maior elemento (92) está na posição correta
Para um vetor de n elementos, são necessárias n-1 iterações.
A cada iteração, os elementos vão assumindo suas posições corretas.

Implementação em Python

O for de fora itera os passos de 1 a n-1 e o for de dentro faz com que percorra
os elementos até a penúltima posição
If (se o v[j] for maior que o v[j+1], isto é o elemento da esquerda for maior que
o elemento da direita é feita a troca dos dois elementos (v[j], v[j+1] por v[j+1,
v[j])
Insertion sort: Ideia básica:
Ordenação por - Ordenar o conjunto inserindo os elementos em um subconjunto já ordenado.
inserção, - No i-ésimo passo, inserir o i-ésimo elemento na posição correta entre x[0], ...,
inserimos o o x[i-1], que já estão em ordem.
elemento em - Realocar elementos
um
subconjunto já
ordenado
1º comparo o segundo elemento com o primeiro, se o segundo for maior, não é
feito nada, assim segue a lista. Quando chega em um elemento que é menor que
o anterior, armazenamos o elemento (15) em uma variável auxiliar e deslocamos
os demais elementos anteriores até que o elemento (15) seja maior que o
elemento anterior

• X = (44 , 55 , 12 , 42 , 94 , 18 , 06 , 67)
• passo 1 (55) 44 55 12 42 94 18 06 67
• passo 2 (12) 12 44 55 42 94 18 06 67
• passo 3 (42) 12 42 44 55 94 18 06 67
• passo 4 (94) 12 42 44 55 94 18 06 67
• passo 5 (18) 12 18 42 44 55 94 06 67
• passo 6 (06) 06 12 18 42 44 55 94 67
• passo 7 (67) 06 12 18 42 44 55 67 94

For: é para percorrer o vetor da posição 1 até o tamanho da lista (for i in range
(1, len(v)); (como a lista começa com 1, o elemento na posição 0 fica parado,
como se estivesse já ordenado
Então o x recebe o 2º elemento e insere na lista;
J é para comparar com o x
Enquanto o j >= 0 e x< v[j], faço o descolamento.
Após o while terminar, é feita a inserção do x na sua posição correta
QUIZ

VIDEO AULA 12 ALGORITMOS CLÁSSICOS DE ORDENAÇÃO II


Merge sort Também chamado de ordenação por intercalação.
Mais complexo Ideia básica: dividir para conquistar
que os - Um vetor v é dividido em duas partes, recursivamente.
anteriores - Cada metade é ordenada e ambas são intercaladas formando o vetor
porém mais ordenado.
eficiente - Usa um vetor auxiliar para intercalar.

Temos uma lista,


1º que dividimos em 2 partes iguais (subvetor), dividimos esses subvetores ao
meio, que é dividido novamente até sobrar subvetores individuais.
2º inicia a intercalação, que junta os subvetores individuais em pares já
ordenados, assim, ao ir juntando os pares, já vai ficando ordenado.

A intercalação facilita a ordenação, ao juntar os pareces de 4, há 2 ponteiros


que vão comparando cada um dos elementos e ordenando.
1º Na definição da função, coloco o vetor (v) e também duas variáveis (ínicio e
fim), o início =0 e o fim =len(v)-1
2º São feitas chamadas recursivas colocando o meio (meio = (ini+fim)//2) e
aplica a recursão do inicio até o meio (merg)sort(v, ini, meio) e do meio até o
fim (v meio+1, fim), vão sendo feitas as recursões até o ínicio seja => que o fim
3º após todas as divisões por recursão, entra na fase de intercalação, usamos
então 2 vetores auxiliares L e R, que recebem uma submissa do vetor original (L
= v(ini:meio+1) e R = v(meio + 1: fim+1) o fim + 1 é usando para incluir o último
valor
 É colocado um valor de sentinela para cada vetor, que são os valores
máximos que cada vetor pode ter
A idéia de implementar um valor sentinela é para no passo seguinte, facilitar a
incrementação para que não haja i e j maiores do que devem
4º Pego um valor de k para percorrer do inicio até fim + 1
3º então é feita a escolha entre os valores da esquerda e da direita para inserir
no vetor ordenado(if L[i] <= R[j]...)
- Algoritmo também baseado na estratégia dividir para conquistar.
Ideia básica:
- Dividir o vetor em dois vetores menores que serão ordenados
independentemente e combinados para produzir o resultado final.

1º passo:
Escolha de um elemento pivô x, colocando-o em sua posição correta
2º Ordenar de forma que os elementos à esquerda do pivô são menores ou
iguais a ele e os elementos à direita são maiores ou iguais a ele
- Percorrer o vetor v da esquerda para direita até v[i] >= x; e da direita
para esquerda até que v[j] <= x.
- Trocar v[i] com v[j], incrementar i, decrementar j
- Quando i e j se cruzarem, a iteração finaliza, de forma que v[0]...v[j] são
menores ou iguais a x e v[i]...v[n-1] são maiores ou iguais a x

3º PASSo:
Ordenar subvetores à esquerda e à direita do elemento pivô.
Ex. 25 57 35 37 12 86 92 33
São colocados 2 ponteiros nas posições i = 0 e j = l + 1
Para encontrar o pivô, uso a fómula v=0+7)/2] = 3,5 = 4 – elemento da posição 4
= 37
Começo a incrementar i até que ele seja maior ou igual a 37, o mesmo o ocorre
o j, que deve ser <= 37. Quando são encontrados os elementos, eles são
trocados de posição entre si
Então incremento o i e p j para a posição seguinte.
Quando todos são feitos ficamos com os elementos d j na posição menor que o
pivô e i na posição maior que o pivô.
Feito isso, não é mais necessário trocar elementos dos vetores i com j.
Ficando 2 subvetores separados, nos quais deve ser feito o mesmo processo nos
subvetores separados
Exercício:
Fazer as ordenações dos subvetores, repetindo o processo 25 33 35 12 37 86 92
57

QUIZ

VÍDEO AULA 13 ALGORTIMOS CLÁSSICOS DE ORDENAÇÃO III


Heap sort Utiliza uma estrutura heap (amontoar) para ordenar os elementos.
Um heap é uma estrutura de dados em que há uma ordenação dos elementos:
É o maiss representação via árvore binária.
complexo e
rápido

Um heap observa conceitos de ordem e de forma.


- Ordem: o item de qualquer nó deve satisfazer uma relação de ordem com os
itens dos nós filhos.
- Heap máximo: pai >= filhos (usado no heap sort)
- Heap mínimo: pai <= filhos
- Forma: árvore binária tem que ser completa até o penúltimo nível, sendo que
no último nível os nós têm que estar agrupados à esquerda.
O segundo não é heap porque o 1 deveria estar mais a esquerda
Não é heap porque o filho 16 é maior que o pai 14 e no outro o filho 8 é maior
que o pai 4

O heap pode ser representado por um vetor, colocamos o pai mais a esquerda e
vamos colocando os filhos em seguida

Para encontrar os filhos do nó k:


Filho esquerdo = 2k +1 (se quiser encontrar o filho de 10, ele é o nó 2, então
2.2+1 = 5, o filho a esquerda é o nó 5, que no caso é o 9)
Filho direito = 2k + 2 (filho de 10 = 2.2+2 = 6, o nó 6 é o elemento 3)
Pai do nó k: (k-1)/2 (se quero saber quem é o pai do nó 4, ele está na posição 8,
então (8-1)/2 = 3, que é o elemento 7)
Folhas = n/2 em diante (no caso acima como n= 10, então as folhas são a partir
do elemento 5)
A estrutura heap pode ser usada para ordenar um vetor.
-Construir um heap máximo
-Trocar a raíz (maior elemento) com o elemento da última posição do vetor
-Diminuir o tamanho do heap em 1
-Rearranjar o heap máximo (agora com n-1 elementos), se necessário
-Repetir o processo n-1 vezes.
Como abaixo:
O processo termina até todos os elementos terem sido incluídos no vetor de
forma ordenada.
É necessário:
-Saber construir um heap a partir de um vetor qualquer.
-Saber como rearranjar o heap, i.e., manter a propriedade do heap máximo.
Como abaixo:

Pode ser feito por meio de vetores, com as regras citadas acima
A construção do heap envolve chamar o procedimento rearranjar heap de
forma ascendente para os n/2 – 1 (porque a partir do nó n/2 é folha) nós da
árvore (nós não folha).
Com isso, ao chamar pela última vez o procedimento para a raíz, teremos o
heap máximo construído.
Por fim faço o heap sort e troco as posições do 16 e do 1, e em seguida vou
fazendo o mesmo até reordenar
QUIZ

BUSCA Ordenar um conjunto antes de realizar a busca permite melhorar o


desempenho do algoritmo
Busca linear é feita percorrendo todos os elementos da lista
Em Python, a busca por um elemento em uma lista pode ser feita de duas
formas:
- Com o in (está contido) - Com o index()(mostra a posição da do elemento na
lista)
>>> l = [7, 6, 3, 4] >>> l = [7, 6, 3, 4]
>>> 3 in l >>> l.index(3)
True 2
>>> 8 in l >>> l.index(5)
False erro
Busca Linear Importante notar que se a lista não estiver ordenada, a única maneira de
implementar o operador in e o método index() é por meio de uma "varredura"
item a item na lista até encontrá-lo.
No pior caso, o algoritmo percorre toda a lista, ou seja, seu tempo de execução
é proporcional ao tamanho da lista.
Busca Binária Se os elementos na lista são comparáveis é possível ordená-los inicialmente,
usando algum método de ordenação (e.g. método sort()):
>>> l.sort() (está na própria biblioteca Python)
>>> l [3, 4, 6, 7]
Com isso, podemos aplicar algoritmos de busca mais eficientes, como a busca
binária

Ao invés de comparar inicialmente o elemento desejado com o primeiro


elemento (índice 0), suponha que o comparamos com o elemento armazenado
num índice i qualquer. (ex. - i = 5 Se procuro 5)
Teremos 3 possibilidades:
- l[i] == elemento desejado -> finaliza a busca
- l[i] > elemento desejado -> elemento pode estar à esquerda
- l[i] < elemento desejado -> elemento pode estar à direita

Exemplo: selecionar o meio da lista

Como o meio o elemento é 6, que é menor que 12, é desconsiderado todos os


elementos do lado esquedo de 6 e então a lista (6,9,10,12,15) é dividida e
compara-se o 12 com o elemento do meio, que no caso é o 10, como 10 é
menor que doze, desconsideramos todos os elementos da parte esquerda de
10....
Implementação em Python de uma função recursiva que realiza a busca binária
em uma lista.

Def busca_binaria(l, x, inicio, fim) #os parâmetros são l (lista) , x (elemento que
procuro), inicio e fim que indicam o começo e o final da lista

Meio = (inicio + fim) // 2

If fim < inicio:


Return -1

If x ==l(mais):
Return meio

If x < l(meio):
Return busca binaria(l, x, inicio, meio –1)

If x > l(meio):
Return busca binaria(l, x , meio + 1, fim)

Python Console
>>> import random
>>> l = random.simple (range(10), 5)
>>>l
[2,1,6,8,9]
>>> l.sort() # ordena a lista
[1, 2, 6, 8, 9]

>>> busca_binaria (l, 2, 0, 4) #lista que procuro, posição que procuro, inicio e
final
QUIZ

QUIZ COM
OBJETIVO
EDUCACIONAL

ATIVIDADE
AVALIATIVA
ERREI, correto é e. Busca sequencial
Errei, o correto é d. Mergesort
ERREI, correto é Quicksort
ERREI, correto c. Busca binária
ERREI, correto é b. heapsort

SEMANA 6 PROCESSAMENTO DE ELEMENTOS DA WEB


VIDEOAULA 15 CONCEITOS FUNDAMENTAIS DA WEB
WWW A Internet é uma rede global que conecta computadores ao redor do globo.
(programa) = Permite a troca de mensagens entre programas conectados a ela.
sistema de
documentos A World Wide Web (WWW ou simplesmente Web) é um sistema distribuído de
ligados por documentos ligados por hiperlinks e armazenados em servidores Web
hiperlink e espalhados pela Internet.
Internet (fisico)
= conecta
computares
Servidor = A comunicação entre programas tipicamente ocorre quando um dos programas
serve requisita um recurso a outro programa.
O provedor do recurso é chamado de servidor Web e quem requisita/recebe o
e cliente = recurso é chamado de cliente.
requisita O navegador é um cliente Web, e além de requisitar um recurso, também
processa o recurso, exibindo o conteúdo na tela.
URL (endereço Para fazer a requisição de um recurso, é necessário:
do recurso = -Identificar o recurso
pedido, feito -Localizar o recurso
pelo cliente) -Usar uma linguagem padronizada de comunicação

A Web oferece funcionalidades para identificar e localizar um recurso, além de


um protocolo de comunicação que permite a troca de mensagens entre cliente e
servidor.

A URL (Uniform Resource Locator) oferece um identificador único para cada


recurso na Web, definindo também sua localização e o protocolo de
comunicação.

Scheme O esquema define como acessar o recurso. No exemplo anterior, usamos o


(esquema = protocolo HTTP.
protocolo Existem outros protocolos conhecidos: SUBSTRING
cliente/servidor -HTTPS (conexão segura)
) -FTP (para arquivos)
- MAILTO (para e-mail)
-FILE
- etc.
Host = O host é o nome do servidor que armazena o recurso/documento.
endereço do O host é transformado em um endereço IP a partir de uma consulta a um servidor
servidor de nomes (DNS), realizada pelo cliente.
Tanto o hostname como o IP são únicos e localizam o servidor na rede.
Path = caminho O path em uma URL especifica o caminho relativo do recurso a partir de um
no servidor diretório predefinido (diretório raiz do servidor Web). Uma vez localizado o
para encontrar servidor, é necessário especificar em qual subdiretório do servidor o recurso se
o recurso encontra.

HTTP

Http://www.univesp.br
Http = protocolo
www.univesp.br = hostname

Padrão de mensagens requisição/resposta entre cliente e servidor


Por padrão, usam-se conexões TCP/IP na porta 80

Mensagem típica de requisição:

Mensagem típica de resposta:


Fluxo de
requisições

Quando faço a pesquisa:


1º o Navegador web envia ao Servidor DNS o hostname (www.univesp.br)
2º o Servidor DNS retorna o IP correspondente (código)
3º Usando o IP, o navegador faz a solicitação ao Servidor Web
4ª O servidor Web retorna a página html requisitada
QUIZ

Domain Name System (Sistema de Nomes de Domínios)


VIDEOAULA HTML E JSON
16
Intercâmbio de A troca de informações entre diferentes aplicações permite que programas
dados = sejam bem aceitos e difundidos.
PADRONIZAÇÃ Para viabilizar essa comunicação, é necessário que as aplicações sigam
O IMPORTANTE determinados padrões previamente especificados.
HTML o conteúdo de uma típica troca de mensagens entre cliente e servidor usando o
protocolo HTTP:

Se o cliente for um navegador Web será capaz de interpretar o conteúdo da


resposta, apresentando-o na tela de maneira formatada.

Além do conteúdo em si, uma página Web contém elementos que definem o
layout, cabeçalhos, imagens, vídeos, hiperlinks, etc. Exemplo:

NO NAVEGADOR CLICAR: VIEW – DEVELOPER - RESOURCE

HTML (HyperText Markup Language) é uma linguagem que permite definir


cabeçalhos, listas, imagens, vídeos, hiperlinks, etc. em uma página Web.
Utilizam-se elementos HTML, cada um com uma função específica.

Um elemento possui o seguinte formato:


<nome_tag atributo=”valor”>conteudo</nome_tag>

https://developer.mozilla.org/pt-BR/docs/Web/HTML/Element - ELEMENTOS
DO HTML

Um elemento pode estar contido em outro elemento: aparece entre as tags de


início e fim.
<head><title>W3C Mission
Summary</title></head>
Os elementos de um documento HTML formam uma árvore hierárquica, como
veremos a seguir.

Um elemento âncora serve para criar textos de hiperlink:


<a href=”URL”>Texto de hiperlink</a>

HREF = Hypertext Reference

onde "URL" é o endereço (relativo ou absoluto) do recurso que foi ancorado.

JSON JSON (JavaScript Object Notation) define um formato padrão para descrever,
em formato texto, objetos como dicionários, listas, números e strings. A maioria
das linguagens de programação possui bibliotecas para produzir e processar
dados no formato JSON.
As linguagem C++, java entendem as especificações do json e podem rodar elas.
O módulo json da biblioteca padrão contém funções para codificar objetos
Python em JSON e vice-versa.

Dumps:
quiz

VIDEOAULA Python WWW API


17 Módulos de Python que permitem que façamos manipulação
de páginas da web.
Módulo O módulo urllib.request permite requisitar e receber recursos da Web, de modo
urllib.request similar a um navegador.
A função urlopen():
-recebe como parâmetro uma URL
-formula uma requisição HTTP que será enviada ao servidor especificado na URL
-obtém e retorna uma resposta HTTP completa do servidor.

No python:
1º importar biblioteca urlib.request
2º importar biblioteca urlopen
3º defino a função get source
4º defino a variável response
5º obtenho seu resultado por meio da response.read
6º Return html.decod (decodifica o conteudo encontrado e envia para fora da
função uma string quer contém os elementos html do recurso requisitado)
7º html == getsource http://univesp.org.br
Módulo O módulo html.parser, por meio da classe HTMLParser, permite processar
html.parser elementos HTML de uma página Web.
O método feed() da classe HTMLParser recebe como entrada uma página HTML
no formato string, e para cada 'token' lido (tags de início, tags de fim, texto,
etc.), executa um handler correspondente.

Inicialmente, cada handler é implementado para não fazer nada. Assim,


executamos o código abaixo, o qual não gera nenhuma saída visível:

Para trazer funcionalidade a um determinado handler, precisamos sobrescrever


o método correspondente, estendendo a classe HTMLParser.
quiz
QUIZ COM
OBJETIVO
EDUCACIONAL

ATIVIDADE
AVALIATIVA

ERREI, CORRETO É: B - HTTPS


ERREI, CORRETO É: B – TODAS ESTÃO CORRETAS

SEMANA 7 GUIs (INTERFACES GRÁFICAS) - GRAPHICAL USER INTERFACE


Botões, janelas
VIDEOAULA 18 INTERFACES GRÁFICAS EM PYTHON I
Interfaces Para implementar programas com interfaces gráficas (GUI) é necessário fazer uso
gráficas de APIs que fornecem funções para criação de janelas, botões, gráficos e
gerenciamento de eventos. Neste curso, utilizaremos o módulo tkinter, da
biblioteca padrão Python.

Nosso primeiro exemplo será uma janela simples, sem qualquer funcionalidade.
>>> from tkinter import Tk
>>> root = Tk()
>>> root.mainloop()

#WIDGET = FERRAMENTA
#WIDGET LABEL: USADO PARA EXIBIR TEXTO NA JANELA
#WIDGET ENTRY: é apropriado para a entrada (e exibição) de uma única linha de
texto. O usuário pode entrar com texto dentro do widget usando o teclado.
# WIDGET BUTTON: construtor Button.
o primeiro argumento do construtor Button deve se referir ao master do botão. Para
especificar o texto que será exibido no topo do botão, o argumento text é usado,
novamente assim como para um widget Label
A única diferença entre um botão e um label é que um botão é um widget interativo.
Toda vez que um botão é clicado, uma ação é realizada. Essa “ação” é, na realidade,
implementada como uma função, chamada toda vez que esse botão é acionado.
Podemos especificar o nome dessa função usando uma opção command no construtor
Button.
Quando o botão é clicado, a função clicked() será executada.
#WIDGET ROOT: CRIA A JANELA
#WIDGET CLICKED(): a função clicked() será executada. Agora, precisamos
implementar essa função. Quando chamada, a função deverá exibir a informação atual
de dia e hora.

Podemos adicionar um texto dentro da janela, para isso usamos o widget Label:
>>> from tkinter import Tk, Label
>>> root = Tk() # OBJETO ROOT SERÁ A JANELA CRIADA
>>> hello = Label(master = root, text = 'Ola classe') # PARAMETRO MASTER
INDICA EM QUAL JANELA IRÁ APARECER O TEXTO
>>> hello.pack() # MÉTODO PACK FAZ O EMPACOTAMENTO DE TODOS OS
COMPONENTES CRIADOS NA JANELA
>>> root.mainloop() # MÉTODO MAINLOOP FAZ A CHAMADA DA FUNÇÃO QUE
CRIA A JANELA.

Há várias opções para alterar o estilo do texto.

Inserindo uma imagem na janela:


>>> from tkinter import Tk, Label, PhotoImage #CLASSE PHTOIMAGE INSERE A
IMAGEM, A PHTOIMAGEM SÓ ACEITA IMAGENS COM FORMATO GIF, A IMAGEM
DEVE FICA NA MESMA PASTA DO PROJETO COM EXTENSÃO .PY
>>> root = Tk()
>>> photo = PhotoImage(file='computer.gif').subsample(5) #CRIA O OBJETO
PHOTO. MÉTODO SUBSAMPLE DIMINUI DE TAMANHO A IMAGEM ARA
>>> hello = Label(master=root, image=photo, width=300, height=180) # É
PRECISO ESPECIFICAR ALTURA E LARGURA
>>> hello.pack()
>>> root.mainloop()

A posição de componentes na janela é gerenciada pelo geometry manager da


tkinter, a partir de diretivas definidas pelo programador.
O método pack() é uma forma de fornecer essas diretivas ao sistema.

Exemplo:
from tkinter import Tk, Label, PhotoImage, TOP, BOTTOM (PARTE DE BAIXO DA
JANELA) #TOP E BOTTOM SÃO DIRETIVAS QUE DETERMINAM O LOCAL QUE
CADA OBJETO DEVERÁ APARECER NA TELA
root = Tk()
photo = PhotoImage(file='computer.gif').subsample(5)
image = Label(master=root, image=photo)
image.pack(side=TOP)
text = Label(master=root, font=("Courier", 18),
text='Olá alunos da UNIVESP!')
text.pack(side=BOTTOM)
root.mainloop()

Outras opções do método pack():

Uma outra opção para fornecer as diretivas ao geometry manager é por meio do
método grid().
Com ele, a janela é dividida em linhas e colunas, e cada célula pode armazenar
um widget.

Exemplo:
from tkinter import Tk, Label, RAISED
root = Tk()

labels = [['1', '2', '3'],


['4', '5', '6'],
['7', '8', '9'],
['*', '0', '#']]
for r in range(4):
for c in range(3):
label = Label(root, relief=RAISED, padx=10, text=labels[r][c])
label.grid(row=r, column=c)
root.mainloop()
QUIZ

VIDEOAULA 19 INTERFACE GRÁFICAS EM PYTHO II


COMO ADICIONAR FUNCIONALIDADE NOS COMPOTENTE COLOCADOS NA
JANELA
Interfaces Na aula passada, aprendemos sobre como interfaces gráficas são criadas em
gráficas Python.
Nesta aula, veremos como adicionar funcionalidade aos widgets criados.

Utilizaremos a abordagem de programação orientada a eventos.


#CADA EVENTO É UMA AÇÃO DO USUÁRIO, QUE GERA UMA TAREFA A SER
EXECUTADA PELO PROGRAMA
Quando uma interface gráfica é iniciada com a função mainloop(), o
interpretador inicia um loop infinito chamado de loop de evento. Seu
pseudocódigo é:

Eventos possíveis: clicar, movimentar o mouse, pressionar um tecla, etc.

Primeiro exemplo: janela com um botão que, quando clicado, exibe o dia e a hora
na tela.

from tkinter import Tk, Button, Label


from tkinter.messagebox import showinfo #MANEIRA DE EXIBIR A JANELA DE
DATA E HORA
from time import strftime, localtime #CLASSES QUE SÃO USADAS PARA OBTER
HORA EXATA DO LOCAL

def clicked():
time = strftime('Day: %d %b %Y\nTime: %H:%M:%S %p\n', localtime()) #\n -
PULA UMA LINHA, P É REFERENTE AO PERÍODO DA TARDE (AM OU PM)
showinfo(message=time) #A FUNÇÃO SHOWINFO É CHAMADA E PASSA A
MENSAGEM STRING TIME CRIADA
root = Tk()
button = Button(root, text='Clique', command=clicked) #ATRIBUTO COMMAND
DETERMINA O QUE ACONTECERÁ COM O OBJETO CRIADO
button.pack()
root.mainloop()

Segundo exemplo: caixa de inserção de texto

#NESTE PROGRAMA O USÁRIO DIGITA O DIA, MES E ANO E O PROGRAMA


IMPRIME EM OUTRA TELA, JUNTAMENTE COM O DIA DA SEMANA DAQUELA
DATA, PARA ISSO USAMOS A FUNÇÃO ‘ENTRY’
from tkinter import Tk, Button, Label, Entry
from tkinter.messagebox import showinfo
from time import strftime, strptime
def compute():
global entry #DÁ ACESSO AO OBJETO INSERIDO PELO USUÁRIO
date = entry.get()
weekday = strftime('%A', strptime(date, '%b, %d, %Y')) #%B É O MES, %D É O
DIA, %Y - É O ANO
showinfo(message='{} was a {}'.format(date, weekday))

root = Tk()
label = Label(root, text='Digite uma data: ')
label.grid(row=0, column=0) #CRIA O LOCAL EM QUE APECERÁ A MENSAGEM NA
JANELA
entry = Entry(root)
entry.grid(row=0, column=1)
button = Button(root, text='Enter', command=compute)
button.grid(row=1, column=0, columnspan=2) #ATRIBURO COLUMSPAN
INFORMA QUE SERÁ MESCLADAS COLUNAS
root.mainloop()/

Terceiro exemplo: caixa de texto com diferentes eventos.


>>>
char: u
char: n
char: Return
char: i
mouse left clicked
Neste exemplo, usamos o widget Text, que funciona como um editor de texto.
Também usamos o método bind() para poder associar diferentes eventos às suas
respectivas funções de tratamento.
Para isso, precisamos entender os padrões de evento, que possuem o seguinte
formato geral:
<modificador-modificador-tipo-detalhe> #TECLAS COMO CRONTOL, ALT - SÃO
MODIFICADORES

Exemplos:
• <Control-Button-1>:
Pressionar Ctrl e botão
esquerdo do mouse,
simultaneamente.

• <Button-1><Button-3>:
Pressionar botão
esquerdo e em seguida o
direito do mouse.

• <KeyPress-D><Return>:
Pressionar D e depois
Enter

from tkinter import Tk, Text, BOTH

def key_pressed(event):
print('char: {}'.format(event.keysym))

def mouse_clicked_left(event):
print('mouse left clicked')

def mouse_clicked_right(event):
print('mouse right clicked')

root = Tk()
text = Text(root, width=20, height='5')
text.bind('', key_pressed)
text.bind('', mouse_clicked_left)
text.bind('', mouse_clicked_right)
text.pack(expand=True, fill=BOTH)
root.mainloop()
EXECUTAR ESSE PROGRAMA EM PYTHON
QUIZ

QUIZ COM
OBETIVO
EDUCACIONAL
ATIVIDADE
AVALIATIVA
ERREI, CORRETO É D. APENAS III
ERREI, CORRETO É C (I, II,III)
ERREI, LETRA C – APENAS I E II, TAMBÉM NÃO É, NÃO É D (APENAS II) - ERREI

Você também pode gostar