Docsity
Docsity

Prepare-se para as provas
Prepare-se para as provas

Estude fácil! Tem muito documento disponível na Docsity


Ganhe pontos para baixar
Ganhe pontos para baixar

Ganhe pontos ajudando outros esrudantes ou compre um plano Premium


Guias e Dicas
Guias e Dicas

ALGORITMOS E COMPLEXIDADE - TEMA 2, Resumos de Autômatos e Teoria da Complexidade

TEMA 2 - RESUMO DA MATERIA ALGORITMOS E COMPLEXIDADE

Tipologia: Resumos

2025

Compartilhado em 29/04/2025

eliza-leal-suzano
eliza-leal-suzano 🇧🇷

5 documentos

1 / 74

Toggle sidebar

Baixe o documento completo

Comprando um plano Premium

e ganhe os pontos que faltam em 48 horas

bg1
DESCRIÇÃO
Conceitos de análise de algoritmos, os tipos de estruturas de dados homogêneas, heterogêneas e
ponteiros, análise da complexidade dos algoritmos, notação O, como avaliar a complexidade dos
algoritmos.
PROPÓSITO
Apresentar os conceitos básicos para o entendimento da construção de algoritmos, empregando os tipos
de estrutura de dados básicos. Compreender a importância da análise de algoritmos, permitindo a
construção de programas com desempenho adequado à necessidade dos usuários. Empregar a notação
O e utilizar exemplos práticos para entender a análise de algoritmo.
PREPARAÇÃO
Antes de iniciar o conteúdo deste tema, tenha em mãos um livro de Matemática do ensino médio que
apresente os conceitos de funções matemáticas, como função lineares, funções quadráticas,
exponenciais e logarítmicas.
OBJETIVOS
pf3
pf4
pf5
pf8
pf9
pfa
pfd
pfe
pff
pf12
pf13
pf14
pf15
pf16
pf17
pf18
pf19
pf1a
pf1b
pf1c
pf1d
pf1e
pf1f
pf20
pf21
pf22
pf23
pf24
pf25
pf26
pf27
pf28
pf29
pf2a
pf2b
pf2c
pf2d
pf2e
pf2f
pf30
pf31
pf32
pf33
pf34
pf35
pf36
pf37
pf38
pf39
pf3a
pf3b
pf3c
pf3d
pf3e
pf3f
pf40
pf41
pf42
pf43
pf44
pf45
pf46
pf47
pf48
pf49
pf4a

Pré-visualização parcial do texto

Baixe ALGORITMOS E COMPLEXIDADE - TEMA 2 e outras Resumos em PDF para Autômatos e Teoria da Complexidade, somente na Docsity!

DESCRIÇÃO

Conceitos de análise de algoritmos, os tipos de estruturas de dados homogêneas, heterogêneas e ponteiros, análise da complexidade dos algoritmos, notação O, como avaliar a complexidade dos algoritmos.

PROPÓSITO

Apresentar os conceitos básicos para o entendimento da construção de algoritmos, empregando os tipos de estrutura de dados básicos. Compreender a importância da análise de algoritmos, permitindo a construção de programas com desempenho adequado à necessidade dos usuários. Empregar a notação O e utilizar exemplos práticos para entender a análise de algoritmo.

PREPARAÇÃO

Antes de iniciar o conteúdo deste tema, tenha em mãos um livro de Matemática do ensino médio que apresente os conceitos de funções matemáticas, como função lineares, funções quadráticas, exponenciais e logarítmicas.

OBJETIVOS

MÓDULO 1

Definir os conceitos básicos para construção de algoritmos

MÓDULO 2

Definir as estruturas de dados manipuladas pelos algoritmos

MÓDULO 3

Definir a notação O e suas aplicações práticas

MÓDULO 4

Empregar a análise da complexidade dos algoritmos

INTRODUÇÃO

Algoritmos são a estrutura básica para a criação de soluções para problemas computacionais. A modularização de algoritmos é a principal forma para diminuir a complexidade desses problemas.

