Divagações...

quinta-feira, 25 de fevereiro de 2010

Filosofia da programação

Programar é a arte de encontrar soluções, crias novas ideias, implementar maneiras mais eficazes de resolver problemas computáveis. Tudo isso instiga o programador a dar o melhor de si, a transcender suas habilidades, para, finalmente, sentir o prazer do 'insight' que sua mente proporciona ao encontrar o que aguçava sua engenhosidade: o desafio.
O desenvolvimento traz consigo o prazer de gerar uma nova solução, sempre tendo em mente a ideia de que fomos capazes de escrever os codigos e ver os resultados sendo executados pela maquina de acordo com o prentendiamos. Após percorrido o caminho árduo de desenvolver o código para satisfazer os requisitos do problema, o sentimento de realização traz a recompensa ao programador, trabalho cumprido, admiração e respeito por tê-lo feito. É da natureza humana se sentir apreciado e contribuir com trabalhos que possa trazer recompensas para as pessoas que nos cerca quanto para nós mesmos. Esse sentimento permeia o programador quando da finalização de um projeto, bom, ao menos no meu caso.

quarta-feira, 24 de fevereiro de 2010

Estruturas de dados - conceitos

Para a estruturação de dados de forma sistematica e organizada existem varias estruturas de dados, cada qual com uma finalidade especifica. Alem das estruturas basicas, como os vetores, matrizes e structs ( registros ), é possivel combiná-las, tal como um vetor de registros por exemplo, para formar uma estrutura de dados mais complexa. A maneira de organizar os dados de um programa pode ser modelado em termos dessas estruturas fornecidas pela linguagem.

Na natureza selvagem

Virtudes, principios, valores, ideias, são todos

Algoritmo - Recursividade

A recursividade permite modelar algoritmos de modo a alcançar a solução através da definição do problema em termos de si mesmo. Em outras palavras, podemos construir um algoritmo, tendo em vista que sua resolução é composta de chamadas a suas instruções até que uma condição de parada seja atendida; de natureza recursiva, a fim de facilitar a confecção do mesmo, pois se torna fácil pensar na solução do problema dessa maneira. A idéia chave por trás dos algoritmos recursivos, consiste em dividir o problema em partes menores até que uma de suas partes seja resolvida diretamente, sem uma chamada ao próprio código, sendo esta ultima execução direta denominada condição de parada.

Algoritmo - Top Down

Com os posts anteriores é possível escrever algoritmos para uma ampla gama de problemas. No entando, as vezes, nos sentimos desnorteados quanto ao rumo que se deve tomar quando do desenvolvimento de um algoritmo para resolver um dado problema. Neste post vou abordar uma técnica que utilizo quando escrevo meus algoritmos.

Esta técnica é denominada top-down, que consiste em um paradigma de atacar o problema de forma gradual. Após o entendimento completo do problema, basta dividi-lo em partes menores para que os detalhes sejam tratados individualmente e a solução como um todo seja alcançada com a união das resoluções de todas as partes. Escrever algoritmos usando top-down facilita a maneira de encarar os problemas, pois dividir um problema inicialmente complexo em partes de solução trivial, propicia 'insights' mentais que nos revelam o caminho que o algoritmo deve seguir.

Algoritmo - Registros

No post anterior abordei a implementação de vetores e matrizes, estruturas de dados básicas que fornecem meios de agrupar dados de um mesmo tipo. Neste post será tratado a implementação de uma estrutura mais sofisticada que permite reunir dados sob um mesmo nome; denominadas estruturas (em C) ou registros em linguagem algoritmica.

Os registros são agrupamentos de dados, possivelmente heterogéneos (real, inteiro, lógico, carácter, literal), que visam oferecer meios mais simples de manipular informações relacionados que o projetista do algoritmo quer manter unidas. Por exemplo, pense em um algoritmo que implemente operações sobre numero de empregados, valor do salário, departamento dos projetos, lucros obtidos de uma empresa. A manipulação de tais dados se torna trivial com a utilização dos registros, pois por meio de um rotulo (identificador do conjunto de dados) é possível acessar os dados-membros do conjunto.

Algoritmo - Vetores e matrizes

Para facilitar a manipulação de muitos dados ao mesmo tempo uma estrutura de dados homogênea é disponibilizada. Para tais implementações usa-se vetores e matrizes.
Vetores são posições contíguas de memória onde o armazenamento é realizado de modo sequencial. Já as matrizes são coleções de dados que podem conter mais de uma dimensão, matrizes planas, que são representadas por linhas e colunas (as mesmas usadas em matemática) e matrizes de duas ou mais dimensões. Tente usar seu poder de abstração para visualizar uma matriz e enxergá-la como um cruzamento de linhas e colunas, onde cada célula representa uma porção de memoria para armazenar um dado elemento.
Todos os tipos de dados apresentados nos posts anteriores são suportados por vetores e matrizes, os quais podem ser de inteiros, reais ou caracteres (chamados usualmente de strings).

