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 explaing to human beings what we want a computer to do."
— Donald E. Knuth, Literate Programming

"Programs must be written for people to read, and incidentally for machines to execute."
— H. Abelson, G. Sussman, The Structure and Interpretation of Computer Programs

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

Leiaute (= layout)

Programas devem 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.

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 com espaçamento variável para escrever programas.  Veja como o resultado é ruim:

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). Recuos corretos são essenciais 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; um verdadeiro "programa de índio". Principalmente porque deixa espaços em branco onde não deve e engole os espaços onde eles são importantes.

Infelizmente, alguns bons programadores e autores cometem esse tipo de atrocidade gratuita.  Espero que você não queira usar esses maus exemplos como licença para escrever mal.

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 de  "enquantoj for menor que n".  Portanto,

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

Além disso, é usual suprimir o espaço entre o nome de uma função e o abre-parêntese seguinte. Assim é usual escrever  func(9, v),  por exemplo.   Mas isso não se aplica aos operadores while, for, if, return, 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 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 duas linhas abaixo tem layout mais decente?
    for (j = 0; j < n; j++) {
    for(j = 0; j < n; j++) {
    
  3. Qual duas linhas abaixo tem layout mais "civilizado"?
    for (j = 0;j < n; j++){
    for (j = 0; j < n; j++) {
    
  4. Qual 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.
    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 ao invés 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 ao invés de 1985. Com a 
    chegada do ano 2000, essa codificação "econômica"
    transformou-se em um erro em potencial.
    

  7. 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/
1998 | Last modified: Mon Feb 5 06:36:57 BRST 2007
Paulo Feofiloff
IME-USP

Valid HTML 4.0 Transitional    Valid CSS!