Os módulos ou subprogramas passam a tratar partes menores da complexidade do problema, facilitando a compreensão e futuras manutenções que serão necessárias durante o ciclo de vida de um software. A modularização também diminui o retrabalho, pois permite que trechos de códigos sejam reutilizados em outros locais no mesmo sistema.

Após a definição de um algoritmo, é necessário passar por uma otimização. Por mais que, atualmente, os computadores possuam uma capacidade computacional bastante poderosa, principalmente comparando com os recursos computacionais de décadas atrás, a otimização permite que o sistema possa ter um desempenho muito mais adequado, oferecendo ao usuário uma melhor experiência de uso.

A complexidade dos problemas cresceu tão rápido quanto a capacidade computacional, portanto é fundamental a capacidade de analisar diversos algoritmos para um problema complexo para se chegar

Fonte: Shutterstock

A complexidade pode ser reduzida, reduzindo-se a variedade. E a variedade pode ser reduzida, dividindo problemas maiores em problemas menores. Os problemas menores são tratados através do emprego de sub-rotinas, que terão complexidade menor e poderão ser implementadas de uma forma mais fácil.

Uma técnica que será estudada para a decomposição de problemas é conhecida como top-down, a qual será estudada mais adiante, e que irá definir as sub-rotinas que devem ser criadas para a resolução dos problemas.

SUB-ROTINAS

Sub-rotinas, também chamadas de subprogramas, são blocos de instruções que realizam tarefas específicas. É um trecho de programa com atribuições específicas, simplificando o entendimento do programa principal, proporcionando ao programa menores chances de erro e de complexidade. Elas são utilizadas para diminuir a complexidade de problemas complexos.

Os programas, de acordo com Ascêncio (2012), tendem a ficar menores e mais organizados, uma vez que o problema pode ser subdivido em pequenas tarefas. Em resumo, são pequenos programas para resolver um problema bem específico. Uma sub-rotina não deve ser escrita para resolver muitos problemas, senão ela acabará perdendo o seu propósito.

OBJETIVOS

Uma sub-rotina possui os seguintes objetivos:

Dividir e estruturar um algoritmo em partes logicamente coerentes.

Facilidade em testar os trechos em separado.

Aumentar a legibilidade de um programa.

Evitar que uma certa sequência de comandos necessária em vários locais de um programa tenha que ser escrita repetidamente nestes locais, diminuindo também, o código fonte.

O programador poderá criar sua própria biblioteca de funções, tornando sua programação mais eficiente, uma vez que poderá fazer uso de funções por ele escritas em vários outros programas com a vantagem de já terem sido testadas.

VANTAGENS

Uma sub-rotina possui as seguintes vantagens:

Clareza e legibilidade no algoritmo.

Construção independente.

Testes individualizados.

Simplificação da manutenção.

Reaproveitamento de algoritmos.

DECOMPOSIÇÃO DE PROBLEMAS

Um método adequado para realizar a decomposição de problemas é trabalhar com o conceito de programação estruturada, pois a maior parte das linguagens de programação utilizadas atualmente também são adequadas a este tipo de paradigma, o que facilita a aplicação deste processo de trabalho. O método mais adequado para aplicar a técnica de decomposição de problemas é o top-down, segundo Manzano e Oliveira (2016).

Este método permite que o programa tenha uma estrutura semelhante a um organograma.

A figura mostra um exemplo da estrutura top-down.

Uma sub-rotina é um bloco contendo início e fim, sendo identificada por um nome, pelo qual será referenciada em qualquer parte e em qualquer momento do programa.

SUB-ROTINA

A sub-rotina serve para executar tarefas menores, como ler, calcular, determinar o maior/menor valor entre uma lista de valores, ordenar, converter para maiúsculas, entre outras.

Como uma sub-rotina é um programa, ela poderá efetuar diversas operações computacionais, como entrada, processamento e saída, da mesma forma que são executadas em um programa.

A sintaxe genérica de uma sub-rotina é a seguinte:

