Projeto de Algoritmos

"Let us change our traditional attitude to the construction of programs.
Instead of imagining that our main task is to instruct a computer what to do,
let us imagine that our main task is
to explain to human beings what we want a computer to do.
"
— Donald E. Knuth, Literate Programming

"First, beautiful software ought to be visually beautiful —
the written code I mean — and almost a pleasure to read.
"
— Don Sherwood Olson, escritor e ex engenheiro de software

"Any fool can write code that a computer can understand.
Good programmers write code that humans can understand.
"
— Martin Fowler, Refactoring: Improving the Design of Existing Code

Leiaute

Programas precisam ser entendidos não só por computadores, mas também (e principalmente) por seres humanos.  Nos exemplos abaixo, não tente entender o que o programa faz; preocupe-se apenas com o leiaute (= layout), ou seja, com a disposição do programa na folha de papel e na tela do monitor.  Observe, em especial,

A propósito, veja o verbete Programming Style na Wikipedia.

É fácil habituar-se a produzir um bom leiaute.  Com um pouco de prática, os dedos do programador, dançando sobre o teclado, passarão a fazer a coisa certa de maneira autônoma, deixando a mente do programador livre para cuidar de assuntos mais importantes.

Um bom leiaute

Eis uma amostra do melhor leiaute que conheço. Ele está de acordo (ou quase) com o leiaute sugerido por Making The Best Use of C no GNU Coding Standards.  (Veja também Elements of Programming Style, de Kernighan e Plauger, McGraw-Hill, 1978, 2a. edição.)

int func( int n, int v[])
{
   int i, j;
   i = 0;
   while (i < n) {
      if (v[i] != 0)
         i = i + 1;
      else {
         for (j = i + 1; j < n; ++j)  
            v[j-1] = v[j];
         n = n - 1;
      }
   }
   return n;
}

Veja como é fácil conferir o casamento de "{" com "}". Note como esse leiaute facilita as alterações do programa (remoção de linhas, inserção de novas linhas) em um editor de textos.

Tenha compaixão pelos seus leitores e não use fonte de espaçamento variável para escrever programas.  Veja como o resultado é inadequado:

int func( int n, int v[])
{
   int i, j;
   i = 0;
   while (i < n) {
     if (v[i] != 0) i = i + 1;
     else {
       for (j = i + 1; j < n; ++j)
         v[j-1] = v[j];
       n = n - 1;
     }
   }
   return n;
}

Um leiaute compacto

O leiaute abaixo ocupa menos espaço que o anterior. Ele é bom para escrever programas com lápis-e-papel (mas não tão bom para fazer alterações com o auxílio de um editor de textos). Indentação correta é essencial nesse leiaute.

int func( int n, int v[]) {
   int i, j;
   i = 0;
   while (i < n) {
      if (v[i] != 0)  i = i + 1;
      else {
         for (j = i + 1; j < n; ++j)  v[j-1] = v[j];
         n = n - 1; }}
   return n; }

Mau exemplo

O que você acha do leiaute no exemplo abaixo?

int func(  int n,int v[] ){
   int i,j;
   i=0;
   while(i<n){
      if(v[i] !=0) i=i +1;
      else
      {
         for(j=i+1;j<n;++j )  
            v[j-1]=v[j];
         n =n- 1;
      }
   }
   return n;
}

Este leiaute é péssimo.  Principalmente porque deixa espaços onde não deve e engole os espaços onde eles são necessários.  Os espaços no código são tão importantes quanto as pausas na música!

Infelizmente, alguns bons programadores e autores cometem esse tipo de atrocidade gratuita.  Espero que você não queira imitar esses maus exemplos.

Sugestões

Quer uma sugestão?  Use as mesmas regras tipográficas que todos os bons livros, revistas e jornais seguem:

A expressão  "while(j < n)"  tem o mesmo sabor que  "enquantoj for menor que n".  Portanto,

Há três exceções notórias a essas regras:  escreva  

Além disso, é usual não deixar espaços antes e depois dos operadores de multiplicação e divisão.  Assim, é aceitável escrever  x*y  em lugar de x * y  e  x/y  em vez de x / y.   Há mais uma exceção, ousada e controversa:  na definição e na invocação de uma função, podemos suprimir o espaço antes e inserir um espaço depois do abre-parêntese que introduz a lista de parâmetros ou argumentos.  Por exemplo:  func( 9, v) .   Mas isso não se aplica aos operadores while, for, if, return, sizeof etc., pois esses operadores não são funções.

