EA869 Algoritmos: estruturas de dados e linguagens de programação Faculdade de Engenharia Elétrica e de Computação (FEEC) Universidade Estadual de Campinas (UNICAMP) Prof. Levy Boccato 1 Introdução Problema Computável Problema Não-tratável Problema NP Problema P Encontro solução em tempo factível? COMPLEXIDADE O melhor algoritmo é O(cn) ou maior O(cn) ou maior, mas não se sabe se é a melhor solução ORDEM DE COMPLEXIDADE DO ALGORITMO O(nc) ou menor 2 Introdução As questões a respeito da computabilidade e da complexidade nos levam a refletir sobre a existência de um algoritmo para resolver um problema e sobre o custo computacional envolvido em sua execução. Tendo em mãos um algoritmo de interesse, o que é necessário fazer para que ele esteja pronto para ser executado em um computador? É preciso descrever ou expressar todos os seus passos segundo uma linguagem. Linguagens de programação Uma vez escrito nesta linguagem, o algoritmo precisa ser traduzido para um formato inteligível à máquina incumbida de sua execução. Processo de execução de um programa 3 Linguagem de máquina Na linguagem de máquina, os comandos (ou instruções) e dados que devem ser manipulados são codificados em cadeias binárias. É a linguagem mais próxima ao hardware. A programação, portanto, depende de um pleno conhecimento de como cada comando é representado e interpretado no circuito digital. Palavra de 16 bits 1010100010110101 0101110101010101 0101011101010101 1010101010101011 0101010101011110 Instrução É fácil e eficiente programar em linguagem de máquina? 4 Linguagem de máquina Vejamos um exemplo bastante simples: cb – determina se o valor do registrador B é ou não complementado. sb – seleciona entre o valor referente ao registrador B ou o valor fixo 1. la – habilita o carregamento de um valor especificado na entrada paralela do registrador A. 5 Linguagem de máquina Exemplo: Este humilde computador permite a realização de algumas operações: (1) A ← A + B (2) A ← A + 1 (3) A ← A – B Um “programa”, escrito em linguagem de máquina, que compute a subtração entre os valores em A e B, seria dado pela sequência de comandos binários: cb ← 1 sb ← 0 la ← 1 (complementa B) (seleciona o complemento de B) (armazena o resultado em A) 6 Linguagem simbólica Como poderíamos tornar o código mais compreensível ao programador? Linguagem simbólica (Assembly) Substitui o código de máquina por símbolos mais próximos da linguagem humana. Continua sendo muito próxima do hardware. Trata-se de uma linguagem dependente da arquitetura do computador (hardware). O código precisa ser interpretado, isto é, convertido ao formato binário para ser executado pelo computador. MOV R1, R2 1010100010110101 0101110101010101 MOV R1, #4 CMP R1, #4 0101011101010101 1010101010101011 BEQ FIM FIM: ADD R1, R1, 1 0101010101011110 Quais as vantagens e desvantagens desta linguagem? Etapa de montagem – veremos no final do curso 7 Linguagem simbólica Breve história da linguagem Assembly Programas eram escritos em linguagem de máquina Surgimento das linguagens de alto nível “Era dos microprocessadores” e sistemas embarcados Década de 50 Década de 70/80 Década de 90 até hoje Assembly surge para facilitar a programação Assembly passou a ser pouco usada Assembly “volta” na busca de desempenho e velocidade 8 Linguagem simbólica O uso de Assembly tem se tornado mais frequente. Mar-14 Mar-13 Change Programming Language Ratings Change 1 2 C 17.54% 0.39% 2 1 Java 16.41% -1.75% 3 3 Objective-C 12.14% 1.91% 4 4 C++ 6.31% -2.80% 5 5 C# 5.57% -1.02% 6 6 PHP 3.70% -1.11% 7 7 (Visual) Basic 2.96% -1.65% 8 8 Python 2.02% -2.37% 9 11 JavaScript 1.90% 0.53% 10 16 Visual Basic .NET 1.86% 0.97% 11 17 Transact-SQL 1.48% 0.64% 12 69 F# 1.22% 1.14% 13 10 Perl 1.15% -0.81% 14 9 Ruby 0.97% -1.18% 15 15 Delphi/Object Pascal 0.88% -0.01% 16 13 Lisp 0.75% -0.19% 17 30 D 0.74% 0.40% 18 20 Assembly 0.73% 0.10% 19 14 PL/SQL 0.71% -0.21% 20 23 MATLAB 0.69% 0.07% 9 Linguagem simbólica Muitas aplicações industriais são feitas em Assembly Mais eficiente – não gera códigos supérfluos Facilita a programação em alto nível Acesso direto e controle total do hardware Porque aprender a linguagem Assembly? Programas exigem menos memória e são menores Possibilidade de desenvolver rotinas mais eficazes e incorporá-las a programas de alto nível 10 Linguagem simbólica O que é preciso saber para programar em Assembly? Conhecer detalhes do hardware: organização da memória, registradores, periféricos, arquitetura etc. Trabalhar fluentemente com representação binária: Números negativos. Condições de overflow. Ponto flutuante. Aprender o conjunto de instruções do processador. 11 Linguagens de alto nível E como poderíamos pensar em uma linguagem executável em qualquer máquina e mais próxima da linguagem humana? Linguagens de alto nível Possuem uma semântica mais amigável ao usuário. Distante do código de máquina e muito próximo da linguagem humana. Exemplos: C, C++, C#, Java, Ruby, Python, Lisp, Prolog etc. Podem ser do tipo procedimental (descreve passo a passo) ou declarativa (descreve fatos e regras e busca uma solução lógica). public classMOV ExemploDeFor R1, R2 { public static void main(String[] args) { MOV R1, #4 for (int i = 0; i < 4; i++){ CMP R1, #4 System.out.println("Indice " + i); } BEQ FIM } FIM: ADD R1, R1, 1 } 12 Linguagens de alto nível Existem também linguagens especiais voltadas à aplicação e para outros propósitos. Linguagens voltadas à aplicação Alguns exemplos: • Aplicações matemáticas: Matlab • Voltadas a inteligência artificial: Prolog, Lisp • Linguagens esotéricas: LOLcode HAI CAN HAS STDIO? VISIBLE "OLÁ MUNDO!" KTHXBYE Piet Brainfuck ++++++++++[>++++++++>+++++++++++ >---------->+++>++++++++>+++++++ +++++>+++++++++++>++++++++++>+++ ++++++++>+++<<<<<<<<<<-]>-.>--.> ++++.>++.>---.>---.>.>.>+.>+++., 13 Processo de execução Uma vez escolhida uma linguagem de programação e escrito o código, como ele é executado? Problema Programa de alto nível resolução tradução compilador montador Algoritmo NÍVEL CONCEITUAL Programa em linguagem de máquina HIERARQUIA DE LINGUAGENS decodificação Execução HARDWARE (circuitos e sinais físicos) 14 Linguagens de Programação Ponto importante: um algoritmo pode ser expresso em qualquer linguagem de programação. Em última análise, elas servem apenas como um mediador entre o programador e a máquina. As linguagens de baixo nível (máquina e simbólica) não oferecem muitos recursos para o programador. Porém, o controle sobre sinais e aspectos de hardware é bem mais efetivo. O que muda, portanto, de uma linguagem para outra é a dificuldade e a inteligibilidade do código escrito. 15 Estruturas de dados A preparação de um algoritmo também envolve a escolha de uma forma vantajosa de organizar os dados que serão acessados e processados. Dependendo da aplicação, pode haver um tipo de organização que capture ou expresse de maneira natural uma característica dos dados associados ao problema. Veremos quatro tipos básicos: Vetor Fila Pilha Árvore 16 Estruturas de dados Suponha que certo algoritmo precise acessar a nota de um aluno dado o seu RA. Como os dados devem ser organizados? Solução: uma lista cujo índice seja o RA e o conteúdo as notas Dessa forma, é possível acessar, incluir e modificar a nota de um aluno dado o seu RA de maneira direta. Vetor: sequência de tamanho fixo cujo acesso é realizado através do índice que identifica a posição do elemento a ser lido ou escrito. Com isto, temos acesso aleatório (“direto”) e o tempo de acesso a qualquer elemento é idêntico. Leitura – vetor(i) Escrita – vetor(i) • i é fornecido • i é fornecido • elemento ← vetor(i) • vetor(i) ← elemento 17 Estruturas de dados Considere um algoritmo que deve gerenciar o atendimento telefônico de um call center. Como os dados devem ser organizados? c0 c1 REGISTRO DE DADOS c2 c3 c4 c5 c6 18 Estruturas de dados Fila: o acesso aos elementos da fila é realizado através das posições “entrada” e “saída” – as demais posições não são visíveis. Estrutura do tipo FIFO (first in, first out). Acesso: através de dois apontadores. Manipulação: apenas a entrada e a saída são visíveis. Leitura – posição “saída” Escrita – posição “entrada” • elemento ← f(j) • f(i) ← elemento • atualiza índice de saída j • atualiza índice de entrada i Fila cheia: índice de entrada i > índice máximo da fila. Fila vazia: índice de entrada i = índice de saída j. 19 Estruturas de dados Considere um algoritmo que armazena as páginas que você acessa na Internet de tal modo que seja possível retornar à primeira página acessada refazendo o mesmo caminho. Como os dados devem ser organizados? (2) (1) Devo retornar à página mais recentemente visitada. 20 Estruturas de dados Pilha: o acesso aos elementos da pilha é realizado através da mesma posição (entrada = saída) – as demais posições não são visíveis. Estrutura do tipo LIFO (last in, first out). Acesso: através de um único apontador. Leitura Escrita • atualiza o índice i • p(i) ← elemento •elemento ← p(i) • atualiza o índice i Pilha cheia: i > índice da última posição da pilha. Pilha vazia: i = índice da primeira posição da pilha. i sempre aponta para a próxima posição livre da pilha. 21 Estruturas de dados Árvore: Estrutura: cada célula contém um dado e apontador para a(s) próxima(s) célula(s). As células não precisam ser homogêneas. célula: dados apontador Manipulação: flexível, com início pela raiz. 22 Estruturas de dados Árvore: O acesso aos elementos da árvore é realizado através de um percurso a partir de sua raiz, seguindo o(s) apontador(es) das células. Todas as posições da estrutura são acessíveis. Leitura – célula j Escrita –célula j • navegar na estrutura até célula j • navegar na estrutura até célula j • elemento ← dados da célula • dados da célula ← elemento 23 Créditos Este material está baseado nas notas de aula elaboradas pelo Prof. Léo Pini e pelo aluno de doutorado Tiago Novaes. 24