sub-rotina < nome_da_sub-rotina > [(tipo dos parâmetros : < sequência de declarações de parâmetros

)] : < tipo de retorno >

var < declaração de variáveis locais >; Início comandos que formam o corpo da sub-rotina retorne(< valor >) ; /* ou retorne; ou nada */ Fim sub-rotina

Onde:

Glossário

tipo de retorno Sequência de declarações de parâmetros corpo da sub-rotina

nome da sub-rotina início retorne ( .. )

parâmetros variáveis locais Fim sub-rotina

Atenção! Para visualizaçãocompleta da tabela utilize a rolagem horizontal

TIPO DE RETORNO

Tipo de dado que a sub-rotina dará retorno.

SEQUÊNCIA DE DECLARAÇÕES DE PARÂMETROS

Declarações de variáveis da sub-rotina (tipo e nome).

CORPO DA SUB-ROTINA

Sequência de comandos.

NOME DA SUB-ROTINA

Segue as mesmas regras de declaração de variáveis da linguagem utilizada.

INÍCIO

Início da sub-rotina.

//declaração de sub-rotina sub-rotina soma(inteiro: a,b): inteiro var resultado: inteiro; início resultado <- a + b; retorne resultado; fim sub-rotina início n <- 8; m <- 4; escreva(soma(n, m)); //chamada da sub-rotina (soma) fim Algoritmo.

CHAMADA DE SUB-ROTINA

Uma sub-rotina pode ser acionada de qualquer ponto do algoritmo principal ou de outra sub-rotina. O acionamento de uma sub-rotina é conhecido por chamada ou ativação.

Quando ocorre uma chamada, o fluxo de controle é desviado para a sub-rotina, quando ela é ativada no algoritmo principal. Ao terminar a execução dos comandos da sub-rotina, o fluxo de controle retorna ao comando seguinte àquele onde ela foi ativada, exatamente conforme o seguinte algoritmo:

algoritmo() {... ... < chamada da sub-rotina > ... ... } sub-rotina(...) { ... retorne(...); }

Pode ocorrer que um algoritmo tenha mais de uma sub-rotina. Desta forma, teremos várias chamadas a partir do programa principal a cada uma das sub-rotinas.

 EXEMPLO

O exemplo abaixo mostra um algoritmo com duas sub-rotinas sendo chamadas, veja que o fluxo de execução passa para a sub-rotina chamada (primeira sub-rotina). Ao final da execução da primeira sub- rotina, o controle retorna para o programa principal.

O mesmo procedimento ocorre com a chamada para a segunda sub-rotina, ao final da execução o controle retorna para o programa principal que segue o seu fluxo normal de execução, conforme a figura:

Fonte: Autor

PARAMETRIZAÇÃO DE SUB-ROTINAS

É possível tornar uma sub-rotina mais genérica e, portanto, mais reutilizável. Isso pode ser feito através da utilização de parâmetros. Parâmetros são os valores que uma sub-rotina pode receber antes de iniciar a sua execução.

 COMENTÁRIO

A ativação do módulo precisa indicar os argumentos (valores constantes ou variáveis que serão passados para a sub-rotina). E a passagem dos valores ocorre a partir da correspondência (ordem) argumento X parâmetro.

Podemos ter, por exemplo, uma sub-rotina para exibir a tabuada de oito. Essa sub-rotina poderia ser mais genérica caso fosse possível exibir a tabuada de qualquer número utilizando um parâmetro. Desta forma, a sub-rotina poderia ser executada para calcular a tabuada de qualquer valor passado como parâmetro.

Fonte: O Autor

Na passagem de parâmetros por valor, o valor da variável na chamada é copiado para a variável da função. As alterações realizadas dentro da função não são refletidas na variável original.

Portanto, a substituição de valores na sub-rotina troca (inteiro: x, y) ocorrerá apenas dentro da sub- rotina, não alterando os valores das variáveis a e b.

Outra forma de passar valores por parâmetros é a passagem por referência, onde os endereços de memória das variáveis são acessados diretamente e alterações nos valores são refletidas nas variáveis originais.

