Resumo APC2

Fazer download em pdf ou txt
Fazer download em pdf ou txt
Você está na página 1de 17

Tipos Mutáveis e Não Mutáveis em Python:

Quando fazemos uma atribuição

a=3

O objeto int com valor 3 e o nome “a” são criados na memória. Python mantém em uma tabela as variáveis criadas ,
que apontam para objetos alocados na memória

a=3 b = 3.0 c = ‘hello’ d = [2,3,5,8,11]

O que ocorre ao alterarmos o valor de a para 6?

a=6

• int, bool, float, str e complex são IMUTÁVEIS

Já no caso de listas, seu valor pode alterar:

➢ d = [2,3,5,8,11]
➢ d[3]=7

Mutabilidade de Objetos e Atribuição de Variáveis:

b mantém apontando para o valor original de a


Questão 1.1

Dado o seguinte trecho de código em Python, considere S para as instruções que são válidas, e N para as que
não são válidas:

lista = ['abc', ['d'], ['ef']]

( ) lista[0] = 'x'

( ) lista[0][0] = 'x'

( ) lista[1][0] = 'x'

( ) lista[2][0] = 'x'

( ) lista[2][0][0] = 'x'

Assinale a alternativa que apresenta a sequência correta, respectivamente:

a) S-N-S-S-N
b) S-S-S-S-N
c) S-S-S-N-N
d) S-S-N-N-N
e) S-N-N-N-N

Resolução: Strings são imutáveis, então, quando tenta-se alterar um caractere dela, dá erro. Por exemplo, lista[0][0]
irá acessar o caractere ‘a’ da primeira string da lista. Já lista[0] acessa a string inteira, podendo esse ponteiro ser
alterado para outra string (no caso é o caractere x).

A resposta correta é: S-N-S-S-N.

Programação Estruturada, Classes e Atributos


Objeto: Entidade que formaliza o modo pelo qual compreendemos algo no domínio do problema. Entidade o mais
próximo possível das entidades do mundo real.

A um objeto está sempre associado: seu estado e seu comportamento

Classe: Descreve um conjunto de Objetos semelhantes, um grupo de atributos e métodos que resumem
características de um objeto. É uma abstração geral de um grupo de objetos específicos.

Na prática, definimos uma classe, e depois a instanciamos por meio da criação de um objeto.
Definindo uma classe:

Para definir classes em Python, usa-se o operador class, seguido do nome da classe e dois pontos. No bloco de
código associado à classe, pode-se declarar variáveis e funções. O código abaixo declara a classe MyClass com uma
variável e uma função interna, chamadas my_variable e my_func respectivamente.

Criando um objeto pertencente a uma classe:

Para criar um objeto (ou instância) da classe MyClass, usa-se a mesma sintaxe de chamada de funções:

Com isso, a variável my_object agora representa uma instância, i.e., um objeto, da classe MyClass.
Portanto, my_object tem acesso tanto à variável my_variable, quanto à função my_func, sendo possível acessá-las
como segue:

É possível criar múltiplos objetos da mesma classe. Cada um deles conterá cópias independentes das variáveis e
funções definidas na classe. Por exemplo, podemos criar mais um objeto da classe MyClass, chamado b e mudar o
valor de my_variable:

Assim, my_variable representa um atributo dos objetos da classe MyClass. Como é esperado que diferentes objetos
tenham valores diferentes em seus atributos, seria incoveniente se fosse necessário modificar os valores dos
atributos após a criação de cada objeto, em outras palavras seria mais interessante que o valor dos atributos
pudesse ser informado no momento da criação do objeto. Para isso, usa-se um método especial, chamado __init__,
também conhecido como construtor. Uma classe com construtor pode ser definida da seguinte forma:

Quando uma classe é definida com um método __init__, a criação de novos objetos da classe automaticamente
invoca __init__ para cada novo objeto. Assim, uma nova instância pode ser criada como:

O primeiro parâmetro dos métodos __init__ e my_func é o mesmo: self. O parâmetro self é uma referência ao
próprio objeto, permitindo acesso aos identificadores definidos no namespace do objeto. No método __init__, a
linha self.my_variable = value cria o atributo my_variable no namespace do objeto, com o valor passado como
argumento. É isso que permite que o valor do atributo seja acessado como b.my_variable. Se uma outra variável
fosse declarada dentro do método __init__, mas sem associá-la ao self, ela não ficaria acessível fora do método.
Exemplo:

Note que ao chamar um método de um objeto, não se deve passar um valor para o parâmetro self. Quando o
método é chamado, self automaticamente se torna uma referência ao objeto associado. Além disso, self não é uma
palavra reservada e não é obrigatório que o primeiro parâmetro chame-se self. Isso é apenas uma convenção.
Questão 1.2

Considere uma classe “Fracao” em Python e dois objetos definidos como segue:

class Fracao:

def __init__(self, num, den):

self.num = num

self.den = den

def __repr__(self):

return str(self.num) + '/' + str(self.den)

f1 = Fracao(1, 2)

f2 = Fracao(3, 4)

print(f1)

print(f2)

Considere as afirmativas como verdadeiras (V) ou falsas (F):

( ) A instrução print(f2) fará com que seja gerado um erro.

( ) f1 e f2 são objetos da classe Fracao.

( ) A classe Fracao possui dois atributos, f1 e f2.

Assinale a alternativa que apresenta a sequência correta, respectivamente:

a) F-V-F
b) V-V-V
c) V-V-F
d) V-F-F
e) F-F-F

RESOLUÇÃO

A resposta correta é: F-V-F.

A instrução print(f2) irá imprimir 3/4. Os atributos da classe Fracao são: num e den.
Questão 2

Implemente uma classe em Python que represente o conceito ‘Horário’, contendo os seguintes atributos: hora,
minuto e segundo. Em seguida, crie um objeto h dessa classe, em que ao executar a instrução ‘print(h)’, o
programa deverá imprimir uma string no formato: ‘hora:minuto:segundo’.

Pilhas, Filas, Lista, Árvores e Grafos


Pilha: 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.

Operadores:

• 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

Exemplo simples de Pilha


Filas: estrutura para armazenar um conjunto de elementos, 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

Principal uso: 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.

Exemplo simples de
Pilha(Pile):Último a entrar, Fila

primeiro a sair pop(-1)

Fila(Queue): Primeiro a entrar,


primeiro a sair pop(0)

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. As 4 maneiras
principais de se implementar listas são: Sequencial vs Encadeada, Estática vs Dinâmica.

Lista Sequencial vs Lista Encadeada


Índice
Sequencial:

• Elementos são inserido em sequência na memória, fisicamente


• Permite acesso aos elementos por meio de índices
• Vantagem: acesso aos elementos pelo índice
• Desvantagem: memória mal utilizada
• Python implementa listas usando a abordagem sequencial

Encadeada

• Elementos não estão necessariamente em posições


adjacentes de memória, possuindo uma sequência lógica
• Usa-se um ponteiro para o primeiro e elemento possuí um
ponteiro indicando o próximo
• Vantagem: otimização de memória
• Desvantagem: perda do acesso direto de elementos

Lista Estática vs Lista Dinâmica

Estática:

• Toda memória é alocada, mesmo sem ser utilizada


• Vantagens: Mais simples, pois é realizada somente uma vez

Dinâmica:

• A memória é alocada sob demanda, à medida que necessário


• Vantagens: melhor gerenciamento de memória, útil quando não sabemos o tamanho total de elementos
de uma lista
• Python implementa listas usando a abordagem dinâmica

Outras variações de listas

Ordenadas vs Não Ordenada Linear vs Não Linear Homogênea vs


