Blog de Helton Duarte

O seu portal de informações sobre TI

Programando melhor: Aula 2 – Estruturas de Dados

Mais um pouco de conhecimento adquirido!

Bem pessoal, venho hoje postar a segunda aula do nosso curso “Programando melhor”, como sempre baseado no livro Programming Challenges, de Steven Skiena e Miguel Revilla, falando hoje um pouco sobre Estruturas de Dados, as quais infelizmente eu não vi no curso do CEFET-RN (atual IF-RN), contudo acredito serem essenciais para um bom programador. No final estarei indicando os links de exercícios para vocês praticarem o assunto estudado, blz? Vamos começar!

Aula 2 – Estruturas de Dados

Conteúdo: abordagem das estruturas de dados elementares, assim como mais dicas de como abordar um problema e os métodos para testar/debuggar.

Estruturas de dados são primordiais em qualquer programa robusto, sendo primordial a escolha da estrutura certa para representar o problema, evitando códigos feios e diversos bugs pela frente. ^^

Iremos mostrar as principais estruturas de dados (pilhas, filas e dicionários), com algumas operações básicas para manipulá-las. Para aqueles programadores de C++ e Java já existem bibliotecas prontas para esse controle, contudo é interessante o entendimento de como elas trabalham por dentro. Para C++: stl.h; para Java: java.util.

Pilhas: as pilhas e as filas são estruturas nas quais seus itens são controlados de acordo com a ordem de inserção e não pelo conteúdo armazenado. Ao inserir ou remover um item, fazemos em seu topo. As operações básicas são as seguintes:

Push(x, s) – Insere o item x no topo da pilha s.

Pop(s) – Retorna (e remove) o item do topo da pilha s.

Initialize(s) – Cria uma pilha vazia.

Full(s), Empty(s) – Testa se a pilha pode aceitar mais Push ou Pop, respectivamente.

Obs.: Não há operação para procurar um item na pilha, justamente pelo fato que o conteúdo não importa, somente é vista a ordem de inserção.

Filas: assim como nas pilhas, não importa o conteúdo, apenas a ordem. Nas filas os itens são inseridos em seu final e removidos do início. Um exemplo interessante do uso de filas é quando se trabalha com baralhos de cartas (tente fazer um exemplo para entender melhor XD ). A seguir, as operações:

Enqueue(x,q) – Insere o item x no fim da fila q.

Dequeue(q) – Retorna (e remove) o item da frente da fila q.

Initialize(q), Full(q), Empty(q) – Análogos às operações de pilhas.

Filas precisam de um pouco mais de cuidado, já que acontecem coisas nos dois lados da estrutura. O modo mais simples de implementação é utilizando arrays (vetores), inserindo no final e movendo todos os elementos restantes para preencher o espaço vazio do Dequeue. Contudo, temos que pensar um pouco antes de criar filas com vetores, pois é bastante desperdício esse movimento a cada Dequeue e o fato de filas circulares, ou seja, o primeiro e o último elemento são iguais. Por essas e outras, filas são estruturas mais simples de se trabalhar com listas encadeadas (um pouco sobre ponteiros para os adeptos de Pascal aqui) do que com vetores.

Dicionários: estruturas as quais pode-se trabalhar com o conteúdo dos elementos, tendo como operações primárias:

Insert(x,d) – Insere o item x no dicionário d.

Delete(x,d) – Deleta o item x (ou o item apontado por x) do dicionário d.

Search(k,d) – Retorna o item com a chave k se o mesmo existir no dicionário d.

Nós precisamos, então, saber qual é a melhor maneira de se trabalhar com esse tipo de estrutura e assim segue abaixo cada caso:

Dicionários estáticos => Essas estruturas são criadas uma vez e nunca mais mudadas, precisando então apenas do Search, não mais do Insert ou Delete. O melhor jeito para se trabalhar com eles é na utilização de vetores, sendo então sua preocupação apenas de como mantê-los ordenados, para otimizar suas buscas, contudo isso iremos ver em outras aulas.

Dicionários semi-dinâmicos => São aqueles em que se pode inserir ou pesquisar (Search), porém não pode deletar. Se soubermos o máximo de elementos, é possível a utilização de vetores, contudo sem essa informação será preciso novamente trabalhar com listas encadeadas.

Dicionários dinâmicos => Aqueles em que é permitida qualquer operação. Como muitos já devem ter percebido, a melhor maneira de se implementar esse tipo de estrutura é com a utilização de listas encadeadas, somente, para não tornar nosso código extremamente horroroso.

Finalmente chegamos ao fim dessa abordagem sobre estruturas de dados propriamente dita, esperando ter conseguido relembrar e otimizar o uso delas, além de fazê-lo mais preparado para os problemas que virão. A seguir colocarei mais dicas de resolução de problemas.

Sua solução começa agora

  • Leia o programa atentamente – Leia cada linha do problema cuidadosamente e releia quando o juiz online lhe reportar algum. Veja até mesmo a história que você acha não ter importância, no início do problema, porém preste bastante atenção às descrições de entrada/saída, além de seus exemplos.
  • Não assuma nada – Esteja atento a instruções de entrada não especificadas, números sem limites, linhas longas de entrada, números negativos, etc. NÃO ESQUEÇA: qualquer situação que não é explicitada como proibida deve ser assumida como possível!
  • Não tão rápido – Não se preocupe tanto com eficiência, a menos que você esteja passando por problemas com o juiz (como um conhecido “Time limit exceeded”). Ao conhecer bem as especificações, ou seja, sabendo qual o valor máximo para as entradas, é possível prever quão rápido necessitará ser seu algoritmo. IMPORTANTE: eu não estou incentivando códigos feios e cheios de gambiarras, todavia não é preciso um cuidado excessivo com isso logo no começo do trabalho, deu pra entender?