Se a passagem de parâmetros da sub-rotina troca (inteiro: x, y) fosse por referência, os valores das variáveis teriam sido comutados entre si.

Existem sub-rotinas que podem receber parâmetros e retornar um valor para o programa principal ou ainda sub-rotinas que recebem parâmetros e não retornam nenhum valor para o programa principal.

As primeiras são chamadas de funções enquanto as últimas, além de receberem a denominação de funções, são também chamadas de procedimentos em algumas linguagens de programação.

Seguem dois exemplos de sub-rotinas, uma função com retorno e um procedimento. Os dois exemplos utilizam uma estrutura de repetição para somar os valores de 1 a 10, mostrando no final o valor da soma.

Vamos ver o primeiro exemplo com retorno.

Algoritmo somaValoresComRetorno; var resultado : inteiro; // declaração de sub-rotina // utilizei o nome procedimento, poderia ser utilizado sub-rotina procedimento somaValores( ) var

soma : inteiro; inicio soma <- 0; para i de 1 até 10 faça soma <- soma + i; fim-para retorne soma; fim procedimento; inicio resultado <- somaValores( ); escreva(“ A soma dos valores é “, soma); fim Algoritmo.

Agora, vamos ver o segundo exemplo sem retorno.

Algoritmo somaValoresSemRetorno;

// declaração de sub-rotina // utilizei o nome função, também poderia ser utilizado sub-rotina função somaValores( ) var soma : inteiro; inicio soma <- 0; para i de 1 até 10 faça soma <- soma + i; fim-para escreva(“ A soma dos valores é “, soma); fim procedimento;

inicio somaValores( ); fim Algoritmo.

VAR

< DECLARAÇÃO DE VARIÁVEIS LOCAIS >;

INÍCIO

COMANDOS QUE FORMAM O CORPO DA SUB-ROTINA

RETORNE(< VALOR >) ; /* OU RETORNE; OU NADA */

FIM SUB-ROTINA

DAS OPÇÕES APRESENTADAS ABAIXO, MARQUE A QUE APRESENTA APENAS

PARTES OBRIGATÓRIAS DE FORMA QUE A FUNÇÃO EXECUTE ALGUMA

TAREFA, SEM LEVAR EM CONSIDERAÇÃO OS SÍMBOLOS (CHAVES,

PARÊNTESES, PARÂMETROS, DENTRE OUTROS).

A) Tipo de retorno, nome e corpo da função

B) Tipo de retorno, parâmetro e corpo da função

C) Tipo de retorno, nome e parâmetros

D) Tipo de retorno, nome, parâmetros e corpo da função

2. A MODULARIZAÇÃO DE ALGORITMOS É IMPORTANTE PARA ORGANIZAR

MELHOR O CÓDIGO, FACILITAR A MANUTENÇÃO, ENTRE OUTRAS COISAS.

SOBRE FUNÇÕES E PROCEDIMENTOS, ASSINALE A ALTERNATIVA CORRETA

SOBRE A MODULARIZAÇÃO:

A) O procedimento sempre retorna um valor ao programa.

B) A função retorna um valor ao programa.

C) As variáveis definidas no escopo de cada função são acessíveis em todo o programa.

D) As variáveis locais são declaradas no escopo do programa inteiro.

GABARITO

1. Funções são usadas para criar pequenos pedaços de códigos separados do programa principal. Elas são importantes porque elas retornam valores, ajudam a fragmentar o código em partes menores - mais fáceis de lidar - e ainda por cima podem ser utilizadas mais de uma vez no mesmo programa, poupando preciosos minutos de programação e inúmeras linhas de código. Na definição de uma função, precisamos escrever suas partes, sendo algumas obrigatórias e outras, facultativas.

sub-rotina < nome_da_sub-rotina > [( tipo dos parâmetros : < sequência de declarações de parâmetros > )] : < tipo de retorno > var < declaração de variáveis locais >; início comandos que formam o corpo da sub-rotina retorne(< valor >) ; / ou retorne; ou nada / Fim sub-rotina