Talvez você não goste dessas regras e queira adotar outras. De qualquer modo, seja consistente, isto é, faça as coisas sempre do mesmo jeito.

Exercícios

  1. Qual das duas linhas abaixo tem layout mais "civilizado"?
    para j variando de 1 até n de 1 em 1, faça
    paraj variando de1 até n de 1em1,faça
    
  2. Qual das duas linhas abaixo tem layout mais decente?
    for (j = 0; j < n; ++j) {
    for(j = 0; j < n; ++j) {
    
  3. Qual das duas linhas abaixo tem layout mais "civilizado"?
    for (j = 0;j < n; ++j){
    for (j = 0; j < n; ++j) {
    
  4. Qual das duas linhas abaixo tem layout mais decente?
    for(j=0;j<n;++j){
    for (j = 0; j < n; ++j) {
    
  5. Reescreva o trecho de programa abaixo com leiaute "civilizado".
    int func(int n,int v[]){int i,j;i=0;while(i<n){
    if(v[i]!=0) ++i;else{for(j=i+1;j<n;++j)
    v[j-1]=v[j];--n;}}return n;}
    
  6. Corrija os erros de leiaute no texto abaixo.
    A computação nãoé a ciência doscomputadores,da mesma
    formaque a astronomia nãoé aciência dostelescópios.
    
  7. Corrija os erros de leiaute no texto abaixo.
    Em 1959 e nas décadas seguintes   nenhum programador Cobol
    poderia imaginar que os programas de computador que estava
    criando ainda estariam em operação no fim do século.Poucos
    se lembram hoje que há menos de quinze anos os primeiros PCs
    possuíam apenas 64Kbytes de memória.Como o custo dos dispositivos
    de armazenamento era alto e a quantidade de memória disponível
    era pequena,usavam-se muitos truques para economizar esse recurso.
    Um deles foi o uso de dois dígitos   para representar o 
    ano:armazenava-se(por exemplo ) 85 em vez de 1985.com a 
    chegada do ano 2000,essa codificação"econômica"
    transformou-se em um erro em potencial .
    

    Solução:

    Em 1959 e nas décadas seguintes nenhum programador Cobol
    poderia imaginar que os programas de computador que estava
    criando ainda estariam em operação no fim do século. Poucos
    se lembram hoje que há menos de quinze anos os primeiros PCs
    possuíam apenas 64Kbytes de memória. Como o custo dos dispositivos
    de armazenamento era alto e a quantidade de memória disponível
    era pequena, usavam-se muitos truques para economizar esse recurso.
    Um deles foi o uso de dois dígitos para representar o 
    ano: armazenava-se (por exemplo) 85 em vez de 1985. Com a 
    chegada do ano 2000, essa codificação "econômica"
    transformou-se em um erro em potencial.
    
  8. Reescreva o trecho de programa abaixo usando leiaute decente.
    Esq= 0; Dir=N-1;
    i=(Esq+Dir)/2;     /*indice do "meio"de R[]*/
    while(Esq <= Dir && R[i] != X){
       if(R[i]<X) Esq = i+1;
       else Dir = i-1;  /* novo indice do "meio"de R[] */
       i= (Esq + Dir)/2;
       }
    

    Solução:

    Esq = 0; Dir = N - 1;
    i = (Esq + Dir)/2;   /* índice do "meio" de R[] */
    while (Esq <= Dir && R[i] != X) {
       if (R[i] < X) Esq = i + 1;
       else Dir = i - 1;   /* novo índice do "meio" de R[] */
       i = (Esq + Dir)/2;
    }
    

    Teria ficado ainda melhor se os nomes das variáveis usassem apenas letras minúsculas (esq no lugar Esqdir no lugar de Dir  etc.).

Dicas

 

 


URL of this site: www.ime.usp.br/~pf/algoritmos/
Last modified: Thu Jan 17 06:59:00 BRST 2013
Paulo Feofiloff
IME-USP

Valid HTML 4.01 Transitional    Valid CSS!