Baixe o app para aproveitar ainda mais
Prévia do material em texto
Introdução aos tipos abstratos de dados 1. O tipo de dado que representa números é muito utilizado em programação; logo, é sua correta utilização durante o desenvolvimento de uma aplicação é fundamental. Suponha que você esteja analisando os tipos de dados para a implementação de uma aplicação voltada à contabilidade. Durante essa análise, você questiona qual tipo de dados uma variável deve utilizar para representar o número 10, visando à redução do custo de memória do computador. Você acertou! A. Int. O tipo int é utilizado exclusivamente para números naturais. O char é utilizado para representar um caractere. As demais opções (long int, double e float) fazem uso de mais memória em comparação ao int. 2. Os tipos de dados booleanos têm características específicas em relação aos outros tipos de variáveis. A partir dessa afirmação, identifique a alternativa que apresenta um exemplo de dados booleanos: Você acertou! A. Verdadeiro ou falso. Dados booleanos são utilizados exclusivamente para demonstrar um estado em contraposição a outro, como verdadeiro/falso. O tipo booleano não poderá receber valores numéricos ou palavras, como as demais opções (Rua Paulista; 2,5; 10; 01/12/2019). 3. Programas de computador fazem uso de diversas variáveis e operações. Em qual momento uma variável ocupa a memória do computador? Você acertou! C. Durante a execução do programa. As variáveis somente existem quando o programa está em execução, pois nesse momento está sendo utilizado um bloco de memória do computador. Durante a finalização do programa, a memória deverá ser liberada, e não alocada. Durante o desenvolvimento do programa ou a compilação, é verificada a estrutura do código, e não a alocação da variável em memória. 4. A utilização de variáveis que consomem pouca memória é de suma importância para o desenvolvimento de aplicações com hardware limitado. Por isso, você precisa poupar memória no sistema de presença de uma universidade, na qual os computadores utilizados serão reciclados pelos alunos de anos iniciais. A partir das informações anteriores, qual tipo de variável deve ser utilizado para representar uma única letra do alfabeto visando à redução do custo de memória do computador? Você acertou! B. Char. Para a representação de um único caractere, seja ele uma letra, um símbolo ou um número, usa-se o tipo char. O tipo string é capaz de representar uma lista de elementos maiores que um caractere. Os tipos int, float e double são utilizados para representar números. 5. Durante o desenvolvimento de uma aplicação, faz-se uso de diferentes tipos de dados. Na definição de tipos abstratos de dados (TAD), faz-se referência ao par (v,o). Qual é o significado desse par? Você acertou! C. (variável, operação). Formalmente, pode-se definir TAD como um par (v,o), em que ‘v’ representa uma ou mais variáveis, e ‘o’ , uma ou mais operações. Listas sequenciais: estáticas e dinâmicas 1. A linguagem Python possibilita a armazenagem de diferentes tipos de dados em um mesmo vetor. A partir desse contexto, um programador implementou o seguinte código: #declaração do vetor Aluno = ['A',20,60,'casa',3] print(Aluno[-1]) Qual será a saída do programa? Você acertou! E. 3. Em Pyhon, o programador poderá acessar cada elemento de forma individual e circular, logo, a posição -1 representa o último elemento do vetor. Posição ==> Conteúdo 0 ou -5 ==> A 1 ou -4 ==> 20 2 ou -3 ==> 60 3 ou -2 ==> casa 4 ou -1 ==> 3 2. A linguagem Python possibilita o acesso direto a um elemento de um vetor. O índice de acesso tem o comportamento circular. A partir dessa afirmação, no vetor abaixo, qual o índice correspondente à primeira posição 0 (zero)? vetor = ['A','B','C','D','E'] Você acertou! C. -5. A posição correspontende à posição zero é a -5, de acordo com a tabela abaixo: Posição ==> Conteúdo 0 ou -5 ==> A 1 ou -4 ==> B 2 ou -3 ==> C 3 ou -2 ==> D 4 ou -1 ==> E 3. O vetor deverá corresponder a uma lista de elementos na qual cada nodo deverá armazenar uma informação. A partir dessa informação, qual é a posição ocupada pelo último elemento do vetor a seguir? vetor = [1,2,5,7,9] Você acertou! B. 4. As posições de um vetor são numerados a partir do valor zero, sendo zero para o primeiro elemento e, consequentemente, aos demais elementos do vetor. Posição ==> Conteúdo 0 ou -5 ==> 1 1 ou -4 ==> 2 2 ou -3 ==> 5 3 ou -2 ==> 7 4 ou -1 ==> 9 4. A lista encadeada é muito utilizada para armazenar um número indefinido de elementos. Em uma lista encadeada simples, cada nodo possui duas informações. Quais são elas? Você acertou! A. Conteúdo e índice do próximo nodo. Uma lista encadeada simples possui sempre o seu conteúdo e o seu endereço de memória (índice) do próximo nodo. Os nodos não têm o conhecimento do seu respectivo lugar na lista, ou seja, não sabem a sua origem ou nodo anterior, pois não armazenam essa informação; são independentes e desconhecem o tamanho da lista. 5. As listas encadeadas simples e os vetores têm diversas vantagens e desvantagens comparadas entre si. Qual das informações a seguir é uma vantagem das listas encadeadas simples, se comparada a vetores? Você acertou! C. Têm o seu tamanho flexível em tempo de execução. As listas encadeadas simples têm em seu nodo o seu respectivo conteúdo e o endereço de memória do próximo, logo ocupam mais memória que um vetor; poderão aceitar elementos durante a sua utilização definidos pelo usuário, desde tipos primitivos a abstratos, criados pelo programador; e, por não terem tamanho fixo ou previamente definido, não poderão ser listadas por comando for predeterminado, havendo a necessidade de adicionar um break. Listas encadeadas simples 1. A análise e o desenvolvimento de algoritmos com o uso de listas encadeadas são de suma importância no desenvolvimento de uma aplicação. Durante essa ação, o desenvolvedor precisa realizar a análise prévia dos códigos de uma determinada aplicação para iniciar seu desenvolvimento. Analise o algoritmo a seguir e marque a alternativa que representa seu significado: def acao(self,item): atual = self.inicio status = False while atual != None and not status: if atual.dado()==item: status = True else: atual = atual.prox() return status Você acertou! C. Procura um elemento na lista. O algoritmo inicia com o apontamento para o início da lista e declara uma variável como Falso. No segundo momento (comando While), percorre a lista enquanto não chegar ao seu final e o status for diferente de Falso. Dentro do laço com o comando IF, verifica se o dado recebido na função encontra-se no Nodo; caso afirmativo, troca o status para True, informando que encontrou o valor. Ao final, retorna o status se encontrou ou não o conteúdo na lista. 2. A lista simplesmente encadeada é uma lista do tipo dinâmica e apresenta vantagens em relação a listas estáticas, como vetores. A partir da afirmação anterior, marque a opção que informa uma das vantagens das listas simplesmente encadeadas. Você acertou! B. Permitem variação de seu tamanho em tempo de execução. Uma lista simplesmente encadeada permite o aumento e a redução do número de elementos em tempo de execução, sem precisar alocar posições contínuas de memória, como corre em listas estáticas. Na lista encadeada não existe busca de acordo com a indexação, pois a pesquisa é realizada sequencialmente a partir do primeiro elemento, Nodo. A inserção e a remoção de elementos podem ser realizadas em qualquer posição, sem a necessidade de reordenação dos demais elementos, mas, apesar disso, requerem percorrer nodo a nodo até sua posição. 3. A análise e o desenvolvimento de algoritmos com o uso de listas encadeadas são de suma importância no desenvolvimento de uma aplicação. Durante essa ação, o desenvolvedor precisa realizar a análise prévia dos códigos de uma determinada aplicação para iniciar seu desenvolvimento. Analiseo algoritmo a seguir e marque a alternativa que representa seu significado: 1 def acao (self,item) 2 temp = No(item) 3 temp.prox(self.ini) 4 self.ini = temp Você acertou! B. Adiciona um novo elemento no início da lista. A função, na linha 1, recebe como parâmetro um valor que será utilizado internamente. Na linha 2, realiza a criação de um No com o dado recebido. Na linha 3, realiza a atualização do ponteiro prox para o primeiro elemento da lista. Na linha 4, adiciona o ponteiro do início da lista para o novo No, inserindo o elemento sempre no início da lista. 4. A lista simplesmente encadeada é uma lista do tipo dinâmica e apresenta vantagens em relação a listas estáticas, como vetores. A partir dessa afirmação, marque a opção que informa um tipo de lista em que é mais apropriado utilizar listas simplesmente encadeadas em detrimento de listas do tipo estáticas, como vetores. Você acertou! C. Listas grandes que realizam diversas inserções em diferentes posições. Uma lista simplesmente encadeada é recomendada para utilização em grandes listas, que podem ter muitas inserções e exclusões em quaisquer posições, cujo tamanho é indefinido. Por ser uma lista dinâmica, não tem sua pesquisa indexada e a varredura ocorre apenas em uma direção, pois possui somente o apontamento para o próximo elemento da lista. 5. As listas simplesmente encadeadas possuem características únicas em seus nodos, diferentemente das listas estáticas. Em relação a essas características únicas, leia as alternativas a seguir e selecione a correta. Você acertou! D. O nodo tem seu conteúdo definido pelo usuário e um ponteiro para o próximo elemento. Uma lista simplesmente encadeada possui em seu nodo uma variável com a posição de memória do próximo elemento, bem como seu respectivo conteúdo. Devido a essa característica, seu armazenamento não precisa ser linear em memória, pois armazena a localização do próximo nodo. Implementação de listas encadeadas simples 1. A análise de códigos é de suma importância para o desenvolvimento de um programador, sendo uma das tarefas mais comuns no seu dia a dia, seja na compreensão do desenvolvimento complementar, seja durante os seus estudos. Realize a análise do código a seguir e assinale a alternativa que contém o seu objetivo: def Metodo(self): atual = self.inicio self.inicio = atual.proximo Você acertou! C. Realizar a exclusão do primeiro nodo. Método que realiza a remoção do primeiro elemento: def Remove_Inicio(self): #Realiza a atribuição do início da lista para um o nodo atual. atual = self.inicio #Atualiza o primeiro elemento da lista para o elemento posterior ao primeiro nodo, excluindo o nodo inicial. self.inicio = atual.proximo 2. As operações de manipulação de uma lista simplesmente encadeada permitem a manipulação de seus nodos durante sua execução. Analise o código a seguir e informe qual o seu objetivo: def Metodo(self): atual = self.inicio if self.inicio == None: print("none") else: while atual != None: print(atual) atual = atual.proximo Você acertou! C. Realizar a impressão de uma lista. #Realiza a impressão de todos os elementos de uma lista def Impressão(self): #Ponteiro atual recebe o início da lista: atual = self.inicio #verifica se a lista encontra-se vazia e informa o usuário if self.inicio == None: print("none") #Caso a lista tenha conteúdo, percorre toda a lista e imprime em cada interação o seu respectivo conteúdo. else: while atual != None: print(atual) atual = atual.proximo 3. O desenvolvimento de listas encadeadas pode ser realizado de diversas formas, com ou sem o uso de bibliotecas. O método da biblioteca de listas chamado append(Elemento) realiza qual função no código? Você acertou! B. Adiciona um elemento ao final da lista. #Código em Python: # Lista de letras letras= ['A', 'H', 'T'] # Metodo que adiciona a letra D no final da lista animais.append('D') # imprime a nova lista print('Atualização da lista: ', letras) #Saída do programa # Atualização da lista: ['A', 'H', 'T','D'] 4. As bibliotecas utilizadas em programação auxiliam no desenvolvimento de listas simplesmente encadeadas. O método da biblioteca de listas chamado index(Elemento) realiza qual função no código? Você acertou! D. Retorna à posição da primeira ocorrência do elemento na lista. • #Código em Python: # Lista de letras letras = ['A', 'G', 'P','G'] # imprime a lista print(letras) # Retorna e imprime a posição da primeira ocorrência do elemento G print(letras.index('G')) #Saída do programa # ['A', 'G', 'P','G'] #1 5. Os métodos para a criação das classes nodo, lista encadeada, verificação de lista vazia, adicionar e remover posição na lista são elementos básicos no que se refere à implementação de listas encadeadas simples. Analise o código a seguir e informe qual o seu objetivo: def Metodo(Lista): if Lista.inicio == None : return True else: return False Você acertou! C.Verificar se a lista está vazia. #Método que verifica se a lista está Vazia, Caso positivo Retorna True caso contrário False. def ListaVazia(Lista): # Verifica se o ponteiro para o início da lista está vazio, se positivo retorna True, logo lista vazia. if Lista.inicio == None : return True #Caso o item anterior seja falso, retorna Falso, logo lista contém itens na lista. else: return False Listas encadeadas duplas 1. Uma lista duplamente encadeada tem como estrutura duas referências, o que permite que a lista seja percorrida em dois sentidos: do início ao fim e do fim ao início. Atendendo a essa propriedade, dos exemplos a seguir, quais se aplicam para uma lista duplamente encadeada? Você acertou! B. Sistemas de paginação web, comandos de desfazer (CTRL + Z) e refazer (CTRL + SHIFT + Z) operações, lista de espera de compras e visualizador de imagens. As listas duplamente encadeadas são bem aplicadas em problemas em que seja necessário realizar operações de navegação entre elementos do início ao fim e do fim para o início, como no caso de sistemas de paginação web, comandos de desfazer (CTRL + Z) e refazer (CTRL + SHIFT + Z) operações, lista de espera de compras, visualizador de imagens e playlist de músicas. Os exemplos sistema de georreferenciamento, sorteio de número aleatório, fila de atendimento, paginação unilateral, soma de dois números e ordenação de números não necessitam dessa estrutura de dados, além de não ser possível armazenar dados não sequenciais nessas listas. 2. As listas duplamente encadeadas apresentam algumas características que precisam ser bem definidas para o seu adequado funcionamento. Quais são essas características? Você acertou! A. Definir um ponteiro para o primeiro e o último elemento da lista; o ponteiro anterior, referente ao primeiro elemento da lista, aponta para um endereço NULO; e o último elemento aponta para um endereço NULO. Uma lista duplamente encadeada pode armazenar tanto dados primitivos como estruturas de dados abstratos, e não necessita de ordenação em seus elementos. As principais características para o seu bom funcionamento são: Definir um ponteiro para o primeiro e o último elemento da lista; o ponteiro anterior, referente ao primeiro elemento da lista, aponta para um endereço NULO; e o último elemento aponta para um endereço NULO. 3. Com uma lista duplamente encadeada implementada sobre um vetor ou alocação dinâmica, é possível definir algumas ações para o gerenciamento dos elementos contidos nela. Quais são essas ações? Você acertou! E. Percorrer elementos, inserir elemento, remover elemento e buscar elemento. Para gerenciar os dados de uma lista duplamente encadeada, as ações definidas são: percorrer elementos, inserir elemento, remover elemento e buscar elemento. As demais ações citadas são possíveis de se realizar com pequenasoperações, sem necessidade de implantá-las na lista. 4. Entre as ações de uma lista duplamente encadeada, está a inserção. A inserção de um elemento em uma lista dupla pode ser realizada de três maneiras. Quais são essas maneiras? Você acertou! C. No início da lista, em alguma posição intermediária e no final da lista. Sempre que algum elemento for adicionado à lista, é importante que sejam mantidas as ligações de referências dos apontadores para os elementos anteriores e posteriores. Logo, é possível realizar a inserção de três formas: no início da lista, em alguma posição intermediária e no final da lista. As demais operações, tais como ordenadamente e aleatoriamente, não são formas de inserção, mas sim de possíveis operações. 5. Cada projeto carrega sua particularidade, assim, uma lista pode conter vários métodos associados a ela, alguns mais conhecidos, como: criar uma lista vazia, verificar se a lista está vazia, verificar se a lista está cheia, entre outros. Nesse contexto, para a inserção de um elemento nas listas duplamente encadeadas, quais critérios devem ser atendidos? Você acertou! A. Verificar se existe espaço, adicionar o contador de itens e alocar um espaço para inserir um novo elemento. A inserção de elementos nas listas duplamente encadeadas pode ser realizada de três formas: início, intermédio e final. Além disso, deve atender a alguns critérios, tais como: verificar se existe espaço para inserir um novo elemento; acomodar um espaço para inserir um novo item e assegurar que os outros elementos não ficarão com uma referência vazia, a menos que os elementos sejam incluídos no final da lista; e adicionar o contador de itens. As outras opções citadas são critérios desnecessários. Implementação de listas encadeadas duplas 1. Existem várias formas de implementar as listas duplas. Entre os tipos, há as listas duplas com cabeça fixa. Logo, qual seria a vantagem em utilizar listas com cabeça fixas? Você acertou! A. Listas com cabeça fixa permitem e carregam sempre seu valor em seu início, não necessitando de ponteiros como início e fim. Listas com cabeça fixa não precisam recorrer a mais elementos de uma lista, como os ponteiros nomeados como início e fim, por exemplo, para poder percorrê-la, pois seu endereço já carrega o início da lista consigo. Logo, o endereço nomeado como cabeça fixa não deve também conter nenhuma informação, sendo apenas uma sentinela para acessar o primeiro elemento que contenha informação em uma lista. Uma das propriedades das listas de cabeça fixa é que seu ponteiro anterior aponte para uma referência nula. Além disso, funções básicas de inserção, remoção e impressão, etc., permanecem. 2. As listas duplas são vistas como vias de mão dupla, em que é possível percorrê-las em duas direções. Uma vez implementada, como transformá-la em uma lista circular? Você acertou! D. Para que uma lista dupla seja circular, o endereço de próximo do último elemento deve apontar para o primeiro, e o endereço nulo apontado pelo ponteiro anterior do primeiro elemento, deve apontar para o último. O que diferencia as listas circulares de outras é que nelas o último elemento aponta para o primeiro e vice-versa, em caso de ponteiros duplos, não fazendo referência a endereços nulos, mesmo que exista apenas um elemento. 3. Fazer a análise de um algoritmo, por natureza, envolve entender a sua complexidade. Por que as funções de inserção têm complexidade O(1) e remoção O(n) para os piores casos? Você acertou! B. De forma intuitiva, a inserção é feita de forma direta O(1), enquanto a remoção depende de percorrer (n) elementos na lista. Antes da remoção, é realizada a busca do elemento, tendo no pior caso que percorrer uma somatória de elementos, ou seja, por todos os elementos; enquanto a inserção é feita de modo direto, sem a necessidade de passar por nenhum elemento anterior, justamente pelos ponteiros de referência início e fim. 4. Os problemas computacionais têm entradas bem estabelecidas, restrições e condições que satisfazem os valores de saída. As listas duplamente encadeadas podem ser usadas de acordo com a necessidade de cada problema, devido aos aspectos de uma lista. As listas podem ter diferentes aspectos, quais são esses aspectos? Você acertou! E. Tipo de informação: pode armazenar qualquer tipo de informação; ordem dos elementos: conforme a política de negócio; homogeneidade da informação: os elementos de uma lista podem ser representados pelo mesmo tipo de dado ou armazenar tipos de dados diferentes. As listas podem ter diferentes aspectos, tais como: Tipo de informação: neste caso, a lista pode armazenar qualquer tipo de informação, como nome, endereço, contatos, entre outros elementos existentes no mundo real. Ordem dos elementos: aqui, varia conforme a política de negócio, podendo estar em ordem de inserção, em ordem crescente ou decrescente, etc. Homogeneidade da informação: todos os elementos de uma lista podem ser representados pelo mesmo tipo de dado (inteiro, string ou uma classe criada), ou armazenar tipos de dados diferentes. Em linguagens fracamente tipadas, como Python e PHP, por exemplo, este comportamento é visto com maior naturalidade. Os demais aspectos não fazem ou não são comportamentos de uma lista duplamente encadeada: tipo do problema, complexidade, forma da lista ou linguagem de programação. 5. Entre os diversos tipos de listas duplamente encadeadas, existe uma versão chamada de lista encadeada XOR. Em relação a uma lista duplamente encadeada simples, qual a principal característica de uma lista encadeada XOR? Você acertou! C. Armazenar endereços de memória reais; cada nó armazena o XOR dos endereços dos nós anteriores e dos próximos, necessitando de apenas um espaço de memória. Uma versão com eficiência de memória da lista duplamente vinculada pode ser criada usando apenas um espaço para o campo de endereço em cada nó. Essa lista vinculada duplamente eficiente em memória é chamada de lista vinculada XOR ou memória eficiente, pois a lista usa a operação XOR bit a bit para economizar espaço para um endereço. As listas duplamente encadeadas seguem a propriedade que, a partir de um determinado elemento, seja possível tanto avançar quanto voltar, logo, as outras opções estão incorretas. Implementação de Pilhas em Python 1. A pilha é uma estrutura que permite a inserção e a remoção dos dados utilizando-se de regras predefinidas. Essas operações são realizadas por meio de duas funções: push e pop. Sabendo disso, considere que um programa tenha uma pilha a, inicialmente vazia, e que as seguintes operações foram realizadas: PUSH(a, 10); PUSH(a, 5); PUSH(a, 3); PUSH(a, 50); POP(a); PUSH(a, 11); PUSH(a, 9); PUSH(a,20); POP(a); POP(a). Ao final, quais serão o topo da pilha e o somatório dos elementos ainda dentro da pilha, respectivamente? Você acertou! B. 11 e 29. Considerando a execução de cada um dos comandos na sequência apresentada, 11 é o valor final do topo, e a somatória dos elementos restantes será: 11+3+5+10= 29. 2. Sabendo que a pilha é uma estrutura que utiliza um único caminho para a entrada e a saída de seus elementos, sendo esse o topo da pilha, considere que os números 10, 11, 12, 13 e 14 foram inseridos nessa ordem. Então, nesse caso: Você acertou! C. o número 14 é o primeiro elemento a ser removido da pilha. Como a pilha utiliza-se do modelo last in, first out, e o número 14 foi o último a ser inserido, ele é o primeiro a ser removido. 3. Estruturas de dados, como pilhas e filas, são utilizadas em diversas aplicações, tendo cada uma delas comandos e funções específicas para a manipulação dos elementos que as compõem. Assim sendo, qual método é de uso da estrutura de pilha? Você acertou! C. Push(x), que insere o elemento x no topo da pilha sem sobrepor nenhum elemento. Push(x) é a função correta para a inserção de novos elementos em uma pilha, sem a sobreposição dos elementos já existentes, ajustando o novoelemento com os demais na pilha. Stack() cria uma pilha vazia. Dequeue() remove e retorna o item do início da fila. Um item não pode ser retirado de uma fila vazia. Pop() remove e retorna o item superior da pilha se a pilha não estiver vazia. Top() não é uma função válida em Python. 4. mas Todas as estruturas de dados têm o que chamamos de local para entrada e saída de dados, e com as pilhas não é diferente, sendo esse local o seu topo. Sabendo disso, considere os estados inicial e final da pilha apresentada a seguir: Você acertou! A. Pop(), Pop(), Push(9), Push(3). Se todos os comandos forem executados nesta mesma ordem - Pop(), Pop(), Push(9), Push(3), a pilha será exibida no estado final, sendo removidos os itens 2 e 8, e inseridos 3 e 9. 5. Px é uma pilha com 5 posições, v(1) a v(5), na qual v(5) é o topo. De v(1) até v(5), a pilha Px está preenchida, respectivamente, com os símbolos Q5, Q3, Q1, Q4, Q2. Há mais duas pilhas, inicialmente vazias, Py e Pz, com o mesmo tamanho. Qual é a quantidade mínima de movimentos entre as três pilhas para que a pilha Px, originalmente cheia, esteja preenchida de v(5) até v(1), respectivamente, com os símbolos Q1, Q2, Q3, Q4, Q5? Você acertou! C. 8. Seguindo as especificações dos movimentos, a quantidade mínima de movimentos entre as três pilhas para que elas cheguem ao preenchimento desejado de Px é de 8 movimentos. Implementação de Filas em Python 1. Existem diferentes tipos de estruturas que são utilizadas para organizar dados. Qual dessas estruturas é representada como uma lista linear de elementos nos quais a exclusão pode ser feita de uma extremidade (início) e a inserção pode ocorrer apenas na outra extremidade (fim)? Você acertou! A. Fila. A lista linear de elementos nos quais a exclusão é feita na parte frontal e a inserção na parte traseira é chamada de fila, a qual utiliza o modelo first in, first out, FIFO. As pilhas utilizam o princípio LIFO, last in, first out, em que há inserção em apenas uma extremidade. Árvores tem os nós acessados por meio de busca direta, não seguindo o princípio FIFO. Em listas vinculadas aponta-se um ponteiro para os elementos que se deseja incluir/remover, não sendo utilizado, assim, o princípio FIFO das filas. Arrays têm seus elementos inseridos por meio de busca direta, não utilizando o princípio FIFO das filas. 2. Existe um conjunto de operações básicas que podem ser realizadas sobre filas; algumas operações permitem manipulação, enquanto outras apenas retornam consultas sobre as filas. Entre as operações a seguir, qual delas retorna um valor booleano? Você acertou! C. estaVazia(). A operação que retorna um booleano é a estaVazia(), que retorna True se a fila estiver vazia, e False caso contrário. A operação tamanho() devolve um inteiro, com a quantidade de itens na fila. A operação primeiro() retorna (mas não remove) uma referência ao primeiro elemento da fila. Já a operação fila() cria uma fila vazia, enquanto a operação enfilera(item) adiciona um item no final da fila. 3. Em cada estrutura de dados é utilizado um processo para inserção e remoção de elementos. Todo tipo de estrutura, seja fila, pilha ou árvore, tem funções que auxiliam nesse processo. Sendo assim, se os elementos A, B, C e D forem colocados nesta ordem em uma fila e excluídos um de cada vez, em que ordem serão removidos? Você acertou! C. ABCD. A fila segue a abordagem FIFO, ou seja, abordagem primeiro a entrar, primeiro a sair. Portanto, a ordem dos elementos de remoção é ABCD, a mesma ordem em que foram inseridos. DCBA representaria uma pilha, que segue a abordagem LIFO, na qual o último a entrar é o primeiro a sair. As alternativas DCAB, ABDC e ACDB poderiam ser implementadas com árvores ou listas, por exemplo. 4. Python disponibiliza diversas bibliotecas que facilitam a manipulação de diferentes estruturas de dados. Utilizando a biblioteca Python queue, com a seguinte implementação: import queue f = queue.Queue() f.put("abacate") f.put("amora") f.put("abacaxi") f.put_nowait("uva") f.get() f.get_nowait() f.put("pêra") f.put("amora") print(list(f.queue)) Qual seria a fila resultante? Você acertou! E. ['abacaxi', 'uva', 'pêra', 'amora']. O código em questão faz a criação de uma fila de nome f (f = queue.Queue()), depois adiciona 3 elementos na fila (abacate, amora, abacaxi). Então, com os comandos get e get_nowait, os dois primeiros elementos são removidos da fila (abacate, depois amora) e, por fim, outros dois elementos são adicionados (pêra e amora), sendo assim, a fila resultante é ['abacaxi', 'uva', 'pêra', 'amora']. O resultado [] é uma lista vazia, e teria sido obtido se fosse parado na segunda linha de código. O resultado ['abacate', 'amora', 'abacaxi', 'uva', 'pêra', 'amora'] só seria possível se não houvesse os dois comandos de remoção da fila (get e get_nowait). O resultado ['abacate'] só seria possível se fosse parado na terceira linha, e adicionado somente mais uma linha de impressão. Por fim, o resultado ['abacate', 'amora', 'abacaxi', 'uva'] só seria possível se, após inserir “uva”, fosse finalizado com uma linha de impressão. 5. Há diversas situações no cotidiano que poderiam ser representadas por diferentes estruturas de dados, como filas, pilhas, árvores, deques, entre outras. Entre as situações reportadas a seguir, qual melhor se encaixa com a estrutura do tipo fila? Você acertou! C. Documentos esperando para serem impressos em uma impressora. Documentos esperando para serem impressos em uma impressora melhor representam a estrutura de fila, em que o primeiro a ser enviado será o primeiro a ser impresso (first in, first out). Uma torre com pratos sobrepostos em uma mesa pode ser representada por uma pilha. A visualização do resultado da Copa do Mundo pode ser feita utilizando uma árvore, visto que o conjunto de times que passa para a próxima fase vai reduzindo até chegar ao campeão, que será o nodo raiz da árvore. Por fim, a relação de filmes indicados ao Oscar, assim como uma lista de itens a serem comprados no supermercado poderia ser implementada com uma lista comum. Implementação de Deques em Python 1. Existem diferentes estruturas de dados que podem ser usadas para estruturar algoritmos que resolvam problemas relacionados a containers de dados, e a escolha de qual usar depende do problema a ser resolvido. Entre as opções a seguir, qual delas melhor define uma deque? Você acertou! A. Uma estrutura com inserção/exclusão possível nos extremos frontal e traseiro da fila. Deque é uma estrutura que permite inserir e remover tanto pela cabeça quanto pela cauda. Em pilhas, é possível inserir e remover apenas em uma das extremidades. Nas filas, é possível inserir apenas em uma extremidade e remover apenas na outra extremidade. Já as árvores são hierárquicas, e os dados são inseridos iniciando-se pelo nó raiz. Em deques, não há a obrigatoriedade de inserir e recuperar dados de forma ordenada: eles podem ser inseridos na ordem em que forem gerados. 2. Usando a biblioteca Collections, é possível aproveitar alguns métodos já prontos para a manipulação de deques. Após executar o código abaixo, qual seria o resultado esperado na impressão? import collections d = collections.deque('abcd') d.appendleft('d') print (d) Você acertou! E. Inclusão do ‘d’ à esquerda. O resultado do print será: deque(['d', 'a', 'b', 'c', 'd']), incluindo um ‘d’ à esquerda da deque que foi criada inicialmente. Para incluir à direita, o comando da linha 3 deveria ser d.append('d'). Para remover o ‘d’, o comando seria d.pop(); para imprimir a letra ‘d’, o comando na quarta linha seria print ('d'); e, para imprimir a deque inicial, o comando print (d) deveria ser movido para a terceira linha. 3. Entre os métodos já implementados na biblioteca Collections, estão métodos para remoção dos elementos em uma deque. Considere que inicializamos uma dequeda seguinte forma: d = collections.deque('6598732') Qual comando utilizamos para remover o elemento 2? Você acertou! C. d.pop(). Para remover o elemento 2, utilizamos o comando d.pop(), pois ele está à direita na deque. Esse comando não recebe parâmetros; portanto, não podemos colocar dentro do parêntese o valor a ser removido. Por esse motivo, as alternativas d.pop(2) e d.popright(2) estão incorretas. Adicionalmente, o comando popright() não existe na sintaxe, visto que, como a eliminação padrão em uma fila é pela direita, o comando, nesses casos, é o pop(). Ao utilizarmos o comando d.popleft(), seria eliminado o primeiro elemento da esquerda, ou seja, o 6, e não o 2, como pede o enunciado. 4. A linguagem de programação Python facilita a manipulação de estruturas de dados a partir do uso de bibliotecas com comandos que, em poucas linhas, ajudam a inserir, remover, fazer consultas, entre outras funcionalidades. Utilizando a biblioteca Collections, qual seria a deque resultante da seguinte sequência de operações? import collections d = collections.deque() d.extend('abcd') d.pop() d.append('j') d.appendleft('z') d.pop() print (d) Você acertou! A. deque(['z', 'a', 'b', 'c']). Após a criação da deque com os elementos 'abcd', foi removido o 'd', adicionado o 'j' à direita, adicionado o 'z' à esquerda e removido o 'j'. Dessa forma, o resultado é deque(['z', 'a', 'b', 'c']). Se, no lugar do comando pop da linha 7, tivéssemos o comando d.reverse(), o resultado seria deque(['j', 'c', 'b', 'a', 'z']). Se houvesse um d.clear()no lugar do comando pop da linha 7, o resultado seria uma deque vazia: deque([]). Esta deque(['a', 'b', 'c', 'd']) é o resultado inicial, após o comando extend da linha 2, que é usado para adicionar múltiplos valores à direita da fila. Esta deque(['z', 'a', 'b', 'c', 'j']) seria resultante se não houvesse o d.pop()da linha 7, que removeu o 'j'. 5. A computação simula o mundo real, criando ambientes e estruturas baseados no funcionamento de processos já existentes no dia a dia. Qual dos seguintes cenários do mundo real você associaria a uma estrutura de dados do tipo deque? Você acertou! C. Check-in de embarque em um voo nacional. A oferta de serviços com base na prioridade do cliente, como o check-in em um voo, é um exemplo que pode ser implementado usando-se deques. As crianças em fila para andar no carrossel podem ser um exemplo de filas simples, em que não é necessário priorização. Uma árvore pode representar a hierarquia em uma empresa, e uma coleção de revistas sobrepostas pode ser representada por uma pilha. Métodos de pesquisa em listas: sequencial, binária e tabelas hash 1. A busca sequencial é uma técnica simples e intuitiva para buscar elementos em vetores ou listas. Tendo a informação de que os dados estão ordenados de forma crescente, qual otimização você pode aplicar na busca sequencial? Você acertou! D. Parar a execução e informar que o valor não existe, quando o valor atual for maior que o buscado. O desempenho de pior caso da busca sequencial pode ser otimizado sabendo-se que o vetor está ordenado. Para tanto, continua-se a buscar um elemento enquanto o elemento atual for maior que o buscado. No momento em que ele for menor, sabe-se que o vetor é ordenado e, no futuro, não será possível encontrar outro elemento maior. O contrário não é verdade, pois, caso seja encontrado um valor menor que o buscado, ainda é possível achar valores maiores no futuro. Funções hash podem ser utilizadas apenas em tabelas hash. Ainda, descobrir a posição de um elemento sem buscar em várias posições do vetor também só é possível em tabelas hash. 2. A busca binária é uma técnica eficiente para buscar elementos em vetores ou listas. A única restrição desse método é que o vetor ou a lista estejam ordenados. Das seguintes sequências de acessos em um vetor, qual é válida em uma execução de busca binária? Você acertou! C. 5, 2, 1. Em cada iteração da busca binária, o elemento do meio do intervalo atual é acessado. Nesse sentido, para acessar a posição 1, é necessário que o tamanho do intervalo seja 2. Assumindo que o vetor tivesse tamanho 2, não seria possível nas alternativas (1, 2, 5) e (1, 5, 2) acessar elementos maiores que 2 após esse primeiro acesso. No caso da alternativa (5, 7, 3), o problema vai quando o elemento 5 é acessado e logo todos os menores que 5 são ignorados, mas, logo após, o número 3 é acessado. O mesmo ocorre na alternativa (5, 2, 8). Portanto, a alternativa correta é (5, 2, 1), um vetor de tamanho 10; o primeiro acesso é o 5, após a metade é o 2 e, por fim, o 1. 3. Tabelas hash são estruturas muito eficientes utilizadas por diversas linguagens de programação e serviços. Entender seu funcionamento é crucial para o desenvolvedor, o qual deverá decidir o tamanho da tabela e a função hash que otimiza o desempenho de determinada aplicação. Considere uma tabela hash de 5 posições (de 1 a 5, aceitando repetições) e uma função hash que representa a i-ésima letra do alfabeto com o número i. Quantas colisões ocorrem após a inserção das chaves: A, B, A, C, A, E? Você acertou! B. 2. Uma tabela hash de 5 posições tem índices de 1 a 5. A função hash converte um caractere para um índice de acordo com a ordem no alfabeto. Por exemplo, a letra A é 1, a letra B é 2, e assim por diante. Nesse sentido, colisões vão ocorrer apenas quando a mesma letra for inserida. Como foi inserida três vezes a letra A, e as colisões ocorrem a partir da segunda inserção, o total de colisões é 2: a segunda inserção da letra A e a terceira. 4. Métodos de busca são muito utilizados em milhares de sistemas e aplicações reais. O projetista e o desenvolvedor devem ter muito conhecimento sobre seu funcionamento e também sobre as vantagens e desvantagens de cada método. Para uma aplicação que realiza muitas inserções e atualizações nos dados, qual é o método mais indicado? Você acertou! D. Tabela hash implementada com vetores e listas para tratar colisões. A busca sequencial tem um custo muito alto e só é indicada para aplicações com vetores pequenos que realizam poucas buscas. A binária, por outro lado, pode ser eficiente, dependendo do caso: inserir dados sempre ordenados aumenta o custo da inserção, que, no caso de aplicação com muitas inserções e atualizações nos dados, é um ponto importante; ordenar apenas quando atualizar vai aumentar o custo das atualizações, que também são muito recorrentes nesse caso. Já uma lista encadeada não permite encontrar os elementos de forma veloz, pois é necessário percorrê-la do início ao fim. Assim, a resposta correta é tabela hash, pois, dada uma chave, é possível inserir e atualizar apenas computando a função hash, que tem baixo custo. 5. Uma das maneiras de avaliar o melhor método para uma aplicação é analisar a complexidade de pior e melhor caso dos métodos e constatar com as entradas da aplicação- alvo. Para tanto, é necessário conhecimento sobre ordens assintóticas. Nesse sentido, qual é a complexidade de pior caso das buscas sequencial, binária e na tabela hash, respectivamente? Você acertou! C. O(n), O(log2 n), O(K). Para calcular a complexidade de pior caso, deve-se pensar na pior entrada possível para o programa. No caso da busca sequencial, como se tem um laço que vai de 1 até N, o pior caso é percorrer esse laço N vezes. Nesse sentido, a complexidade da busca sequencial é O(n). Quando se fala da busca binária, ela é mais eficiente, pois a cada iteração elimina metade do intervalo. Essa eliminação de metade do vetor por vez remete a uma árvore binária, por isso o nome da busca. Nesse caso, a complexidade de tempo é O(log2 n). Por fim, a tabela hash tem uma complexidade de melhor caso de O(1); entretanto, no pior caso, podem ocorrer K colisões, e uma lista encadeada será percorrida até o K-ésimo elemento. Logo, complexidade O(K). Ordenação de dados - Métodos simples 1. O algoritmo de ordenação por bolha é o mais simples e intuitivo.O seu funcionamento se baseia em comparar todos os elementos, dois a dois, do inicio ao fim da lista ou vetor. Essa operação é repetida enquanto ocorrerem trocas entre elementos. Dado o vetor [22, 11, 7, 46, 29], após duas rodadas de execução do algoritmo de ordenação por bolha, ordenando de forma decrescente, qual será o estado do vetor? Você acertou! A. 22, 46, 29, 11, 7. O algoritmo de ordenação por bolha compara elementos dois a dois da esquerda para a direita. Nesse exercício, o objetivo é ordenar de forma decrescente, ou seja, quando a comparação for feita, caso o elemento na posição i for menor que o da posição i + 1, é realizada a troca de posição entre os elementos. Na primeira rodada vai comparar 22 com 11 e não trocar. Após, compara 11 com 7 e também não troca. Agora, quando compara 7 com 46 vai trocar e, após 7 com 29, troca novamente. Na primeira rodada tem-se: [22, 11, 46, 29, 7]. Na segunda rodada compara-se 22 com 11 e não troca. Logo após, troca 11 por 46 e 11 por 29. Finalmente, compara 11 com 7 e não troca. O estado do vetor na segunda rodada é [22, 46, 29, 11, 7]. 2. A ideia principal do algoritmo de ordenação por inserção é como em um jogo de cartas. Quando você recebe uma nova carta, já ordena ela de alguma maneira. Vamos assumir que você está jogando cartas e tem a seguinte lista de cartas na mão: [Q, J, Q, J]. Quantas trocas serão feitas caso você ordene as cartas de forma ascendente, baseando-se no algoritmo de ordenação por inserção? Você acertou! C. 3. Na primeira rodada, o escolhido será o J (2.º elemento), o qual será comparado com o Q (1.º elemento). Uma vez que J é menor que Q lexicograficamente, ambos são trocados de posição (1 troca). O estado do vetor após a primeira rodada é [J, Q, Q, J]. Na segunda rodada, o escolhido é o Q (3.º elemento), que será comparado com outro Q (2.º elemento) e nada irá acontecer. Na terceira rodada, o escolhido é o J (4.º elemento), que será comparado com os dois Qs (3.º e 2.º elementos), sendo trocado (mais 2 trocas, totalizando 3). Ao fim dessa rodada, com 3 trocas, o vetor está ordenado [J, J, Q, Q]. 3. A ordenação por seleção busca o menor elemento da parte não ordenada do vetor em cada iteração e o coloca na sua posição correta. Quantas comparações e trocas são necessárias para ordenar o vetor [1, 5, 3, 9, 6] de forma crescente? Você acertou! D. 10 e 2. Na primeira rodada, o 1 será o menor e já está em sua posição correta. Serão 4 comparações com os 4 elementos à direita do 1 e nenhuma troca. Na segunda rodada, o 5 será comparado com os 3 elementos à direita e uma troca será feita entre o 5 e o 3. Na terceira rodada, o 5 já estará na sua posição correta, logo, aconteceram 2 comparações e nenhuma troca. Ao final, na rodada quatro, o 9 será comparado com o 6, 1 comparação,e serão trocados, logo, uma troca. Somando 4 + 3 + 2 + 1 são 10 comparações e 2 trocas. 4. Você foi contratado como consultor por uma empresa de desenvolvimento de sistemas. Um dos clientes solicitou o desenvolvimento de uma nova funcionalidade que permite ordenar os clientes por idade e renda. Essa funcionalidade será utilizada diversas vezes ao dia, o que indica que após uma ordenação, as outras só serão necessárias caso atualizações tenham sido feitas no banco de dados. Quantas comparações serão feitas pelo algoritmo de ordenação por bolha, caso a entrada seja uma lista de 10 elementos já ordenados? Você acertou! B. 9. Tomando como exemplo o vetor [1, 2, 3], com três elementos, o algoritmo de ordenação por bolha irá comparar 1 com 2, e 2 com 3, ou seja, 2 comparações, N - 1 elementos. Assim, é possível concluir que para um vetor já ordenado com 10 elementos, o algoritmo de ordenação por bolha irá fazer 9 comparações. 5. Uma das maneiras de avaliar o melhor algoritmo de ordenação para determinada aplicação é analisando a sua complexidade de tempo. Você foi contratado para fazer essa análise. A primeira pergunta que seu chefe fez foi qual seria a complexidade de melhor e pior caso do algoritmo de ordenação em seleção, caso ele fosse executado M vezes consecutivas. O que você responderia? Você acertou! E. O(M * N2) e O(M * N2). O algoritmo de ordenação por seleção em cada iteração corrige a posição de um dos elementos do vetor. Para tanto, em cada iteração ele busca em toda lista pelo menor elemento ainda não processado. Isso ocorre tanto no caso de o vetor estar desordenado (pior caso) quanto no caso de estar ordenado (melhor caso). Nesse sentido, a complexidade de tempo de melhor e pior caso desse algoritmo é a mesma, O(N2).Entretanto, é preciso levar em consideração as M execuções citadas no enunciado. Nesse caso, serão repetidos M vezes a complexidade O(N2), ou seja, a complexidade final tanto de melhor quanto de pior caso é O(M * N2). Ordenação de dados com métodos eficientes e uso de Python 1. O algoritmo de ordenação rápida utiliza um pivô para recursivamente ordenar o vetor. Em cada chamada da função de partição, os elementos menores que o pivô são colocados na esquerda e os maiores que o pivô na direita. Essa operação é repetida até que reste apenas um elemento. Dado o vetor [13, 87, 63, 91, 55] e o pivô 55, qual das opções a seguir é válida após a primeira execução da função partição? Você acertou! A. [13, 55, 63, 91, 87]. O algoritmo de ordenação rápida utiliza pivôs para ordenar o vetor. Nesse exercício, o objetivo é executar uma vez a função de partição utilizando o pivô 55. O vetor original é o [13, 87, 63, 91, 55]. Da esquerda para a direita, os elementos menores que o pivô vão sendo armazenados, enquanto na direita os maiores que o pivô. O próprio pivô é inserido à direita dos menores elementos. No caso desse exemplo, o 13 é o único elemento menor que o pivô. O 55, que é o pivô, é trocado pelo 87, que é a primeira posição após o elemento menor. Nesse caso, o vetor após a primeira execução da função partição será [13, 55, 63, 91, 87]. 2. A complexidade de tempo de melhor caso da ordenação rápida ocorre quando o elemento escolhido como pivô divide o vetor exatamente ao meio. No exemplo [M, Q, S, I, B], qual elemento escolhido como pivô resultaria no melhor caso de execução da ordenação rápida? Você acertou! E. M. O melhor caso da ordenação rápida ocorre quando o pivô escolhido é a mediana do vetor analisado. No exemplo do nosso vetor [M, Q, S, I, B], a mediana é o M, que dividiria o vetor em dois subvetores: [I, B] e [Q, S]. 3. A ordenação por mistura ordena, de forma recursiva, sequências a partir de subsequências já ordenadas. Na fase de divisão, os elementos são recursivamente divididos. Dado o vetor [7, 4, 9, 5, 1], quantas chamadas recursivas serão feitas na fase de divisão? Você acertou! E. 8. O vetor original é o [7, 4, 9, 5, 1]. As duas primeiras chamadas recursivas serão [7, 4, 9] e [5, 1]. Após, serão feitas mais quatro chamadas: [7, 4]; [9]; [5] e [1]. Por fim, mais duas chamadas serão feitas: [7] e [4]. O total de chamadas recursivas é 8. 4. O melhor e o pior caso da ordenação por mistura é o mesmo, O(n log2 n). Dado um vetor totalmente desordenado [8, 7, 6, 5, 4, 3, 2, 1], qual será o estado do vetor após duas execuções da função merge? Você acertou! B. [7, 8, 5, 6, 4, 3, 2, 1]. Inicialmente, a ordenação por mistura irá dividir os elementos até chegar em vetores de tamanho um. Após, a fase de conquista começará e a função merge será utilizada. A recursão vai toda para a esquerda e a primeira execução do merge irá ordenar o vetor [8, 7], resultando em [7, 8, 6, 5, 4, 3, 2, 1]. Na segunda execução do merge, o vetor [6, 5] será ordenado. Resultando no vetor [7, 8, 5, 6, 4, 3, 2, 1]. 5. A implementação dos algoritmos eficientes tem como base a técnica de divisão e conquista. Em ambas as ordenações, por mistura e rápida, o ponto-chave é a complexidade de tempo das funções de partição e de merge. Qual é a complexidade de tempo dessas funções quando executadas N vezes para um vetor de N posições? Vocêacertou! D. O(N2). A complexidade de ambos os algoritmos é Nlog2 N, sendo que log2 N é a altura da árvore de divisão e N é o custo de cada chamada, as funções partição e merge. A questão pergunta a complexidade de executar essas funções N vezes. O que resulta em N vezes O(N), ou seja, O(N2). Árvores: estruturas hierárquicas 1. Alguns problemas requerem estruturas que possibilitem operações como inserção e remoção de maneira dinâmica, tais como as árvores. Em relação às árvores e suas vantagens em relação às demais estruturas, marque a alternativa correta. Você acertou! B. Árvores são consideradas eficientes para guardar informações, pois apresentam uma forma de organização não linear. Devido à topologia hierárquica das árvores, os dados podem ser localizados facilmente, quando comparadas a estruturas lineares, tais como listas, filas e pilhas. Além disso, normalmente os dados são alocados dinamicamente na memória. Sua forma e inserção pode respeitar algumas propriedades, mas não limita que sejam inseridas nas extremidades (início e fim). 2. Considere que você precisa utilizar uma árvore binária e o TAD deve ter um campo para armazenar um número inteiro. Os nós podem ser representados na linguagem Python como uma classe com os seguintes atributos básicos: Você acertou! A. Número do nó, ponteiro para subárvore da direita e ponteiro para subárvore da esquerda. Um TAD para representar um nó, de maneira básica, precisa ter três campos: - um campo para armazenar a informação do nó e, como o enunciado cita inteiros, as alternativas com strings e listas (visto que é apenas uma informação) são eliminadas. - um campo para referenciar a subárvore da esquerda. - um campo para a subárvore da direita. Veja que também não precisa de lista e de ponteiro para o pai. 3. Durante a implementação de um TAD hierárquico, será necessário conhecer alguns termos para projetar os métodos. Acerca das terminologias da estrutura de dados do tipo árvore, considere a imagem a seguir e marque a alternativa correta: Você acertou! C. O grau do nó E é 2. Alguns temos importantes para classificar as árvores são: - o grau de um nó que é dado pelo número de arestas que incidem neste nó. - a altura de uma árvore está relacionada ao seu nível máximo, essa árvore tem altura 3. - os nós folhas têm subárvore da direita e da esquerda vazias, ou seja, grau zero. - O nível de um nó é sua distância do nó raiz, logo o nó raiz tem nível igual a zero. Como você pode observar, essa árvore tem altura igual a três e seus nós folhas são D, G, H e F. O grau do nó C é um, já o grau do nó B e E é igual a dois. No segundo nível estão os nós D, E e F. 4. Dada a seguinte árvore e considerando as propriedades de armazenamento de uma árvore binária, após a inserção do nó 9 e do nó 5, nessa ordem, pode-se afirmar que esses nós serão filhos dos nós: Você acertou! B. 9 será filho da esquerda do nó 10 e 5 será filho da direita do nó 4. Durante a inserção em uma árvore binária deve-se respeitar a propriedade em que os maiores valores são inseridos à direita e menores são inseridos à esquerda. Inicia-se a inserção pela raiz e essa propriedade é verificada em cada subárvore até encontrar o pai. Nesse exemplo, o 9 será filho à esquerda do nó 10 e o 5 será filho à direita do nó 4. 5. Caso você tivesse que indicar uma estrutura de dados apropriada para armazenar uma sequência de comandos HTML e verificar sua sintaxe antes de apresentar as informações no browser, qual estrutura você indicaria? Você acertou! E. Árvore A linguagem HTML verifica os comandos digitados, analisando se eles pertencem a uma determinada tag que o programador está usando e, para agilizar as consultas, as informações são organizadas de maneira hierárquica. Nesse caso, uma árvore seria a estrutura ideal. Caminhamento em árvore 1. As árvores são estruturas de dados de grande contribuição, principalmente no que tange as expressões aritméticas, em que o percurso utilizado pode influenciar diretamente. O caminhamento em árvore é realizado de três formas, as quais variam conforme a posição de leitura do nó raiz, que podem ser: Você acertou! D. em-ordem, pós-ordem, pré-ordem. Os percursos realizados em árvores binárias variam em três tipos, conforme a posição de leitura do nó raiz, podendo ser pré-ordem, quando a raiz de cada subárvore é lida anteriormente às subárvores esquerda e direita. Quando somente a subárvore esquerda é visitada antes do nó raiz, dá-se o nome de percurso em-ordem. E quando tanto a subárvore esquerda como a direita são lidas anteriormente à raiz, atribui-se o percurso pós-ordem. 2. Árvores binárias possibilitam maior organização dos elementos adicionados, o que facilita separar os elementos a cada nível de crescimento da árvore. Dada a seguinte lista de caracteres [P, R, O, G, R, A, M, A, D, O, R, U, M], como ficaria seu resultado final em uma leitura pós-ordem, caso seus valores fossem adicionados sequencialmente, do primeiro ao último elemento, em uma árvore binária? Para montar uma árvore binária, os elementos menores ou iguais ao nó mais abaixo entrará à esquerda; caso contrário, ficará à direita. Você acertou! B. A D A M O M G O R R U R P. 3. Uma árvore binária que tenha como finalidade resolver problemas aritméticos, necessita que sua leitura seja feita de tal modo a combinar dois operandos para o operador da expressão. Exemplo: A + B. Portanto, como uma árvore deveria posicionar seus elementos e qual seria a melhor forma de leitura para que as operações ocorram? Você acertou! B. É preferível que os valores da operação aritmética estejam localizados à esquerda e à direita da raiz, desde que o operador seja raiz, e a leitura da árvore seja feita em-ordem. Em uma árvore binária, para avaliar expressões aritméticas, é importante organizá-la de tal forma que os operadores dividam simetricamente cada subexpressão, de modo a facilitar sua leitura. Tendo este objetivo em mente, é preferível que existam os operadores (soma, subtração, multiplicação e divisão), ocupando sempre a raiz, separando de forma mais simétrica os operandos (valores) da expressão, para uma leitura realizada em-ordem. 4. O caminhamento de uma árvore binária influencia diretamente no resultado final de leitura de uma determinada sequência de símbolos, e pode se encontrar em 3 tipos, como percursos em pré-ordem, in-ordem e pós-ordem, variando, assim, a posição do valor raiz. Qual função a seguir descreve o percurso realizado em pós-ordem? Você acertou! A. def funcao(no): if atual != None: funcao(no.esquerdo) funcao(no.direito) print("Valor: {}.".format(no.valor)) A ordem dos elementos visitados em pós-ordem estabelece que os elementos da subárvore à esquerda serão visitados, seguidos dos elementos das subárvores à direita e, por fim, os elementos raízes. Mesmo que todas as funções apresentem recursividade, apenas a função com a impressão sucedendo às duas chamadas recursivas para as subárvores esquerda e direita imprimem o caminho pós-ordem. 5. O modo como é feito o percurso determina como será o nível de prioridade de leitura dos elementos, podendo o nó raiz estar com prioridade (leitura em pré-ordem), ou os elementos da subárvore à esquerda (leitura in-ordem), ou os elementos da subárvore à esquerda seguido da leitura à direita (pós-ordem). Considerando a imagem a seguir, mostre a sequência de expressões resultantes, conforme os percursos de pré-ordem, em-ordem e pós-ordem, respectivamente. Você acertou! C. * 3 * 5 13 3 * 5 * 13 3 5 13 * * Os percursos variam conforme a sua modalidade, a qual está relacionada à posição de visita do nó raiz. Neste caso, onde é desejado obter as 3 formas de leitura, é possível identificar um padrão no posicionamento do operador aritmético, cujo posicionamento está mais à esquerda na leitura em pré-ordem: * 3 * 5 13; está mais simétrico na leitura em-ordem: 3 * 5 * 13; e mais à direita para a leituraem pós-ordem: 3 5 13 * *. Pesquisa binária 1. A estrutura de dados de árvore apresenta grande versatilidade. Pode ser aplicada na solução de um leque de problemas, como em indexação de bancos de dados, em buscas, em estruturas de diretórios em sistemas de arquivos, entre outros. Considerando uma árvore binária de busca, qual destas é uma de suas propriedades? Você acertou! B. A subárvore esquerda de um nó contém os nós com chaves menores ou iguais que a do nó. Para uma árvore agir como uma árvore de busca, os valores armazenados em cada nó devem ser maiores que qualquer outro que esteja na subárvore esquerda e menores do que os salvos em subárvores à direita. Logo, a subárvore esquerda de um nó contém os nós com chaves menores ou iguais ao nó referente; a subárvore direita de um nó contém os nós com chaves maiores que o nó referente; e as subárvores esquerda e direita também devem ser uma árvore de pesquisa binária. De acordo com a propriedade de uma árvore de busca, uma subárvore à esquerda não pode receber chaves maiores que o nó. Além disso, em uma árvore binária de busca, cada nó pode ter, no máximo, dois filhos. Sobre o tipos e os valores armazenados nos nós, não exitem restrições: pode ser tanto uma string como um valor numérico qualquer, e, quando se trata de valores numéricos, também não existem restrições se o valor é positivo ou negativo. 2. Uma árvore binária de busca é conhecida pela sua eficiência quando é necessária a pesquisa de algum valor, seguindo as regras de buscas, ramificando para a esquerda e para a direita. Sabendo disso, de acordo com a árvore na imagem, determine qual caminho a chave de busca percorreu para pesquisa do valor 87 e se este existe ou não. Você acertou! D. Visitou chave 70. Visitou chave 90. Visitou chave 83. Visitou chave 85. Visitou chave 89. Resultado: falha. Considerando que a raiz da árvore corresponde ao valor 70, para o número procurado (87), precisaremos caminhar pela subárvore à direita. Em seguida, será visitado nó de chave 90, porém o valor procurado ainda não é esse, e, como 87 é menor que 90, será explorada à subárvore à esquerda do nó de chave 90, resultando em uma visita ao nó de chave 83. Como 87 é maior que 83, seguiremos à procura pela subárvore à direita desse nó, chegando ao nó de chave 85. O valor 87 é maior que 85, fazendo com que seja realizada a leitura ao último nó dessa ramificação: o nó de chave 89. Como não existem mais elementos a serem explorados a partir do nó de chave 89, o resultado obtido é de falha, pois o elemento 87 não existe. 3. Sempre que vimos uma árvore, presumimos a ordem em que seus elementos foram adicionados. Dessa forma, conforme a imagem utilizada no exercício anterior, defina uma possível ordem do vetor que culminou na árvore apresentada, lembrando que o primeiro valor corresponde à raiz da árvore. Você acertou! B. [70,90,4,114,2,23,83,116,72,15,85,89,63]. Podemos verificar a ordem de cada elemento fazendo uma pequena inserção em uma árvore abstrata. Ao criar uma árvore binária sem balanceamento, temos sempre que considerar sua forma de organizar seus valores. Logo, se o valor 89, que é uma folha, for adicionado antes do valor 85, o valor 89 que antes não tinha nenhuma ramificação passará a ter o nó 85 como subárvore esquerda. Seguindo esse raciocínio, podemos estabelecer uma possível ordem como: [70,90,4,114,2,23,83,116,72,15,85,89,63]. 4. Uma árvore binária de busca, como o próprio nome sugere, é uma estrutura de dados que armazena dados de maneira que permita a realização de busca binária. Essa busca segue o paradigma de divisão e conquista e acaba tendo uma eficiência melhor do que uma busca linear. Existem duas abordagens para realizar a implementação dessa busca: a implementação recursiva e iterativa. Qual a principal diferença entre essas implementações? Você acertou! C. Na abordagem recursiva, um nó definido como base nele próprio realiza a repetição dos seus passos invocando a si próprio, executando todos os seus passos novamente até encontrar o valor buscado. Diferentemente da busca recursiva, a busca iterativa considera as ramificações de maneira explícita de cada nó para percorrer seus nós, pois não há uma chamada interna para a mesma função. A abordagem recursiva realiza autorreferência, ou seja, ocorre quando algo é definido em termos de si mesmo. No caso da árvore, um nó é definido com base nele próprio até achar o valor buscado; já no método iterativo, a busca é realizada percorrendo explicitamente todos os nós da árvore até se encontrar o valor buscado. Além disso, apenas o método iterativo usa laços de repetição, como while e for. E, apesar de serem abordagens diferentes, ambas visitam os mesmos nós no processo de busca por determinado valor. 5. Em termos de alocação de memória, podemos implementar uma árvore de busca binária utilizando alocação dinâmica ou alocação estática. Considerando a alocação estática, como ocorre a representação de uma árvore de pesquisa binária em um vetor? Você acertou! A. 1- O nó raiz deve ficar na posição inicial do vetor. 2- Para cada nó em determinada posição i de um vetor, seu filho esquerdo ficará na posição 2*i + 1, e seu filho direito ficará na posição 2*i + 2. As árvores também podem ser implementadas sob listas fixas ou estáticas, que ocorrem por meio da distribuição dos nós da árvore ao longo de um vetor (array). Essa distribuição ocorre da seguinte forma: o nó raiz será o primeiro elemento do vetor, e, para cada nó em determinada posição i do vetor, seu filho esquerdo ficará na posição 2*i + 1, e seu filho direito ficará na posição 2*i + 2. Balanceamento de árvore 1. Uma das principais vantagens das árvores binárias em relação às demais estruturas de dados é a sua eficiência no processo de realizar buscas. A árvore AVL é conhecida por ter um resultado muito eficiente durante a operação de busca, pois realiza uma distribuição homogênea dos dados. Qual a ideia central ao fazer o balanceamento em uma árvore? Você acertou! A. A ideia central do balanceamento é que, para cada novo elemento adicionado ou removido da árvore, seja realizado uma reorganização para que a distribuição dos elementos conforme sua subárvore, continue homogênea. No que tange o balanceamento, a ideia central é que para cada novo elemento adicionado ou removido da árvore, seja realizada uma reorganização para que a distribuição dos elementos, conforme sua subárvore, continue homogênea. Em uma árvore AVL não existe a necessidade de as subárvores terem a mesma quantidade de nós, e seus nós não têm valores de pesos. Além disso, existe mais de um tipo de árvore balanceada, as quais têm um objetivo de retornar uma busca eficiente. 2. As árvores AVL correspondem à família das árvores binárias, em que a distribuição dos elementos é feita de acordo com determinadas condições, as quais são necessárias para garantir o balanceamento da árvore. Em relação à altura de uma AVL, qual é a afirmação correta? Você acertou! D. A altura de uma árvore nula é igual a -1. Uma árvore balanceada é assim chamada por alguns critérios, sendo um deles, a altura: Altura: a altura de uma árvore é o nível máximo de suas folhas. Em algumas literaturas, é determinado como profundidade de uma árvore. A altura de uma árvore nula, por exemplo, é definida como –1, e uma árvore binária balanceada é uma árvore em que as alturas de suas subárvores (esquerda e direita) de todo nó nunca diferem em mais de 1. Quando a árvore tem apenas um elemento, sua altura é de zero. Logo, quando não tiver nenhum elemento, essa árvore é nula, e sua altura é -1. 3. Uma árvore AVL é uma árvore binária muito utilizada para armazenamento de dados em memória. Cada nó de uma árvore AVL necessita da informação de altura, pois é fundamental para o processo de balanceamento. Para um nó folha, que tem uma altura igual a 1, sendo que essa árvore AVL tem 7 nós. Qual é a altura máxima que essa árvore podeter? Você acertou! D. 3. Para encontrar a altura máxima, os nós devem ser mínimos em cada nível. Supondo altura como 3, número mínimo de nós necessário: N (h) = N (h-1) + N (h-2) + 1 N (3) = N (2) + N (1) + 1 = 4 + 2 + 1 = 7 Logo, a altura máxima é 3. 4. Uma árvore AVL tem as funções básicas como inserção, remoção e busca, assim como uma árvore simples. Considere a seguinte árvore AVL. Qual das alternativas a seguir é a árvore AVL atualizada após a inserção de 70? Você acertou! C. 5. No processo de realizar o balanceamento de uma árvore AVL, após a exclusão ou inclusão são realizadas operações para realizar o balanceamento. Quais das seguintes operações são usadas pelas árvores AVL? Você acertou! A. Rotação à esquerda e rotação à direita. Para auxiliar no processo de balanceamento das árvores AVL, são utilizadas as operações de rotação à esquerda e à direita, com o objetivo de redistribuir os elementos de maneira homogênea. A operação de recoloração de nós pertence à árvore rubro-negra; não existe esse ajuste por altura de peso, e as funções de caminhamento têm apenas a função de percorrer os nós.
Compartilhar