Para ilustrar melhor como funcionam tais estruturas segue abaixo suas construções:

declare soma[10]: inteiro;
declare media[100] : real;
declare nomes[20][100] : caracter;

Representação do vetor soma[10]:
Esta é a maneira como o computador armazena vetores na memória RAM. As posições representas de E1 até E10 são os elementos propriamente ditos e sua referência é feita por meio dos indices, os quais são numerados de 1 a 10 trazendo a tona o elemento em sua localização.

Em pormenores, a memória principal do computador implementa o vetor como uma sequência de células que são referenciadas pelo seu endereço. O endereço de uma célula é o modo como o computador sabe a localização de um elemento em um vetor ou matriz. Para acessarmos um determinado elemento usamos índices, que varrem as posições do primeiro elemento até o último.

Os tipos dos vetores soma[10] e media[100] definidos acima indicam quais as operações são permitidas serem efetuadas com os valores e a faixa de precisão que o tipo admite. Já na declaração nomes[20][100] podemos guardar 20 nomes de tamanho 100, isto é, representa uma matriz de 20 linhas, as quais possuem 100 colunas; podendo ser armazenado em cada linha um nome de no máximo 100 caracteres.

Para a escrita e saída dos dados e manipulação dos mesmos, as seguintes operações
são necessárias:

Leitura/Escrita de vetores:

para i=1 ate 10 passo 1 faça
leia soma[i]; //lê o valor e guarda o elemento na posição i
escreva "Valor contido em: ", soma[i];
fim-para

Leitura/Escrita de matrizes:

para i=1 ate 20 passo 1 faça
para j=1 ate 100 passo 1 faça
leia nomes[i][j];
fim-para
fim-para

Para a inserção de dados em uma matriz foi preciso dois índices, pois é necessário controlar suas linhas e colunas. A referencia as linhas é efetuada por meio do índice i, já as colunas é por intermédio do índice j.

Qualquer duvida sobre como implementar ou operar sobre as estruturas homegeneas de dados deixe seu comentário e quando possível responderei.

Algoritmo - Estrutura de repetição

Estruturas de repetição são criadas para que diversas instruções sejam executadas um derteminado número de vezes. Elas servem para implementar ações de modo a automatizar os comandos até que uma condição seja satisfeita. Há duas maneiras de construirmos nossas estruturas de repetição: sabendo a condição de parada previamente ou quando desconhecemos seus limites. Exemplificarei abaixo:

estrutura de repetição controlada por contador:
para i=1 ate f passo 1 faça
instrução 1;
instrução 2;
instrução n;
fim-para

Algoritmo - Estrutura condicional

Veremos neste post como implementar controle de fluxo nos algoritmos. Controle de fluxo significa controlar quais blocos de comandos serão executados em função de uma comparação realizada nas instruções se e senao.

Os comandos se e senao são assim definidos:
se ( condicao )
instrução 1;
instrução 2;
instrução n;
senao
instruções 1 ... n;
instruções em caso de a condição acima resultar em valor lógico falso.

Algoritmo - Entrada/Saida de dados

No post anterior escrevi a definição de algoritmos. Neste tópico vamos aprender como modelar
nossos próprios algoritmos por meio de uma linguagem conhecida como portugol.
Primeiramente é necessário definir quais os objetivos do nosso algoritmo, ou seja, a função
que ele vai desempenhar de acordo com as necessidades do usuário. Após realizada a análise do problema basta traduzí-lo em comandos para execução sequencial. Para tanto é necessário representar os dados (entradas fornecidas pelo usuário) através de variáveis (segmentos de memorias com endereço referenciável) para que as informações sejam manipuladas pelo algoritmo e forneça a saída desejada pelo utilizador.

Algoritmos - Definição

Todo bom profissional da area de TI modela seus programas através de algoritmos, os quais especificam de maneira clara e objetiva quais os passos que o programa deve tomar no decorrer de sua execução.
Uma das possiveis definições de algoritmo seria a que segue: um conjunto de instruções/comandos que visam obter a solução de um problema por meio de sua execução sequencial ate que as saidas (resultados) corretas do algoritmo seja atingido. Em outras palavras, comandos que manipulam dados, os processa por intermedio de operações logicas e/ou aritmeticas e gera um resultado com sentindo agregado aos própositos do usuario.
Para a confecção de um algoritmo é necessario uma notação, que inclui comandos de entrada e saida de dados, declarações de variaveis, definições de constantes, estruturas de controle de fluxo e estruturas de repetição.
Nos próximos topicos abordarei cada um desses itens explicando como escrever seus proprios algoritmos em uma linguagem portugol (pseudo-codigo escrito em portugues).