Das opções apresentadas abaixo, marque a que apresenta apenas partes obrigatórias de forma que a função execute alguma tarefa, sem levar em consideração os símbolos (chaves, parênteses, parâmetros, dentre outros).

A alternativa "A " está correta.

Os parâmetros em funções não são obrigatórios. Em uma função são obrigatórios: o tipo de retorno, nome e corpo da função.

2. A modularização de algoritmos é importante para organizar melhor o código, facilitar a manutenção, entre outras coisas. Sobre funções e procedimentos, assinale a alternativa correta sobre a modularização:

A alternativa "B " está correta.

As funções sempre retornam um valor ao programa principal. Os procedimentos não retornam um valor ao programa principal.

MÓDULO 2

 Definir as estruturas de dados manipuladas pelos algoritmos

INTRODUÇÃO

Os tipos primitivos (inteiro, real, caractere e lógico) não são suficientes para representar todos os tipos de informação, particularmente quando temos mais de uma informação relacionada, por exemplo, uma

Um vetor é uma variável homogênea que repete um tipo de dado um número específico de vezes. Ou seja, é um arranjo de elementos armazenados na memória principal, um após o outro, todos com o mesmo nome. A ideia é a mesma de uma matriz linha da matemática, isto é, várias colunas e uma linha. Este tipo de estrutura, em particular, é também denominado como arranjo unidimensional.

Um exemplo de vetor de valores inteiros está representado abaixo.

Fonte: O Autor

Esse é um vetor de 10 elementos, isto é, tem 10 variáveis, todas com o mesmo nome e diferentes por sua posição dentro do arranjo que é indicada por um índice.

Quando se tem somente uma linha, podemos omiti-la e colocar somente a coluna. Em algoritmos, expressamos da seguinte forma:

Fonte: O Autor

DECLARAÇÃO

A declaração de um vetor caracteriza-se por ser definida uma única variável dimensionada com um determinado tamanho. A dimensão de um vetor é constituída por constantes inteiras e positivas. Os nomes dados aos vetores seguem as mesmas regras de nomes utilizados em variáveis simples.

tipo < nome_do_vetor > [tamanho] ;

Uma variável simples somente pode conter um valor por vez. No caso dos vetores, estes poderão armazenar mais de um valor por vez, pois são dimensionados exatamente para este fim. Lembrando que

a manipulação dos elementos de um vetor ocorrerá de forma individualizada, pois não é possível efetuar a manipulação de todos os elementos do conjunto ao mesmo tempo.

Tanto a entrada como a saída de dados manipuladas em um vetor são processadas passo a passo, um elemento por vez. Estes processos são executados com o auxílio de estruturas de repetição, um looping.

Com o objetivo de apresentar o benefício do emprego de vetores, vamos imaginar que é necessário criar um algoritmo para calcular a média geral de uma turma de dez alunos. Na implementação abaixo, vamos utilizar um algoritmo sem empregar um vetor.

Algoritmo media_1; var n1, n2, n3, n4, n5, n6, n7, n8, n9, n10, media: real; Início escreva(“Entre com a nota do 1º aluno: “); ler(n1); escreva(“Entre com a nota do 2º aluno: “); ler(n2); escreva(“Entre com a nota do 3º aluno: “); ler(n3); escreva(“Entre com a nota do 4º aluno: “); ler(n4); escreva(“Entre com a nota do 5º aluno: “); ler(n5); escreva(“Entre com a nota do 6º aluno: “); ler(n6); escreva(“Entre com a nota do 7º aluno: “); ler(n7); escreva(“Entre com a nota do 8º aluno: “); ler(n8); escreva(“Entre com a nota do 9º aluno: “); ler(n9); escreva(“Entre com a nota do 10º aluno: “); ler(n10); media (n1 + n2 + n3 + n4 + n5 + n6 + n7 + n8 + n9 + n10)/10; escreva(“A média da turma é: ”, media); Fim.

 COMENTÁRIO