Heterogênea
• A lista • Em uma lista linear, • Uma lista
ordenada enumera os os elementos são homogênea possibilit
elementos; a lista organizados em uma a o armazenamento
não-ordenada coloca ordem linear, onde de grupos de valores
marcadores antes de cada um dos em uma única
cada elemento elementos é anexado variável pois são do
ao seu adjacente mesmo tipo, um tipo
anterior e ao próximo. de estrutura de dados
Em uma estrutura de heterogênea; agrupa
dados não linear, os itens de dados de
elementos de dados diferentes tipos
são anexados de
maneira hierárquica.

Grafos: Grafos são o tipo mais comum de estrutura Não-Linear, demonstrando a relação direta entre diversos
elementos de maneira não consecutiva/linear

Árvores: São um tipo de estrutura de dado Não Linear, separada hieraquicamente por galhos, Permitem tratamento
computacional eficiente quando comparadas a estruturas mais genéricas como grafos. Árvores são ótimas para
busca.

Conceitos e Defininições: 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 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, o qual os mesmos conceitos se aplicam
Árvores binárias: Árvores com grau 2, ou seja, cada nó pode ter 2 filhos, no máximo

Árvores binárias de busca (ABB): Também chamadas 'árvores de pesquisa' ou 'árvores ordenadas'.

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 esqueda 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.

Para saber quantos nós cabem em uma árvore de N níveis, usamos a fórmula 𝟐𝑵 − 𝟏

Questão 1.3

Assinale a alternativa que melhor representa o conceito apresentado na definição a seguir:

“Primeiro que entra é o primeiro que sai”.

a) Pilha.
b) Fila.
c) Árvore.
d) Lista.
e) Grafo.

RESOLUÇÃO

A resposta correta é: Fila.

Filas são estruturas de dados em que os primeiros elementos que são inseridos são os primeiros a serem
removidos. Todas as outras alternativas são de estruturas que não têm relação com o conceito do enunciado. Em
uma pilha, o último que entra é o primeiro que sai. Já em árvores, listas e grafos, não há uma ordem de inserção e
remoção pré-definida.

Algoritmos de Ordenação
Ordenaçã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. Por outro lado, se a busca for uma operação
frequente, vale a pena ordenar (pode ser feita apenas uma vez).

Terminologia

• Ordenação de Registros: cada registro é ordenado por sua chave


• Ordenação Interna: todos registrados são salvos na memória principal
• Ordenação Externa: os dados não cabem na memória principal e são armazenados em disco
• Ordenação Estável: a ordem original dos registros é preservada após a ordenação

Algoritmos de Ordenação populares, explicação rápida

• Bubble sort: Compara pares de vizinhos repetidamente, e troca se necessário


• Insertion sort: Adiciona um novo elemento ao grupo já ordenado repetidamente
• Selection sort: Repetidamente seleciona o menor elemento e o append ao resultado
• Quick sort: Seleciona um pivô e separa menores à esquerda e maiores à direita
• Heap sort: Usa uma árvore binária para ordernar
• Merge sort: Dividir para conquistar. Divide a lista em 2 grupos e compara entre eles

Bubble sort

• Percorre o conjunto várias vezes


• A cada iteração, compara cada elemento com seu
sucessor (v[i] com v[i+1]) e trocá-los de lugar caso
estejam em ordem incorreta

Para um vetor de n elementos, são necessárias n-1 iterações.

O nível de complexidade de tempo é de O(n²) e O(1) de espaço

Vantages do Bubble sort

• Fácil de entender
• Não necessita memória extra
• Código simples
• Espaço mínimo

Desvantagens do Bubble sort Implementação em Python


• Não funciona bem com listas grandes e não-ordenadas
• N² de complexidade/tempo
Insertion sort

• Ordena o conjunto inserindo os elementos em um subconjunto já


ordenado
• No i-ésimo passo, insere o i-ésimo elemento na posição correta
entre x[0], ..., x[i-1], que já estão em ordem.
o Realocar elementos

O nível de complexidade de tempo é de O(n²) e O(1) de espaço

Vantagens do Insertion Sort

• Simples implementação
• Eficiente em datasets pequenos
• Ordenação Estável (a ordem original dos registros é preservada
após a ordenação)
• Espaço mínimo

Implementação em Python