Testando e “debuggando”

Aprender a evitar erros bestas que podem penalizá-lo em situações de competição é crucial para o sucesso em qualquer lugar, por isso seguem abaixo algumas táticas:

  • Mesmo que pareça simples, é importantíssimo o teste feito com as entradas dadas pelo problema, pois lhe dirá qual a maneira de colocar sua saída na tela;
  • Se o problema exige determinadas ações ao se colocar entradas inválidas, certifique-se primeiramente que elas estão sendo feitas;
  • Crie sempre situações de teste simples, as quais você pode testar no papel e compare as soluções, pois pode ajudar na procura de erros mais comuns;
  • Coloque sempre entradas gigantescas (no limite do permitido), para ver como o programa se comporta, ou seja, se ele não fica “doido” com números grandes, comportando-se de maneira inesperada.
  • Conheça seu “Debugger” – Qualquer ambiente de desenvolvimento vem agora com um “debugger” (a opção de executar o programa linha por linha) e é preciso que você o conheça claramente. Quanto mais cedo você começar a usá-lo, mais tempo e frustação que você vai evitar ^^;
  • No caso de não possuir esse “debugger”, crie pontos no programa para imprimir certos valores importantes, entretanto faça-os com linhas relevantes para ler a saída rapidamente e achar os possíveis erros;
  • Faça seus vetores um pouco maiores do que o necessário – precisa comentar? É apenas para garantir que a memória não vai “acabar” durante a execução…

É isso aí! Agora vamos para os exercícios e, como já avisado, apenas colocarei os links para eles no site do UVa Online Judge:

Posts interessantes:

Como falei no meu Twitter: Bora lá pessoal, nossa guerra ainda está no começo! Animação! Qualquer dúvida sobre o assunto pode perguntar. Novamente, quando tiver dicas sobre os exercícios postarei e vocês façam o mesmo. Comentem!

Helton de Melo Duarte

“Ainda que a figueira não floresça, nem haja frutos nas vides; ainda que falhe o produto da oliveira, e os campos não produzam mantimento; ainda que o rebanho seja extirpado da malhada e nos currais não haja gado; todavia eu me alegrarei no Senhor, exultarei no Deus da minha salvação.” Habacuque 3.17,18

Fevereiro 20, 2009 - Publicado por Helton de Melo Duarte | Programando Melhor | , , , | 11 Comentários

11 Comentários »

  1. Parabéns…..!!!!!!!!!!!!!!!!!!!!!!
    :)
    :)
    :)
    Só quem BRILHA!!!!!!!!!!!!
    um bjo!

    Comentário por Dayane | Fevereiro 21, 2009

  2. Pessoal,
    Estarei ausente nesse período de carnaval e voltarei a respondê-los na quarta-feira de cinzas, ok?

    Obrigado.

    Comentário por Helton de Melo Duarte | Fevereiro 21, 2009

  3. Como dito, estou de volta para qualquer dúvida…vamos lá perguntem!

    Comentário por Helton de Melo Duarte | Fevereiro 25, 2009

  4. Valeu Helton!!!

    Parabéns pela iniciativa amigão!
    Estou tentando acompanhar sempre que possivel!

    Boa Sorte!

    Comentário por Bryan Souza | Fevereiro 26, 2009

  5. [...] Programando melhor: Aula 2 – Estrutura de Dados [...]

    Pingback por Programando melhor: Aula 3 - Strings « Blog de Helton Duarte | Março 3, 2009

  6. [...] Programando melhor: Aula 2 – Estruturas de Dados [...]

    Pingback por OBI vem aí! « Blog de Helton Duarte | Março 7, 2009

  7. [...] Programando melhor: Aula 2 – Estruturas de Dados [...]

    Pingback por Programando melhor: Aula 4 - Ordenação « Blog de Helton Duarte | Março 11, 2009

  8. [...] os problemas “The Trip”, em Exercícios 1 (Parte I) e “Jolly Jumpers”, na Aula 2, pois foram resolvidos por mim no site do UVa Online Judge [...]

    Pingback por Programando melhor: Revisão « Blog de Helton Duarte | Março 27, 2009

  9. Olá pessoal,

    Para quem está com dificuldades no primeiro problema da lista, aí vão as dicas:

    * Crie um vetor para armazenar os números e outros para contabilizar as diferenças;
    * Zere o vetor de diferenças e coloque uma variável indicando que a sequência é Jolly;
    * Faça um loop pelo vetor de números da seguinte maneira:

    /* Vê as diferenças */
    for (i = 2; i <= n; i++)
    {
    k = numeros[i] – numeros[i-1];
    if (k = n))
    {
    jolly = 0;
    break;
    }
    else
    {
    dif[k]++;
    }
    }

    Pronto! Se a variável “jolly” for 1, a sequência é Jolly Jumper, se não, então não é, oras! =D

    OBS: Para quem não entendeu o “if” do loop é o seguinte: se a diferença (representada pela variável “k”) for 0 ou >= n, então foge do que o problema propôs (todos os valores entre 1 e n). Se a posição dif[k] já for 1, então repetiu essa diferença, deixando também de ser Jolly Jumper.

    Boa sorte a todos!

    Comentário por Helton de Melo Duarte | Março 27, 2009

  10. OBS: No código acima ficaram faltando duas coisas
    => o teste se “k” é menor que zero, para trocar o seu sinal, já que o problema pede a DIFERENÇA ABSOLUTA;
    => dentro do if, não compara se é igual a “n”, as comparações são: se dif[k] == 1 OU se k == 0 OU se k >= n.

    Obrigado.

    Comentário por Helton de Melo Duarte | Março 27, 2009


Deixe um comentário