Merge sort (ordenação por intercalação)

• Um vetor v é dividido em duas partes, recursivamente.


• Cada metade é ordenada e ambas são intercaladas formando o vetor ordenado.
• Usa um vetor auxiliar para intercalar.

O nível de complexidade de tempo é de O(n*log n) e O(n) de espaço


Vantagem e Desvantagem

• A complexidade do MergeSort não depende da sequência de entrada


• A função MERGE requer um vetor auxiliar, o que aumenta o consumo de memória e tempo de execução

Implementação em Python

Quicksort

Algoritmo também baseado na estratégia dividir para conquistar.

• Dividir o vetor em dois vetores menores que serão ordenados independentemente e combinados para
produzir o resultado final.

1. Escolha de um elemento pivô x, colocando-o em sua posição correta


o 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
2. Ordenar subvetores à esquerda e à direita do elemento pivô.

O nível de complexidade de tempo é de O(n*log n) e O(n) de espaço

Vantagens do Quicksort

• É extremamente eficiente para ordenar arquivos de dados.


• Necessita de apenas uma pequena pilha como memória auxiliar.
• Requer O(n log n) comparações em média (caso médio) para ordenar n itens.

Desvantangens do Quicksort

• Tem um pior caso O(n²) comparações.


• Sua implementação é delicada e difícil: Um pequeno engano pode levar a efeitos inesperados para
algumas entradas de dados.
• O método não é estável.

Implementação em Python

Heapsort

Utiliza uma estrutura heap para ordenar os elementos. Um heap é uma estrutura de dados em que há uma
ordenação dos elementos: representação via árvore binária.

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.
o Heap máximo: pai >= filhos
o 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.

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.

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. 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.
Implementação em Python

Questão 1.4

Assinale a alternativa que melhor representa o conceito apresentado na definição a seguir:

“Realiza comparações entre elementos consecutivos, de modo que a cada iteração do laço mais externo o
maior elemento é posicionado no final do vetor”.

a) Quicksort
b) Heapsort
c) Radixsort
d) Bubblesort
e) Mergesort

RESOLUÇÃO

A resposta correta é: Bubblesort.

O algoritmo Bubblesort realiza comparações entre elementos consecutivos, de modo que a cada iteração do laço
mais externo o maior elemento é posicionado no final do vetor.O Quicksort seleciona um pivô para ordenar os
elementos à esquerda e à direita. O Heapsort utiliza uma árvore binária para ordenar. O Radixsort não é baseado
em comparações, e o Mergesort é baseado em divisão-e-conquista.

Interfaces Gráficas em Python


Para implementar programas com interfaces gráficas (GUI) é necessário fazer uso de APIs que fornecem funções
para criação de janelas, botões, gráficos e gerenciamento de eventos. Utilizaremos o módulo tkinter da biblioteca
padrão Python

Criando uma janela simples

Podemos adicionar um texto dentro da janela, para isso usamos o widget Label:
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.

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.
Questão 3

Considere o programa em Python:

from tkinter import Tk, Button, Label, Entry, END

def clicked():

global entry

name = entry.get()

print('Ola', name)

entry.delete(0, END)

root = Tk()

label = Label(root, text='Nome:')

label.grid(row=0, column=0)

entry = Entry(root)

entry.grid(row=0, column=1)

button = Button(root, text='OK', command=clicked)

button.grid(row=1, column=0, columnspan=2)

root.mainloop()

O que representa e para que serve a variável entry?

RESOLUÇÃO

O programa cria uma janela com alguns componentes: Label, contendo o texto ‘Nome:’; entry, que é uma caixa de
texto para o usuário inserir algum dado; e um botão que, quando clicado pelo usuário, faz com que a função
clicked() seja executada. Essa função obtém o texto do componente entry e imprime o no terminal precedido da
string ‘Ola’. Desse modo, a variável entry representa um objeto da classe Entry, responsável por adicionar um caixa
de texto na janela, para que o usuário possa inserir um texto pelo teclado.

Você também pode gostar